diff --git a/ElvUI/Bindings.xml b/ElvUI/Bindings.xml
new file mode 100644
index 0000000..7c22127
--- /dev/null
+++ b/ElvUI/Bindings.xml
@@ -0,0 +1,17 @@
+
+
+ RaidMark_HotkeyPressed(keystate)
+
+
+ FarmMode()
+
+
+ HideLeftChat()
+
+
+ HideRightChat()
+
+
+ HideBothChat()
+
+
\ No newline at end of file
diff --git a/ElvUI/Core/API.lua b/ElvUI/Core/API.lua
new file mode 100644
index 0000000..df1756c
--- /dev/null
+++ b/ElvUI/Core/API.lua
@@ -0,0 +1,260 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+--Lua functions
+local _G = _G
+local wipe, date = wipe, date
+local format, select, type, ipairs, pairs = format, select, type, ipairs, pairs
+local strmatch, strfind, tonumber, tostring = strmatch, strfind, tonumber, tostring
+--WoW API / Variables
+local GetCVarBool = GetCVarBool
+local GetFunctionCPUUsage = GetFunctionCPUUsage
+local RequestBattlefieldScoreData = RequestBattlefieldScoreData
+local UnitGroupRolesAssigned = UnitGroupRolesAssigned
+local UnitHasVehicleUI = UnitHasVehicleUI
+local IsInInstance = IsInInstance
+
+E.Role = "Melee" -- TODO: Load locally, or save per specialization.
+
+do -- other non-english locales require this
+ E.UnlocalizedClasses = {}
+ for k, v in pairs(_G.LOCALIZED_CLASS_NAMES_MALE) do E.UnlocalizedClasses[v] = k end
+ for k, v in pairs(_G.LOCALIZED_CLASS_NAMES_FEMALE) do E.UnlocalizedClasses[v] = k end
+
+ function E:UnlocalizedClassName(className)
+ return (className and className ~= "") and E.UnlocalizedClasses[className]
+ end
+end
+
+function E:ScanTooltipTextures(clean, grabTextures)
+ local textures
+ for i = 1, 10 do
+ local tex = _G["ElvUI_ScanTooltipTexture"..i]
+ local texture = tex and tex:GetTexture()
+ if texture then
+ if grabTextures then
+ if not textures then textures = {} end
+ textures[i] = texture
+ end
+ if clean then
+ tex:SetTexture()
+ end
+ end
+ end
+
+ return textures
+end
+
+function E:GetPlayerRole()
+ local isTank, isHealer, isDamage = UnitGroupRolesAssigned("player")
+
+ if isTank or isHealer or isDamage then
+ return isTank and "TANK" or isHealer and "HEALER" or isDamage and "DAMAGER"
+ else
+ return "DAMAGER" -- Assume dps role; Nothing better for ascension.
+ end
+end
+
+do
+ --local Masque = E.Libs.Masque
+ local LBFGroupToTableElement = {
+ ["ActionBars"] = "actionbar",
+ ["Auras"] = "auras"
+ }
+
+ function E:LBFCallback(SkinID, _, _, Group)
+ if not E.private then return end
+
+ local element = LBFGroupToTableElement[Group]
+ if element then
+ if E.private[element].lbf.enable then
+ E.private[element].lbf.skin = SkinID
+ end
+ end
+ end
+
+ if LBF then
+ LBF:RegisterSkinCallback("ElvUI", E.LBFCallback, E)
+ end
+end
+
+do
+ local CPU_USAGE = {}
+ local function CompareCPUDiff(showall, minCalls)
+ local greatestUsage, greatestCalls, greatestName, newName, newFunc
+ local greatestDiff, lastModule, mod, usage, calls, diff = 0
+
+ for name, oldUsage in pairs(CPU_USAGE) do
+ newName, newFunc = strmatch(name, "^([^:]+):(.+)$")
+ if not newFunc then
+ E:Print("CPU_USAGE:", name, newFunc)
+ else
+ if newName ~= lastModule then
+ mod = E:GetModule(newName, true) or E
+ lastModule = newName
+ end
+ usage, calls = GetFunctionCPUUsage(mod[newFunc], true)
+ diff = usage - oldUsage
+ if showall and (calls > minCalls) then
+ E:Print("Name("..name..") Calls("..calls..") Diff("..(diff > 0 and format("%.3f", diff) or 0)..")")
+ end
+ if (diff > greatestDiff) and calls > minCalls then
+ greatestName, greatestUsage, greatestCalls, greatestDiff = name, usage, calls, diff
+ end
+ end
+ end
+
+ if greatestName then
+ E:Print(greatestName.." had the CPU usage of: "..(greatestUsage > 0 and format("%.3f", greatestUsage) or 0).."ms. And has been called "..greatestCalls.." times.")
+ else
+ E:Print("CPU Usage: No CPU Usage differences found.")
+ end
+
+ wipe(CPU_USAGE)
+ end
+
+ function E:GetTopCPUFunc(msg)
+ if not GetCVarBool("scriptProfile") then
+ E:Print("For `/cpuusage` to work, you need to enable script profiling via: `/console scriptProfile 1` then reload. Disable after testing by setting it back to 0.")
+ return
+ end
+
+ local module, showall, delay, minCalls = strmatch(msg, "^(%S+)%s*(%S*)%s*(%S*)%s*(.*)$")
+ local checkCore, mod = (not module or module == "") and "E"
+
+ showall = (showall == "true" and true) or false
+ delay = (delay == "nil" and nil) or tonumber(delay) or 5
+ minCalls = (minCalls == "nil" and nil) or tonumber(minCalls) or 15
+
+ wipe(CPU_USAGE)
+ if module == "all" then
+ for moduName, modu in pairs(self.modules) do
+ for funcName, func in pairs(modu) do
+ if (funcName ~= "GetModule") and (type(func) == "function") then
+ CPU_USAGE[moduName..":"..funcName] = GetFunctionCPUUsage(func, true)
+ end
+ end
+ end
+ else
+ if not checkCore then
+ mod = self:GetModule(module, true)
+ if not mod then
+ self:Print(module.." not found, falling back to checking core.")
+ mod, checkCore = self, "E"
+ end
+ else
+ mod = self
+ end
+ for name, func in pairs(mod) do
+ if (name ~= "GetModule") and type(func) == "function" then
+ CPU_USAGE[(checkCore or module)..":"..name] = GetFunctionCPUUsage(func, true)
+ end
+ end
+ end
+
+ self:Delay(delay, CompareCPUDiff, showall, minCalls)
+ self:Print("Calculating CPU Usage differences (module: "..(checkCore or module)..", showall: "..tostring(showall)..", minCalls: "..tostring(minCalls)..", delay: "..tostring(delay)..")")
+ end
+end
+
+function E:RegisterObjectForVehicleLock(object, originalParent)
+ if not object or not originalParent then
+ E:Print("Error. Usage: RegisterObjectForVehicleLock(object, originalParent)")
+ return
+ end
+
+ object = _G[object] or object
+ --Entering/Exiting vehicles will often happen in combat.
+ --For this reason we cannot allow protected objects.
+ if object.IsProtected and object:IsProtected() then
+ E:Print("Error. Object is protected and cannot be changed in combat.")
+ return
+ end
+
+ --Check if we are already in a vehicles
+ if UnitHasVehicleUI("player") then
+ object:SetParent(E.HiddenFrame)
+ end
+
+ --Add object to table
+ E.VehicleLocks[object] = originalParent
+end
+
+function E:UnregisterObjectForVehicleLock(object)
+ if not object then
+ E:Print("Error. Usage: UnregisterObjectForVehicleLock(object)")
+ return
+ end
+
+ object = _G[object] or object
+ --Check if object was registered to begin with
+ if not E.VehicleLocks[object] then return end
+
+ --Change parent of object back to original parent
+ local originalParent = E.VehicleLocks[object]
+ if originalParent then
+ object:SetParent(originalParent)
+ end
+
+ --Remove object from table
+ E.VehicleLocks[object] = nil
+end
+
+function E:EnterVehicleHideFrames(_, unit)
+ if unit ~= "player" then return end
+
+ for object in pairs(E.VehicleLocks) do
+ object:SetParent(E.HiddenFrame)
+ end
+end
+
+function E:ExitVehicleShowFrames(_, unit)
+ if unit ~= "player" then return end
+
+ for object, originalParent in pairs(E.VehicleLocks) do
+ object:SetParent(originalParent)
+ end
+end
+
+function E:RequestBGInfo()
+ RequestBattlefieldScoreData()
+end
+
+function E:PLAYER_ENTERING_WORLD()
+ if not self.MediaUpdated then
+ self:UpdateMedia()
+ self.MediaUpdated = true
+ end
+
+ local _, instanceType = IsInInstance()
+ if instanceType == "pvp" then
+ self.BGTimer = self:ScheduleRepeatingTimer("RequestBGInfo", 5)
+ self:RequestBGInfo()
+ elseif self.BGTimer then
+ self:CancelTimer(self.BGTimer)
+ self.BGTimer = nil
+ end
+end
+
+function E:PLAYER_LEVEL_UP(_, level)
+ E.mylevel = level
+end
+
+function E:LoadAPI()
+ self:RegisterEvent("PLAYER_LEVEL_UP")
+ self:RegisterEvent("PLAYER_ENTERING_WORLD")
+ self:RegisterEvent("UNIT_ENTERED_VEHICLE", "EnterVehicleHideFrames")
+ self:RegisterEvent("UNIT_EXITED_VEHICLE", "ExitVehicleShowFrames")
+ self:RegisterEvent("UI_SCALE_CHANGED", "PixelScaleChanged")
+
+ do -- setup cropIcon texCoords
+ local opt = E.db.general.cropIcon
+ local modifier = 0.04 * opt
+ for i, v in ipairs(E.TexCoords) do
+ if i % 2 == 0 then
+ E.TexCoords[i] = v - modifier
+ else
+ E.TexCoords[i] = v + modifier
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Core/Animation.lua b/ElvUI/Core/Animation.lua
new file mode 100644
index 0000000..e92562c
--- /dev/null
+++ b/ElvUI/Core/Animation.lua
@@ -0,0 +1,294 @@
+------------------------------------------------------------------------
+-- Animation Functions
+------------------------------------------------------------------------
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+--Lua functions
+local random, next, unpack, strsub = random, next, unpack, strsub
+--WoW API / Variables
+
+E.AnimShake = {{-9,7,-7,12}, {-5,9,-9,5}, {-5,7,-7,5}, {-9,9,-9,9}, {-5,7,-7,5}, {-9,7,-9,5}}
+E.AnimShakeH = {-5,5,-2,5,-2,5}
+
+function E:FlashLoopFinished(requested)
+ if not requested then self:Play() end
+end
+
+function E:RandomAnimShake(index)
+ local s = E.AnimShake[index]
+ return random(s[1], s[2]), random(s[3], s[4])
+end
+
+function E:SetUpAnimGroup(obj, Type, ...)
+ if not Type then Type = "Flash" end
+
+ if strsub(Type, 1, 5) == "Flash" then
+ obj.anim = obj:CreateAnimationGroup("Flash")
+ obj.anim.fadein = obj.anim:CreateAnimation("ALPHA", "FadeIn")
+ obj.anim.fadein:SetChange(1)
+ obj.anim.fadein:SetOrder(2)
+
+ obj.anim.fadeout = obj.anim:CreateAnimation("ALPHA", "FadeOut")
+ obj.anim.fadeout:SetChange(-1)
+ obj.anim.fadeout:SetOrder(1)
+
+ if Type == "FlashLoop" then
+ obj.anim:SetScript("OnFinished", E.FlashLoopFinished)
+ end
+ elseif strsub(Type, 1, 5) == "Shake" then
+ local shake = obj:CreateAnimationGroup(Type)
+ shake:SetLooping("REPEAT")
+ shake.path = shake:CreateAnimation("Path")
+
+ if Type == "Shake" then
+ shake.path:SetDuration(0.7)
+ obj.shake = shake
+ elseif Type == "ShakeH" then
+ shake.path:SetDuration(2)
+ obj.shakeh = shake
+ end
+
+ for i = 1, 6 do
+ shake.path[i] = shake.path:CreateControlPoint()
+
+ if Type == "Shake" then
+ shake.path[i]:SetOffset(E:RandomAnimShake(i))
+ else
+ shake.path[i]:SetOffset(E.AnimShakeH[i], 0)
+ end
+ end
+ shake.path[1]:SetOrder(1)
+ shake.path[2]:SetOrder(2)
+ shake.path[3]:SetOrder(3)
+ shake.path[4]:SetOrder(4)
+ shake.path[5]:SetOrder(5)
+ shake.path[6]:SetOrder(6)
+ else
+ local x, y, duration, customName = ...
+ if not customName then customName = "anim" end
+
+ local anim = obj:CreateAnimationGroup("Move_In")
+ obj[customName] = anim
+
+ anim.in1 = anim:CreateAnimation("Translation")
+ anim.in1:SetDuration(0)
+ anim.in1:SetOrder(1)
+ anim.in1:SetOffset(E:Scale(x), E:Scale(y))
+
+ anim.in2 = anim:CreateAnimation("Translation")
+ anim.in2:SetDuration(duration)
+ anim.in2:SetOrder(2)
+ anim.in2:SetSmoothing("OUT")
+ anim.in2:SetOffset(E:Scale(-x), E:Scale(-y))
+
+ anim.out1 = obj:CreateAnimationGroup("Move_Out")
+ anim.out1:SetScript("OnFinished", function() obj:Hide() end)
+
+ anim.out2 = anim.out1:CreateAnimation("Translation")
+ anim.out2:SetDuration(duration)
+ anim.out2:SetOrder(1)
+ anim.out2:SetSmoothing("IN")
+ anim.out2:SetOffset(E:Scale(x), E:Scale(y))
+ end
+end
+
+function E:Shake(obj)
+ if not obj.shake then
+ E:SetUpAnimGroup(obj, "Shake")
+ end
+
+ obj.shake:Play()
+end
+
+function E:StopShake(obj)
+ if obj.shake then
+ obj.shake:Finish()
+ end
+end
+
+function E:ShakeHorizontal(obj)
+ if not obj.shakeh then
+ E:SetUpAnimGroup(obj, "ShakeH")
+ end
+
+ obj.shakeh:Play()
+end
+
+function E:StopShakeHorizontal(obj)
+ if obj.shakeh then
+ obj.shakeh:Finish()
+ end
+end
+
+function E:Flash(obj, duration, loop)
+ if not obj.anim then
+ E:SetUpAnimGroup(obj, loop and "FlashLoop" or "Flash")
+ end
+
+ if not obj.anim:IsPlaying() then
+ obj.anim.fadein:SetDuration(duration)
+ obj.anim.fadeout:SetDuration(duration)
+ obj.anim:Play()
+ end
+end
+
+function E:StopFlash(obj)
+ if obj.anim and obj.anim:IsPlaying() then
+ obj.anim:Stop()
+ end
+end
+
+function E:SlideIn(obj, customName)
+ if not customName then customName = "anim" end
+ if not obj[customName] then return end
+
+ obj[customName].out1:Stop()
+ obj[customName]:Play()
+ obj:Show()
+end
+
+function E:SlideOut(obj, customName)
+ if not customName then customName = "anim" end
+ if not obj[customName] then return end
+
+ obj[customName]:Finish()
+ obj[customName]:Stop()
+ obj[customName].out1:Play()
+end
+
+local FADEFRAMES, FADEMANAGER = {}, CreateFrame("FRAME")
+FADEMANAGER.delay = 0.05
+
+function E:UIFrameFade_OnUpdate(elapsed)
+ FADEMANAGER.timer = (FADEMANAGER.timer or 0) + elapsed
+
+ if FADEMANAGER.timer > FADEMANAGER.delay then
+ FADEMANAGER.timer = 0
+
+ for frame, info in next, FADEFRAMES do
+ -- Reset the timer if there isn't one, this is just an internal counter
+ if frame:IsVisible() then
+ info.fadeTimer = (info.fadeTimer or 0) + (elapsed + FADEMANAGER.delay)
+ else
+ info.fadeTimer = info.timeToFade + 1
+ end
+
+ -- If the fadeTimer is less then the desired fade time then set the alpha otherwise hold the fade state, call the finished function, or just finish the fade
+ if info.fadeTimer < info.timeToFade then
+ if info.mode == "IN" then
+ frame:SetAlpha((info.fadeTimer / info.timeToFade) * info.diffAlpha + info.startAlpha)
+ else
+ frame:SetAlpha(((info.timeToFade - info.fadeTimer) / info.timeToFade) * info.diffAlpha + info.endAlpha)
+ end
+ else
+ frame:SetAlpha(info.endAlpha)
+
+ -- If there is a fadeHoldTime then wait until its passed to continue on
+ if info.fadeHoldTime and info.fadeHoldTime > 0 then
+ info.fadeHoldTime = info.fadeHoldTime - elapsed
+ else
+ -- Complete the fade and call the finished function if there is one
+ E:UIFrameFadeRemoveFrame(frame)
+
+ if info.finishedFunc then
+ if info.finishedArgs then
+ info.finishedFunc(unpack(info.finishedArgs))
+ else -- optional method
+ info.finishedFunc(info.finishedArg1, info.finishedArg2, info.finishedArg3, info.finishedArg4, info.finishedArg5)
+ end
+
+ if not info.finishedFuncKeep then
+ info.finishedFunc = nil
+ end
+ end
+ end
+ end
+ end
+
+ if not next(FADEFRAMES) then
+ FADEMANAGER:SetScript("OnUpdate", nil)
+ end
+ end
+end
+
+-- Generic fade function
+function E:UIFrameFade(frame, info)
+ if not frame then return end
+
+ frame.fadeInfo = info
+
+ if not info.mode then
+ info.mode = "IN"
+ end
+
+ if info.mode == "IN" then
+ if not info.startAlpha then info.startAlpha = 0 end
+ if not info.endAlpha then info.endAlpha = 1 end
+ if not info.diffAlpha then info.diffAlpha = info.endAlpha - info.startAlpha end
+ else
+ if not info.startAlpha then info.startAlpha = 1 end
+ if not info.endAlpha then info.endAlpha = 0 end
+ if not info.diffAlpha then info.diffAlpha = info.startAlpha - info.endAlpha end
+ end
+
+ frame:SetAlpha(info.startAlpha)
+
+ if not frame:IsProtected() then
+ frame:Show()
+ end
+
+ if not FADEFRAMES[frame] then
+ FADEFRAMES[frame] = info -- read below comment
+ FADEMANAGER:SetScript("OnUpdate", E.UIFrameFade_OnUpdate)
+ else
+ FADEFRAMES[frame] = info -- keep these both, we need this updated in the event its changed to another ref from a plugin or sth, don't move it up!
+ end
+end
+
+-- Convenience function to do a simple fade in
+function E:UIFrameFadeIn(frame, timeToFade, startAlpha, endAlpha)
+ if not frame then return end
+
+ if frame.FadeObject then
+ frame.FadeObject.fadeTimer = nil
+ else
+ frame.FadeObject = {}
+ end
+
+ frame.FadeObject.mode = "IN"
+ frame.FadeObject.timeToFade = timeToFade
+ frame.FadeObject.startAlpha = startAlpha
+ frame.FadeObject.endAlpha = endAlpha
+ frame.FadeObject.diffAlpha = endAlpha - startAlpha
+
+ E:UIFrameFade(frame, frame.FadeObject)
+end
+
+-- Convenience function to do a simple fade out
+function E:UIFrameFadeOut(frame, timeToFade, startAlpha, endAlpha)
+ if not frame then return end
+
+ if frame.FadeObject then
+ frame.FadeObject.fadeTimer = nil
+ else
+ frame.FadeObject = {}
+ end
+
+ frame.FadeObject.mode = "OUT"
+ frame.FadeObject.timeToFade = timeToFade
+ frame.FadeObject.startAlpha = startAlpha
+ frame.FadeObject.endAlpha = endAlpha
+ frame.FadeObject.diffAlpha = startAlpha - endAlpha
+
+ E:UIFrameFade(frame, frame.FadeObject)
+end
+
+function E:UIFrameFadeRemoveFrame(frame)
+ if frame and FADEFRAMES[frame] then
+ if frame.FadeObject then
+ frame.FadeObject.fadeTimer = nil
+ end
+
+ FADEFRAMES[frame] = nil
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Core/AprilFools.lua b/ElvUI/Core/AprilFools.lua
new file mode 100644
index 0000000..c3e5d9d
--- /dev/null
+++ b/ElvUI/Core/AprilFools.lua
@@ -0,0 +1,369 @@
+--[[
+ Collection of previous april fools pranks
+
+ Harlem Shake: Try it out with the command /harlemshake
+ Hello Kitty: Try it out with the command /hellokitty (pay attention to the popups, read what it says)
+]]
+
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local AB = E:GetModule("ActionBars")
+
+--Lua functions
+local _G = _G
+local pairs = pairs
+local twipe, tinsert = wipe, tinsert
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local DoEmote = DoEmote
+local GetCVar, SetCVar = GetCVar, SetCVar
+local PlayMusic, StopMusic = PlayMusic, StopMusic
+local SendChatMessage = SendChatMessage
+local NUM_PET_ACTION_SLOTS = NUM_PET_ACTION_SLOTS
+
+--Harlem Shake (Activate with command: /harlemshake)
+--People really seemed to like this one. We got a lot of positive responses.
+do
+ function E:StopHarlemShake()
+ E.isMassiveShaking = nil
+ StopMusic()
+ SetCVar("Sound_EnableAllSound", self.oldEnableAllSound)
+ SetCVar("Sound_EnableMusic", self.oldEnableMusic)
+
+ self:StopShakeHorizontal(ElvUI_StaticPopup1)
+ for _, object in pairs(self.massiveShakeObjects) do
+ if object then
+ self:StopShake(object)
+ end
+ end
+
+ if E.massiveShakeTimer then
+ E:CancelTimer(E.massiveShakeTimer)
+ end
+
+ E.global.aprilFools = true
+ E:StaticPopup_Hide("HARLEM_SHAKE")
+ twipe(self.massiveShakeObjects)
+ DoEmote("Dance")
+ end
+
+ function E:DoTheHarlemShake()
+ E.isMassiveShaking = true
+ ElvUI_StaticPopup1Button1:Enable()
+
+ for _, object in pairs(self.massiveShakeObjects) do
+ if object and object:IsShown() then
+ self:Shake(object)
+ end
+ end
+
+ E.massiveShakeTimer = E:ScheduleTimer("StopHarlemShake", 42.5)
+ SendChatMessage("DO THE HARLEM SHAKE!", "YELL")
+ end
+
+ function E:BeginHarlemShake()
+ DoEmote("Dance")
+ ElvUI_StaticPopup1Button1:Disable()
+ self:ShakeHorizontal(ElvUI_StaticPopup1)
+ self.oldEnableAllSound = GetCVar("Sound_EnableAllSound")
+ self.oldEnableMusic = GetCVar("Sound_EnableMusic")
+
+ SetCVar("Sound_EnableAllSound", 1)
+ SetCVar("Sound_EnableMusic", 1)
+ PlayMusic(E.Media.Sounds.HarlemShake)
+ E:ScheduleTimer("DoTheHarlemShake", 15.5)
+
+ self.massiveShakeObjects = {}
+ tinsert(self.massiveShakeObjects, GameTooltip)
+ tinsert(self.massiveShakeObjects, Minimap)
+ tinsert(self.massiveShakeObjects, WatchFrame)
+ tinsert(self.massiveShakeObjects, LeftChatPanel)
+ tinsert(self.massiveShakeObjects, RightChatPanel)
+ tinsert(self.massiveShakeObjects, LeftChatToggleButton)
+ tinsert(self.massiveShakeObjects, RightChatToggleButton)
+
+ if ElvUI_ReputationBar then
+ tinsert(self.massiveShakeObjects, ElvUI_ReputationBar)
+ end
+ if ElvUI_ExperienceBar then
+ tinsert(self.massiveShakeObjects, ElvUI_ExperienceBar)
+ end
+
+ for unit in pairs(UF.units) do
+ tinsert(self.massiveShakeObjects, UF[unit])
+ end
+
+ for _, header in pairs(UF.headers) do
+ tinsert(self.massiveShakeObjects, header)
+ end
+
+ for _, bar in pairs(AB.handledBars) do
+ for i = 1, #bar.buttons do
+ tinsert(self.massiveShakeObjects, bar.buttons[i])
+ end
+ end
+
+ if ElvUI_StanceBar then
+ for i = 1, #ElvUI_StanceBar.buttons do
+ tinsert(self.massiveShakeObjects, ElvUI_StanceBar.buttons[i])
+ end
+ end
+
+ for i = 1, NUM_PET_ACTION_SLOTS do
+ local button = _G["PetActionButton"..i]
+ if button then
+ tinsert(self.massiveShakeObjects, button)
+ end
+ end
+ end
+
+ function E:HarlemShakeToggle()
+ self:StaticPopup_Show("HARLEM_SHAKE")
+ end
+end
+
+--Hello Kitty (Activate with command: /hellokitty)
+--This is one of those pranks where you either love it or hate it I think
+--Unfortunately there was a bug which caused some of the hello kitty changes to stick,
+-- when they should have reverted to the original settings. This bug was fixed later on.
+do
+ local function OnDragStart(self)
+ self:StartMoving()
+ end
+
+ local function OnDragStop(self)
+ self:StopMovingOrSizing()
+ end
+
+ local function OnUpdate(self, elapsed)
+ if self.elapsed and self.elapsed > 0.1 then
+ self.tex:SetTexCoord((self.curFrame - 1) * 0.1, 0, (self.curFrame - 1) * 0.1, 1, self.curFrame * 0.1, 0, self.curFrame * 0.1, 1)
+
+ if self.countUp then
+ self.curFrame = self.curFrame + 1
+ else
+ self.curFrame = self.curFrame - 1
+ end
+
+ if self.curFrame > 10 then
+ self.countUp = false
+ self.curFrame = 9
+ elseif self.curFrame < 1 then
+ self.countUp = true
+ self.curFrame = 2
+ end
+ self.elapsed = 0
+ else
+ self.elapsed = (self.elapsed or 0) + elapsed
+ end
+ end
+
+ function E:SetupHelloKitty()
+ if not self.db.tempSettings then
+ self.db.tempSettings = {}
+ end
+
+ --Store old settings
+ local t = self.db.tempSettings
+ local c = self.db.general.backdropcolor
+ if self:HelloKittyFixCheck() then
+ E:HelloKittyFix()
+ else
+ self.oldEnableAllSound = GetCVar("Sound_EnableAllSound")
+ self.oldEnableMusic = GetCVar("Sound_EnableMusic")
+
+ t.backdropcolor = {r = c.r, g = c.g, b = c.b}
+ c = self.db.general.backdropfadecolor
+ t.backdropfadecolor = {r = c.r, g = c.g, b = c.b, a = c.a}
+ c = self.db.general.bordercolor
+ t.bordercolor = {r = c.r, g = c.g, b = c.b}
+ c = self.db.general.valuecolor
+ t.valuecolor = {r = c.r, g = c.g, b = c.b}
+
+ t.panelBackdropNameLeft = self.db.chat.panelBackdropNameLeft
+ t.panelBackdropNameRight = self.db.chat.panelBackdropNameRight
+
+ c = self.db.unitframe.colors.health
+ t.health = {r = c.r, g = c.g, b = c.b}
+ t.healthclass = self.db.unitframe.colors.healthclass
+
+ c = self.db.unitframe.colors.castColor
+ t.castColor = {r = c.r, g = c.g, b = c.b}
+ t.transparentCastbar = self.db.unitframe.colors.transparentCastbar
+
+ c = self.db.unitframe.colors.auraBarBuff
+ t.auraBarBuff = {r = c.r, g = c.g, b = c.b}
+ t.transparentAurabars = self.db.unitframe.colors.transparentAurabars
+
+ --Apply new settings
+ self.db.general.backdropfadecolor = {r = 131/255, g = 36/255, b = 130/255, a = 0.36}
+ self.db.general.backdropcolor = {r = 223/255, g = 76/255, b = 188/255}
+ self.db.general.bordercolor = {r = 223/255, g = 217/255, b = 47/255}
+ self.db.general.valuecolor = {r = 223/255, g = 217/255, b = 47/255}
+
+ self.db.chat.panelBackdropNameLeft = E.Media.Textures.HelloKittyChat
+ self.db.chat.panelBackdropNameRight = E.Media.Textures.HelloKittyChat
+
+ self.db.unitframe.colors.castColor = {r = 223/255, g = 76/255, b = 188/255}
+ self.db.unitframe.colors.transparentCastbar = true
+
+ self.db.unitframe.colors.auraBarBuff = {r = 223/255, g = 76/255, b = 188/255}
+ self.db.unitframe.colors.transparentAurabars = true
+
+ self.db.unitframe.colors.health = {r = 223/255, g = 76/255, b = 188/255}
+ self.db.unitframe.colors.healthclass = false
+
+ SetCVar("Sound_EnableAllSound", 1)
+ SetCVar("Sound_EnableMusic", 1)
+ PlayMusic(E.Media.Sounds.HelloKitty)
+ E:StaticPopup_Show("HELLO_KITTY_END")
+
+ self.db.general.kittys = true
+ self:CreateKittys()
+
+ self:UpdateAll()
+ end
+ end
+
+ function E:RestoreHelloKitty()
+ --Store old settings
+ self.db.general.kittys = false
+ if HelloKittyLeft then
+ HelloKittyLeft:Hide()
+ HelloKittyRight:Hide()
+ end
+
+ if not self.db.tempSettings then return end
+ if self:HelloKittyFixCheck() then
+ self:HelloKittyFix()
+ self.db.tempSettings = nil
+ return
+ end
+ local c = self.db.tempSettings.backdropcolor
+ self.db.general.backdropcolor = {r = c.r, g = c.g, b = c.b}
+
+ c = self.db.tempSettings.backdropfadecolor
+ self.db.general.backdropfadecolor = {r = c.r, g = c.g, b = c.b, a = (c.a or 0.8)}
+
+ c = self.db.tempSettings.bordercolor
+ self.db.general.bordercolor = {r = c.r, g = c.g, b = c.b}
+
+ c = self.db.tempSettings.valuecolor
+ self.db.general.valuecolor = {r = c.r, g = c.g, b = c.b}
+
+ self.db.chat.panelBackdropNameLeft = self.db.tempSettings.panelBackdropNameLeft
+ self.db.chat.panelBackdropNameRight = self.db.tempSettings.panelBackdropNameRight
+
+ c = self.db.tempSettings.health
+ self.db.unitframe.colors.health = {r = c.r, g = c.g, b = c.b}
+ self.db.unitframe.colors.healthclass = self.db.tempSettings.healthclass
+
+ c = self.db.tempSettings.castColor
+ self.db.unitframe.colors.castColor = {r = c.r, g = c.g, b = c.b}
+ self.db.unitframe.colors.transparentCastbar = self.db.tempSettings.transparentCastbar
+
+ c = self.db.tempSettings.auraBarBuff
+ self.db.unitframe.colors.auraBarBuff = {r = c.r, g = c.g, b = c.b}
+ self.db.unitframe.colors.transparentAurabars = self.db.tempSettings.transparentAurabars
+
+ self.db.tempSettings = nil
+
+ self:UpdateAll()
+ end
+
+ function E:CreateKittys()
+ if HelloKittyLeft then
+ HelloKittyLeft:Show()
+ HelloKittyRight:Show()
+ return
+ end
+ local helloKittyLeft = CreateFrame("Frame", "HelloKittyLeft", UIParent)
+ helloKittyLeft:SetSize(120, 128)
+ helloKittyLeft:SetMovable(true)
+ helloKittyLeft:EnableMouse(true)
+ helloKittyLeft:RegisterForDrag("LeftButton")
+ helloKittyLeft:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMRIGHT", 2, -4)
+ helloKittyLeft.tex = helloKittyLeft:CreateTexture(nil, "OVERLAY")
+ helloKittyLeft.tex:SetAllPoints()
+ helloKittyLeft.tex:SetTexture(E.Media.Textures.HelloKitty)
+ helloKittyLeft.tex:SetTexCoord(0, 0, 0, 1, 0, 0, 0, 1)
+ helloKittyLeft.curFrame = 1
+ helloKittyLeft.countUp = true
+ helloKittyLeft:SetClampedToScreen(true)
+ helloKittyLeft:SetScript("OnDragStart", OnDragStart)
+ helloKittyLeft:SetScript("OnDragStop", OnDragStop)
+ helloKittyLeft:SetScript("OnUpdate", OnUpdate)
+
+ local helloKittyRight = CreateFrame("Frame", "HelloKittyRight", UIParent)
+ helloKittyRight:SetSize(120, 128)
+ helloKittyRight:SetMovable(true)
+ helloKittyRight:EnableMouse(true)
+ helloKittyRight:RegisterForDrag("LeftButton")
+ helloKittyRight:Point("BOTTOMRIGHT", RightChatPanel, "BOTTOMLEFT", -2, -4)
+ helloKittyRight.tex = helloKittyRight:CreateTexture(nil, "OVERLAY")
+ helloKittyRight.tex:SetAllPoints()
+ helloKittyRight.tex:SetTexture(E.Media.Textures.HelloKitty)
+ helloKittyRight.tex:SetTexCoord(0, 0, 0, 1, 0, 0, 0, 1)
+ helloKittyRight.curFrame = 10
+ helloKittyRight.countUp = false
+ helloKittyRight:SetClampedToScreen(true)
+ helloKittyRight:SetScript("OnDragStart", OnDragStart)
+ helloKittyRight:SetScript("OnDragStop", OnDragStop)
+ helloKittyRight:SetScript("OnUpdate", OnUpdate)
+ end
+
+ --When it bugged out for a user the command "/hellokittyfix" attempted to restore the changed settings to default
+ function E:HelloKittyFixCheck(secondCheck)
+ local t = self.db.tempSettings
+ if not t and not secondCheck then t = self.db.general end
+ if t and t.backdropcolor then
+ return self:Round(t.backdropcolor.r, 2) == 0.87 and self:Round(t.backdropcolor.g, 2) == 0.3 and self:Round(t.backdropcolor.b, 2) == 0.74
+ end
+ end
+
+ function E:HelloKittyFix()
+ local c = P.general.backdropcolor
+ self.db.general.backdropcolor = {r = c.r, g = c.g, b = c.b}
+
+ c = P.general.backdropfadecolor
+ self.db.general.backdropfadecolor = {r = c.r, g = c.g, b = c.b, a = (c.a or 0.8)}
+
+ c = P.general.bordercolor
+ self.db.general.bordercolor = {r = c.r, g = c.g, b = c.b}
+
+ c = P.general.valuecolor
+ self.db.general.valuecolor = {r = c.r, g = c.g, b = c.b}
+
+ self.db.chat.panelBackdropNameLeft = ""
+ self.db.chat.panelBackdropNameRight = ""
+
+ c = P.unitframe.colors.health
+ self.db.unitframe.colors.health = {r = c.r, g = c.g, b = c.b}
+
+ c = P.unitframe.colors.castColor
+ self.db.unitframe.colors.castColor = {r = c.r, g = c.g, b = c.b}
+ self.db.unitframe.colors.transparentCastbar = false
+
+ c = P.unitframe.colors.castColor
+ self.db.unitframe.colors.auraBarBuff = {r = c.r, g = c.g, b = c.b}
+ self.db.unitframe.colors.transparentAurabars = false
+
+ if HelloKittyLeft then
+ HelloKittyLeft:Hide()
+ HelloKittyRight:Hide()
+ self.db.general.kittys = nil
+ return
+ end
+
+ self.db.tempSettings = nil
+ self:UpdateAll()
+ end
+
+ function E:HelloKittyToggle()
+ if HelloKittyLeft and HelloKittyLeft:IsShown() then
+ self:RestoreHelloKitty()
+ else
+ self:StaticPopup_Show("HELLO_KITTY")
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Core/Commands.lua b/ElvUI/Core/Commands.lua
new file mode 100644
index 0000000..375a41f
--- /dev/null
+++ b/ElvUI/Core/Commands.lua
@@ -0,0 +1,280 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+local AB = E:GetModule("ActionBars")
+
+--Lua functions
+local tonumber, type = tonumber, type
+local format, lower, match, split = string.format, string.lower, string.match, string.split
+--WoW API / Variables
+local InCombatLockdown = InCombatLockdown
+local UIFrameFadeOut, UIFrameFadeIn = UIFrameFadeOut, UIFrameFadeIn
+local EnableAddOn, DisableAllAddOns = EnableAddOn, DisableAllAddOns
+local SetCVar = SetCVar
+local ReloadUI = ReloadUI
+local debugprofilestop = debugprofilestop
+local UpdateAddOnCPUUsage, GetAddOnCPUUsage = UpdateAddOnCPUUsage, GetAddOnCPUUsage
+local ResetCPUUsage = ResetCPUUsage
+local GetAddOnInfo = GetAddOnInfo
+local GetCVarBool = GetCVarBool
+local ERR_NOT_IN_COMBAT = ERR_NOT_IN_COMBAT
+
+function E:Grid(msg)
+ msg = msg and tonumber(msg)
+ if type(msg) == "number" and (msg <= 256 and msg >= 4) then
+ E.db.gridSize = msg
+ E:Grid_Show()
+ elseif ElvUIGrid and ElvUIGrid:IsShown() then
+ E:Grid_Hide()
+ else
+ E:Grid_Show()
+ end
+end
+
+function E:LuaError(msg)
+ msg = lower(msg)
+ if msg == "on" then
+ DisableAllAddOns()
+ EnableAddOn("ElvUI")
+ EnableAddOn("ElvUI_OptionsUI")
+ SetCVar("scriptErrors", 1)
+ ReloadUI()
+ elseif msg == "off" then
+ SetCVar("scriptErrors", 0)
+ E:Print("Lua errors off.")
+ else
+ E:Print("/luaerror on - /luaerror off")
+ end
+end
+
+function E:BGStats()
+ DT.ForceHideBGStats = nil
+ DT:LoadDataTexts()
+
+ E:Print(L["Battleground datatexts will now show again if you are inside a battleground."])
+end
+
+local function OnCallback(command)
+ MacroEditBox:GetScript("OnEvent")(MacroEditBox, "EXECUTE_CHAT_LINE", command)
+end
+
+function E:DelayScriptCall(msg)
+ local secs, command = match(msg, "^(%S+)%s+(.*)$")
+ secs = tonumber(secs)
+ if (not secs) or (#command == 0) then
+ self:Print("usage: /in ")
+ self:Print("example: /in 1.5 /say hi")
+ else
+ E:Delay(secs, OnCallback, command)
+ end
+end
+
+function FarmMode()
+ if InCombatLockdown() then E:Print(ERR_NOT_IN_COMBAT) return end
+ if not E.private.general.minimap.enable then return end
+
+ if Minimap:IsShown() then
+ UIFrameFadeOut(Minimap, 0.3)
+ UIFrameFadeIn(FarmModeMap, 0.3)
+ Minimap.fadeInfo.finishedFunc = function()
+ Minimap:Hide()
+ FarmModeMap:SetAlpha(1)
+
+ local zoomLevel = Minimap:GetZoom()
+ if zoomLevel < 5 then
+ Minimap:SetZoom(zoomLevel + 1)
+ Minimap:SetZoom(zoomLevel)
+ else
+ Minimap:SetZoom(zoomLevel - 1)
+ Minimap:SetZoom(zoomLevel)
+ end
+ end
+ FarmModeMap.enabled = true
+ else
+ UIFrameFadeOut(FarmModeMap, 0.3)
+ UIFrameFadeIn(Minimap, 0.3)
+ FarmModeMap.fadeInfo.finishedFunc = function()
+ FarmModeMap:Hide()
+ Minimap:SetAlpha(1)
+
+ local zoomLevel = Minimap:GetZoom()
+ if zoomLevel < 5 then
+ Minimap:SetZoom(zoomLevel + 1)
+ Minimap:SetZoom(zoomLevel)
+ else
+ Minimap:SetZoom(zoomLevel - 1)
+ Minimap:SetZoom(zoomLevel)
+ end
+ end
+ FarmModeMap.enabled = false
+ end
+end
+
+function E:FarmMode(msg)
+ if not E.private.general.minimap.enable then return end
+
+ if msg and type(tonumber(msg)) == "number" and tonumber(msg) <= 500 and tonumber(msg) >= 20 and not InCombatLockdown() then
+ E.db.farmSize = tonumber(msg)
+ FarmModeMap:Size(tonumber(msg))
+ end
+
+ FarmMode()
+end
+
+-- make this a locale later?
+local MassKickMessage = "Guild Cleanup Results: Removed all guild members below rank %s, that have a minimal level of %s, and have not been online for at least: %s days."
+function E:MassGuildKick(msg)
+ local minLevel, minDays, minRankIndex = split(",", msg)
+ minRankIndex = tonumber(minRankIndex)
+ minLevel = tonumber(minLevel)
+ minDays = tonumber(minDays)
+
+ if not minLevel or not minDays then
+ E:Print("Usage: /cleanguild , , []")
+ return
+ end
+
+ if minDays > 31 then
+ E:Print("Maximum days value must be below 32.")
+ return
+ end
+
+ if not minRankIndex then minRankIndex = GuildControlGetNumRanks() - 1 end
+
+ for i = 1, GetNumGuildMembers() do
+ local name, _, rankIndex, level, _, _, note, officerNote, connected, _, classFileName = GetGuildRosterInfo(i)
+ local minLevelx = minLevel
+
+ if classFileName == "DEATHKNIGHT" then
+ minLevelx = minLevelx + 55
+ end
+
+ if not connected then
+ local years, months, days = GetGuildRosterLastOnline(i)
+ if days ~= nil and ((years > 0 or months > 0 or days >= minDays) and rankIndex >= minRankIndex)
+ and note ~= nil and officerNote ~= nil and (level <= minLevelx) then
+ GuildUninvite(name)
+ end
+ end
+ end
+
+ SendChatMessage(format(MassKickMessage, GuildControlGetRankName(minRankIndex), minLevel, minDays), "GUILD")
+end
+
+local num_frames = 0
+local function OnUpdate()
+ num_frames = num_frames + 1
+end
+local f = CreateFrame("Frame")
+f:Hide()
+f:SetScript("OnUpdate", OnUpdate)
+
+local toggleMode, debugTimer, cpuImpactMessage = false, 0, "Consumed %sms per frame. Each frame took %sms to render."
+function E:GetCPUImpact()
+ if not GetCVarBool("scriptProfile") then
+ E:Print("For `/cpuimpact` to work, you need to enable script profiling via: `/console scriptProfile 1` then reload. Disable after testing by setting it back to 0.")
+ return
+ end
+
+ if not toggleMode then
+ ResetCPUUsage()
+ toggleMode, num_frames, debugTimer = true, 0, debugprofilestop()
+ self:Print("CPU Impact being calculated, type /cpuimpact to get results when you are ready.")
+ f:Show()
+ else
+ f:Hide()
+ local ms_passed = debugprofilestop() - debugTimer
+ UpdateAddOnCPUUsage()
+
+ local per, passed =
+ ((num_frames == 0 and 0) or (GetAddOnCPUUsage("ElvUI") / num_frames)),
+ ((num_frames == 0 and 0) or (ms_passed / num_frames))
+ self:Print(format(cpuImpactMessage, per and per > 0 and format("%.3f", per) or 0, passed and passed > 0 and format("%.3f", passed) or 0))
+ toggleMode = false
+ end
+end
+
+local BLIZZARD_ADDONS = {
+ "Blizzard_AchievementUI",
+ "Blizzard_ArenaUI",
+ "Blizzard_AuctionUI",
+ "Blizzard_BarbershopUI",
+ "Blizzard_BattlefieldMinimap",
+ "Blizzard_BindingUI",
+ "Blizzard_Calendar",
+ "Blizzard_CombatLog",
+ "Blizzard_CombatText",
+ "Blizzard_DebugTools",
+ "Blizzard_GlyphUI",
+ "Blizzard_GMChatUI",
+ "Blizzard_GMSurveyUI",
+ "Blizzard_GuildBankUI",
+ "Blizzard_InspectUI",
+ "Blizzard_ItemSocketingUI",
+ "Blizzard_MacroUI",
+ "Blizzard_RaidUI",
+ "Blizzard_TalentUI",
+ "Blizzard_TimeManager",
+ "Blizzard_TokenUI",
+ "Blizzard_TradeSkillUI",
+ "Blizzard_TrainerUI"
+}
+
+function E:EnableBlizzardAddOns()
+ for _, addon in pairs(BLIZZARD_ADDONS) do
+ local reason = select(5, GetAddOnInfo(addon))
+ if reason == "DISABLED" then
+ EnableAddOn(addon)
+ E:Print("The following addon was re-enabled:", addon)
+ end
+ end
+end
+
+function E:ChangeRole(role)
+ local roles = {
+ ["melee"]="Melee",
+ ["caster"]="Caster",
+ ["ranged"]="Ranged",
+ ["tank"]="Tank",
+ }
+ E.Role = roles[lower(role)] or "Melee"
+ print("Role was changed to:", E.Role)
+end
+
+function E:LoadCommands()
+ self:RegisterChatCommand("in", "DelayScriptCall")
+ self:RegisterChatCommand("ec", "ToggleOptionsUI")
+ self:RegisterChatCommand("elvui", "ToggleOptionsUI")
+ self:RegisterChatCommand("cpuimpact", "GetCPUImpact")
+
+ self:RegisterChatCommand("cpuusage", "GetTopCPUFunc")
+ -- args: module, showall, delay, minCalls
+ -- Example1: /cpuusage all
+ -- Example2: /cpuusage Bags true
+ -- Example3: /cpuusage UnitFrames nil 50 25
+ -- Note: showall, delay, and minCalls will default if not set
+ -- arg1 can be "all" this will scan all registered modules!
+
+ self:RegisterChatCommand("bgstats", "BGStats")
+ self:RegisterChatCommand("hellokitty", "HelloKittyToggle")
+ self:RegisterChatCommand("hellokittyfix", "HelloKittyFix")
+ self:RegisterChatCommand("harlemshake", "HarlemShakeToggle")
+ self:RegisterChatCommand("luaerror", "LuaError")
+ self:RegisterChatCommand("egrid", "Grid")
+ self:RegisterChatCommand("moveui", "ToggleMoveMode")
+ self:RegisterChatCommand("resetui", "ResetUI")
+ self:RegisterChatCommand("enable", "EnableAddon")
+ self:RegisterChatCommand("disable", "DisableAddon")
+ self:RegisterChatCommand("farmmode", "FarmMode")
+ self:RegisterChatCommand("cleanguild", "MassGuildKick")
+ self:RegisterChatCommand("estatus", "ShowStatusReport")
+
+ self:RegisterChatCommand("role", "ChangeRole")
+ -- This command is added for Ascension. Role checks will be unreliable, but
+ -- this will allow one to set Role manually.
+ -- /role expects one of "melee", "caster", "ranged", "tank"
+ -- and defaults to "melee" if no role is provided.
+
+ if E.private.actionbar.enable then
+ self:RegisterChatCommand("kb", AB.ActivateBindMode)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Core/Config.lua b/ElvUI/Core/Config.lua
new file mode 100644
index 0000000..a0ea893
--- /dev/null
+++ b/ElvUI/Core/Config.lua
@@ -0,0 +1,509 @@
+local E, L, V, P, G = unpack(select(2, ...)); -- Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+local type, ipairs, tonumber = type, ipairs, tonumber
+local floor, select = floor, select
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local IsAddOnLoaded = IsAddOnLoaded
+local InCombatLockdown = InCombatLockdown
+local EditBox_ClearFocus = EditBox_ClearFocus
+local RESET = RESET
+
+local selectedValue, grid = "ALL"
+
+E.ConfigModeLayouts = {
+ "ALL",
+ "GENERAL",
+ "SOLO",
+ "PARTY",
+ "ARENA",
+ "RAID",
+ "ACTIONBARS"
+}
+
+E.ConfigModeLocalizedStrings = {
+ ALL = ALL,
+ GENERAL = GENERAL,
+ SOLO = SOLO,
+ PARTY = PARTY,
+ ARENA = ARENA,
+ RAID = RAID,
+ ACTIONBARS = ACTIONBARS_LABEL
+}
+
+function E:Grid_Show()
+ if not grid then
+ E:Grid_Create()
+ elseif grid.boxSize ~= E.db.gridSize then
+ grid:Hide()
+ E:Grid_Create()
+ else
+ grid:Show()
+ end
+end
+
+function E:Grid_Hide()
+ if grid then
+ grid:Hide()
+ end
+end
+
+function E:ToggleMoveMode(override, configType)
+ if InCombatLockdown() then return end
+ if override ~= nil and override ~= "" then E.ConfigurationMode = override end
+
+ if E.ConfigurationMode ~= true then
+ E:Grid_Show()
+
+ if not ElvUIMoverPopupWindow then
+ E:CreateMoverPopup()
+ end
+
+ ElvUIMoverPopupWindow:Show()
+
+ if IsAddOnLoaded("ElvUI_OptionsUI") then
+ if E.Libs.AceConfigDialog then
+ E.Libs.AceConfigDialog:Close("ElvUI")
+ end
+
+ GameTooltip:Hide()
+ end
+
+ E.ConfigurationMode = true
+ else
+ E:Grid_Hide()
+
+ if ElvUIMoverPopupWindow then
+ ElvUIMoverPopupWindow:Hide()
+ end
+
+ E.ConfigurationMode = false
+ end
+
+ if type(configType) ~= "string" then
+ configType = nil
+ end
+
+ self:ToggleMovers(E.ConfigurationMode, configType or "ALL")
+end
+
+function E:Grid_GetRegion()
+ if grid then
+ if grid.regionCount and grid.regionCount > 0 then
+ local line = select(grid.regionCount, grid:GetRegions())
+ grid.regionCount = grid.regionCount - 1
+ line:SetAlpha(1)
+ return line
+ else
+ return grid:CreateTexture()
+ end
+ end
+end
+
+function E:Grid_Create()
+ if not grid then
+ grid = CreateFrame("Frame", "ElvUIGrid", E.UIParent)
+ grid:SetFrameStrata("BACKGROUND")
+ else
+ grid.regionCount = 0
+ local numRegions = grid:GetNumRegions()
+ for i = 1, numRegions do
+ local region = select(i, grid:GetRegions())
+ if region and region.IsObjectType and region:IsObjectType("Texture") then
+ grid.regionCount = grid.regionCount + 1
+ region:SetAlpha(0)
+ end
+ end
+ end
+
+ local size = E.mult
+ local width, height = E.UIParent:GetSize()
+
+ local ratio = width / height
+ local hStepheight = height * ratio
+ local wStep = width / E.db.gridSize
+ local hStep = hStepheight / E.db.gridSize
+
+ grid.boxSize = E.db.gridSize
+ grid:SetPoint("CENTER", E.UIParent)
+ grid:SetSize(width, height)
+ grid:Show()
+
+ for i = 0, E.db.gridSize do
+ local tx = E:Grid_GetRegion()
+ if i == E.db.gridSize / 2 then
+ tx:SetTexture(1, 0, 0)
+ tx:SetDrawLayer("BORDER")
+ else
+ tx:SetTexture(0, 0, 0)
+ tx:SetDrawLayer("BACKGROUND")
+ end
+ tx:ClearAllPoints()
+ tx:Point("TOPLEFT", grid, "TOPLEFT", i*wStep - (size/2), 0)
+ tx:Point("BOTTOMRIGHT", grid, "BOTTOMLEFT", i*wStep + (size/2), 0)
+ end
+
+ do
+ local tx = E:Grid_GetRegion()
+ tx:SetTexture(1, 0, 0)
+ tx:SetDrawLayer("BORDER")
+ tx:ClearAllPoints()
+ tx:Point("TOPLEFT", grid, "TOPLEFT", 0, -(height/2) + (size/2))
+ tx:Point("BOTTOMRIGHT", grid, "TOPRIGHT", 0, -(height/2 + size/2))
+ end
+
+ for i = 1, floor((height/2)/hStep) do
+ local tx = E:Grid_GetRegion()
+ tx:SetTexture(0, 0, 0)
+ tx:SetDrawLayer("BACKGROUND")
+ tx:ClearAllPoints()
+ tx:Point("TOPLEFT", grid, "TOPLEFT", 0, -(height/2+i*hStep) + (size/2))
+ tx:Point("BOTTOMRIGHT", grid, "TOPRIGHT", 0, -(height/2+i*hStep + size/2))
+
+ tx = E:Grid_GetRegion()
+ tx:SetTexture(0, 0, 0)
+ tx:SetDrawLayer("BACKGROUND")
+ tx:ClearAllPoints()
+ tx:Point("TOPLEFT", grid, "TOPLEFT", 0, -(height/2-i*hStep) + (size/2))
+ tx:Point("BOTTOMRIGHT", grid, "TOPRIGHT", 0, -(height/2-i*hStep + size/2))
+ end
+end
+
+local function ConfigMode_OnClick(self)
+ selectedValue = self.value
+ E:ToggleMoveMode(false, self.value)
+ UIDropDownMenu_SetSelectedValue(ElvUIMoverPopupWindowDropDown, self.value)
+end
+
+local function ConfigMode_Initialize()
+ local info = _G.UIDropDownMenu_CreateInfo()
+ info.func = ConfigMode_OnClick
+
+ for _, configMode in ipairs(E.ConfigModeLayouts) do
+ info.text = E.ConfigModeLocalizedStrings[configMode]
+ info.value = configMode
+ UIDropDownMenu_AddButton(info)
+ end
+
+ UIDropDownMenu_SetSelectedValue(ElvUIMoverPopupWindowDropDown, selectedValue)
+end
+
+function E:NudgeMover(nudgeX, nudgeY)
+ local mover = ElvUIMoverNudgeWindow.child
+ local x, y, point = E:CalculateMoverPoints(mover, nudgeX, nudgeY)
+
+ mover:ClearAllPoints()
+ mover:Point(mover.positionOverride or point, E.UIParent, mover.positionOverride and "BOTTOMLEFT" or point, x, y)
+ E:SaveMoverPosition(mover.name)
+
+ --Update coordinates in Nudge Window
+ E:UpdateNudgeFrame(mover, x, y)
+end
+
+function E:UpdateNudgeFrame(mover, x, y)
+ if not (x and y) then
+ x, y = E:CalculateMoverPoints(mover)
+ end
+
+ x = E:Round(x, 0)
+ y = E:Round(y, 0)
+
+ local ElvUIMoverNudgeWindow = ElvUIMoverNudgeWindow
+ ElvUIMoverNudgeWindow.xOffset:SetText(x)
+ ElvUIMoverNudgeWindow.yOffset:SetText(y)
+ ElvUIMoverNudgeWindow.xOffset.currentValue = x
+ ElvUIMoverNudgeWindow.yOffset.currentValue = y
+ ElvUIMoverNudgeWindow.title:SetText(mover.textString)
+end
+
+function E:AssignFrameToNudge()
+ ElvUIMoverNudgeWindow.child = self
+ E:UpdateNudgeFrame(self)
+end
+
+function E:CreateMoverPopup()
+ local f = CreateFrame("Frame", "ElvUIMoverPopupWindow", UIParent)
+ f:SetFrameStrata("DIALOG")
+ f:SetToplevel(true)
+ f:EnableMouse(true)
+ f:SetMovable(true)
+ f:SetFrameLevel(99)
+ f:SetClampedToScreen(true)
+ f:Width(360)
+ f:Height(195)
+ f:SetTemplate("Transparent")
+ f:Point("BOTTOM", UIParent, "CENTER", 0, 100)
+ f:SetScript("OnHide", function()
+ if ElvUIMoverPopupWindowDropDown then
+ UIDropDownMenu_SetSelectedValue(ElvUIMoverPopupWindowDropDown, "ALL")
+ end
+ end)
+ f:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
+ f:CreateShadow(5)
+ f:Hide()
+
+ local header = CreateFrame("Button", nil, f)
+ header:SetTemplate(nil, true)
+ header:Width(100)
+ header:Height(25)
+ header:Point("CENTER", f, "TOP")
+ header:SetFrameLevel(header:GetFrameLevel() + 2)
+ header:EnableMouse(true)
+ header:RegisterForClicks("AnyUp", "AnyDown")
+ header:SetScript("OnMouseDown", function() f:StartMoving() end)
+ header:SetScript("OnMouseUp", function() f:StopMovingOrSizing() end)
+ header:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
+
+ local title = header:CreateFontString("OVERLAY")
+ title:FontTemplate()
+ title:Point("CENTER", header, "CENTER")
+ title:SetText("ElvUI")
+
+ local desc = f:CreateFontString("ARTWORK")
+ desc:SetFontObject("GameFontHighlight")
+ desc:SetJustifyV("TOP")
+ desc:SetJustifyH("LEFT")
+ desc:Point("TOPLEFT", 18, -32)
+ desc:Point("BOTTOMRIGHT", -18, 48)
+ desc:SetText(L["DESC_MOVERCONFIG"])
+
+ local snapping = CreateFrame("CheckButton", f:GetName().."CheckButton", f, "OptionsCheckButtonTemplate")
+ _G[snapping:GetName().."Text"]:SetText(L["Sticky Frames"])
+
+ snapping:SetScript("OnShow", function(cb)
+ cb:SetChecked(E.db.general.stickyFrames)
+ end)
+
+ snapping:SetScript("OnClick", function(cb)
+ E.db.general.stickyFrames = cb:GetChecked()
+ end)
+
+ local lock = CreateFrame("Button", f:GetName().."CloseButton", f, "OptionsButtonTemplate")
+ _G[lock:GetName().."Text"]:SetText(L["Lock"])
+
+ lock:SetScript("OnClick", function()
+ E:ToggleMoveMode(true)
+
+ if IsAddOnLoaded("ElvUI_OptionsUI") and E.Libs.AceConfigDialog then
+ E.Libs.AceConfigDialog:Open("ElvUI")
+ end
+
+ selectedValue = "ALL"
+ UIDropDownMenu_SetSelectedValue(ElvUIMoverPopupWindowDropDown, selectedValue)
+ end)
+
+ local align = CreateFrame("EditBox", f:GetName().."EditBox", f, "InputBoxTemplate")
+ align:Width(24)
+ align:Height(17)
+ align:SetAutoFocus(false)
+ align:SetScript("OnEscapePressed", function(eb)
+ eb:SetText(E.db.gridSize)
+ EditBox_ClearFocus(eb)
+ end)
+ align:SetScript("OnEnterPressed", function(eb)
+ local text = eb:GetText()
+ if tonumber(text) then
+ if tonumber(text) <= 256 and tonumber(text) >= 4 then
+ E.db.gridSize = tonumber(text)
+ else
+ eb:SetText(E.db.gridSize)
+ end
+ else
+ eb:SetText(E.db.gridSize)
+ end
+ E:Grid_Show()
+ EditBox_ClearFocus(eb)
+ end)
+ align:SetScript("OnEditFocusLost", function(eb)
+ eb:SetText(E.db.gridSize)
+ end)
+ align:SetScript("OnEditFocusGained", align.HighlightText)
+ align:SetScript("OnShow", function(eb)
+ EditBox_ClearFocus(eb)
+ eb:SetText(E.db.gridSize)
+ end)
+
+ align.text = align:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ align.text:Point("RIGHT", align, "LEFT", -4, 0)
+ align.text:SetText(L["Grid Size:"])
+
+ --position buttons
+ snapping:Point("BOTTOMLEFT", 14, 10)
+ lock:Point("BOTTOMRIGHT", -14, 14)
+ align:Point("TOPRIGHT", lock, "TOPLEFT", -4, -2)
+
+ S:HandleCheckBox(snapping)
+ S:HandleButton(lock)
+ S:HandleEditBox(align)
+
+ f:RegisterEvent("PLAYER_REGEN_DISABLED")
+ f:SetScript("OnEvent", function(mover)
+ if mover:IsShown() then
+ mover:Hide()
+ E:Grid_Hide()
+ E:ToggleMoveMode(true)
+ end
+ end)
+
+ local configMode = CreateFrame("Frame", f:GetName().."DropDown", f, "UIDropDownMenuTemplate")
+ configMode:Point("BOTTOMRIGHT", lock, "TOPRIGHT", 8, -5)
+ S:HandleDropDownBox(configMode, 148)
+ configMode.text = configMode:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ configMode.text:Point("RIGHT", configMode.backdrop, "LEFT", -2, 0)
+ configMode.text:SetText(L["Config Mode:"])
+
+ UIDropDownMenu_Initialize(configMode, ConfigMode_Initialize)
+
+ local nudgeFrame = CreateFrame("Frame", "ElvUIMoverNudgeWindow", E.UIParent)
+ nudgeFrame:SetFrameStrata("DIALOG")
+ nudgeFrame:Width(200)
+ nudgeFrame:Height(110)
+ nudgeFrame:SetTemplate("Transparent")
+ nudgeFrame:CreateShadow(5)
+ nudgeFrame:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
+ nudgeFrame:SetFrameLevel(100)
+ nudgeFrame:Hide()
+ nudgeFrame:EnableMouse(true)
+ nudgeFrame:SetClampedToScreen(true)
+
+ ElvUIMoverPopupWindow:HookScript("OnHide", function() ElvUIMoverNudgeWindow:Hide() end)
+
+ desc = nudgeFrame:CreateFontString("ARTWORK")
+ desc:SetFontObject("GameFontHighlight")
+ desc:SetJustifyV("TOP")
+ desc:SetJustifyH("LEFT")
+ desc:Point("TOPLEFT", 18, -15)
+ desc:Point("BOTTOMRIGHT", -18, 28)
+ desc:SetJustifyH("CENTER")
+ nudgeFrame.title = desc
+
+ header = CreateFrame("Button", nil, nudgeFrame)
+ header:SetTemplate(nil, true)
+ header:Width(100)
+ header:Height(25)
+ header:Point("CENTER", nudgeFrame, "TOP")
+ header:SetFrameLevel(header:GetFrameLevel() + 2)
+ header:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
+
+ title = header:CreateFontString("OVERLAY")
+ title:FontTemplate()
+ title:Point("CENTER", header, "CENTER")
+ title:SetText(L["Nudge"])
+
+ local xOffset = CreateFrame("EditBox", nudgeFrame:GetName().."XEditBox", nudgeFrame, "InputBoxTemplate")
+ xOffset:Width(50)
+ xOffset:Height(17)
+ xOffset:SetAutoFocus(false)
+ xOffset.currentValue = 0
+ xOffset:SetScript("OnEscapePressed", function(eb)
+ eb:SetText(E:Round(xOffset.currentValue))
+ EditBox_ClearFocus(eb)
+ end)
+ xOffset:SetScript("OnEnterPressed", function(eb)
+ local num = eb:GetText()
+ if tonumber(num) then
+ local diff = num - xOffset.currentValue
+ xOffset.currentValue = num
+ E:NudgeMover(diff)
+ end
+ eb:SetText(E:Round(xOffset.currentValue))
+ EditBox_ClearFocus(eb)
+ end)
+ xOffset:SetScript("OnEditFocusLost", function(eb)
+ eb:SetText(E:Round(xOffset.currentValue))
+ end)
+ xOffset:SetScript("OnEditFocusGained", xOffset.HighlightText)
+ xOffset:SetScript("OnShow", function(eb)
+ EditBox_ClearFocus(eb)
+ eb:SetText(E:Round(xOffset.currentValue))
+ end)
+
+ xOffset.text = xOffset:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ xOffset.text:Point("RIGHT", xOffset, "LEFT", -4, 0)
+ xOffset.text:SetText("X:")
+ xOffset:Point("BOTTOMRIGHT", nudgeFrame, "CENTER", -6, 8)
+ nudgeFrame.xOffset = xOffset
+ S:HandleEditBox(xOffset)
+
+ local yOffset = CreateFrame("EditBox", nudgeFrame:GetName().."YEditBox", nudgeFrame, "InputBoxTemplate")
+ yOffset:Width(50)
+ yOffset:Height(17)
+ yOffset:SetAutoFocus(false)
+ yOffset.currentValue = 0
+ yOffset:SetScript("OnEscapePressed", function(eb)
+ eb:SetText(E:Round(yOffset.currentValue))
+ EditBox_ClearFocus(eb)
+ end)
+ yOffset:SetScript("OnEnterPressed", function(eb)
+ local num = eb:GetText()
+ if tonumber(num) then
+ local diff = num - yOffset.currentValue
+ yOffset.currentValue = num
+ E:NudgeMover(nil, diff)
+ end
+ eb:SetText(E:Round(yOffset.currentValue))
+ EditBox_ClearFocus(eb)
+ end)
+ yOffset:SetScript("OnEditFocusLost", function(eb)
+ eb:SetText(E:Round(yOffset.currentValue))
+ end)
+ yOffset:SetScript("OnEditFocusGained", yOffset.HighlightText)
+ yOffset:SetScript("OnShow", function(eb)
+ EditBox_ClearFocus(eb)
+ eb:SetText(E:Round(yOffset.currentValue))
+ end)
+
+ yOffset.text = yOffset:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ yOffset.text:Point("RIGHT", yOffset, "LEFT", -4, 0)
+ yOffset.text:SetText("Y:")
+ yOffset:Point("BOTTOMLEFT", nudgeFrame, "CENTER", 16, 8)
+ nudgeFrame.yOffset = yOffset
+ S:HandleEditBox(yOffset)
+
+ local resetButton = CreateFrame("Button", nudgeFrame:GetName().."ResetButton", nudgeFrame, "UIPanelButtonTemplate")
+ resetButton:SetText(RESET)
+ resetButton:Point("TOP", nudgeFrame, "CENTER", 0, 2)
+ resetButton:Size(100, 25)
+ resetButton:SetScript("OnClick", function()
+ if ElvUIMoverNudgeWindow.child.textString then
+ E:ResetMovers(ElvUIMoverNudgeWindow.child.textString)
+ end
+ end)
+ S:HandleButton(resetButton)
+
+ local upButton = CreateFrame("Button", nudgeFrame:GetName().."UpButton", nudgeFrame)
+ upButton:Point("BOTTOMRIGHT", nudgeFrame, "BOTTOM", -6, 4)
+ upButton:SetScript("OnClick", function()
+ E:NudgeMover(nil, 1)
+ end)
+ S:HandleNextPrevButton(upButton)
+ upButton:SetSize(22, 22)
+
+ local downButton = CreateFrame("Button", nudgeFrame:GetName().."DownButton", nudgeFrame)
+ downButton:Point("BOTTOMLEFT", nudgeFrame, "BOTTOM", 6, 4)
+ downButton:SetScript("OnClick", function()
+ E:NudgeMover(nil, -1)
+ end)
+ S:HandleNextPrevButton(downButton)
+ downButton:SetSize(22, 22)
+
+ local leftButton = CreateFrame("Button", nudgeFrame:GetName().."LeftButton", nudgeFrame)
+ leftButton:Point("RIGHT", upButton, "LEFT", -6, 0)
+ leftButton:SetScript("OnClick", function()
+ E:NudgeMover(-1)
+ end)
+ S:HandleNextPrevButton(leftButton)
+ leftButton:SetSize(22, 22)
+
+ local rightButton = CreateFrame("Button", nudgeFrame:GetName().."RightButton", nudgeFrame)
+ rightButton:Point("LEFT", downButton, "RIGHT", 6, 0)
+ rightButton:SetScript("OnClick", function()
+ E:NudgeMover(1)
+ end)
+ S:HandleNextPrevButton(rightButton)
+ rightButton:SetSize(22, 22)
+end
\ No newline at end of file
diff --git a/ElvUI/Core/Cooldowns.lua b/ElvUI/Core/Cooldowns.lua
new file mode 100644
index 0000000..33bbede
--- /dev/null
+++ b/ElvUI/Core/Cooldowns.lua
@@ -0,0 +1,320 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+--Lua functions
+local next, ipairs, pairs = next, ipairs, pairs
+local floor, tinsert = math.floor, table.insert
+--WoW API / Variables
+local GetTime = GetTime
+local CreateFrame = CreateFrame
+local hooksecurefunc = hooksecurefunc
+
+local ICON_SIZE = 36 --the normal size for an icon (don't change this)
+local FONT_SIZE = 20 --the base font size to use at a scale of 1
+local MIN_SCALE = 0.5 --the minimum scale we want to show cooldown counts at, anything below this will be hidden
+local MIN_DURATION = 1.5 --the minimum duration to show cooldown text for
+
+function E:Cooldown_TextThreshold(cd, now)
+ if cd.parent and cd.parent.textThreshold and cd.endTime then
+ return (cd.endTime - now) >= cd.parent.textThreshold
+ end
+end
+
+function E:Cooldown_BelowScale(cd)
+ if cd.parent then
+ if cd.parent.hideText then return true end
+ if cd.parent.skipScale then return end
+ end
+
+ return cd.fontScale and (cd.fontScale < MIN_SCALE)
+end
+
+function E:Cooldown_OnUpdate(elapsed)
+ if self.nextUpdate > 0 then
+ self.nextUpdate = self.nextUpdate - elapsed
+ return
+ end
+
+ if not E:Cooldown_IsEnabled(self) then
+ E:Cooldown_StopTimer(self)
+ else
+ local now = GetTime()
+ if self.endCooldown and now >= self.endCooldown then
+ E:Cooldown_StopTimer(self)
+ else
+ if E:Cooldown_BelowScale(self) then
+ self.text:SetText("")
+ self.nextUpdate = 500
+ elseif E:Cooldown_TextThreshold(self, now) then
+ self.text:SetText("")
+ self.nextUpdate = 1
+ elseif self.endTime then
+ local value, id, nextUpdate, remainder = E:GetTimeInfo(self.endTime - now, self.threshold, self.hhmmThreshold, self.mmssThreshold)
+ self.nextUpdate = nextUpdate
+
+ local style = E.TimeFormats[id]
+ if style then
+ local which = (self.textColors and 2 or 1) + (self.showSeconds and 0 or 2)
+ if self.textColors then
+ self.text:SetFormattedText(style[which], value, self.textColors[id], remainder)
+ else
+ self.text:SetFormattedText(style[which], value, remainder)
+ end
+ end
+
+ local color = self.timeColors[id]
+ if color then
+ self.text:SetTextColor(color.r, color.g, color.b)
+ end
+ end
+ end
+ end
+end
+
+function E:Cooldown_OnSizeChanged(cd, width, force)
+ local scale = width and (floor(width + 0.5) / ICON_SIZE)
+
+ -- dont bother updating when the fontScale is the same, unless we are passing the force arg
+ if scale and (scale == cd.fontScale) and (force ~= true) then return end
+ cd.fontScale = scale
+
+ -- this is needed because of skipScale variable, we wont allow a font size under the minscale
+ if cd.fontScale and (cd.fontScale < MIN_SCALE) then
+ scale = MIN_SCALE
+ end
+
+ if cd.customFont then -- override font
+ cd.text:FontTemplate(cd.customFont, (scale * cd.customFontSize), cd.customFontOutline)
+ elseif scale then -- default, no override
+ cd.text:FontTemplate(nil, (scale * FONT_SIZE), "OUTLINE")
+ else -- this should never happen but just incase
+ cd.text:FontTemplate()
+ end
+
+ if E:Cooldown_BelowScale(cd) then
+ cd:Hide()
+ elseif cd.enabled then
+ self:Cooldown_ForceUpdate(cd)
+ end
+end
+
+function E:Cooldown_IsEnabled(cd)
+ if cd.forceEnabled then
+ return true
+ elseif cd.forceDisabled then
+ return false
+ elseif cd.reverseToggle ~= nil then
+ return cd.reverseToggle
+ else
+ return E.db.cooldown.enable
+ end
+end
+
+function E:Cooldown_ForceUpdate(cd)
+ cd.nextUpdate = -1
+ cd:Show()
+end
+
+function E:Cooldown_StopTimer(cd)
+ cd.enabled = nil
+ cd:Hide()
+end
+
+function E:Cooldown_Options(timer, db, parent)
+ local threshold, colors, icolors, hhmm, mmss, fonts
+ if parent and db.override then
+ threshold = db.threshold
+ icolors = db.useIndicatorColor and E.TimeIndicatorColors[parent.CooldownOverride]
+ colors = E.TimeColors[parent.CooldownOverride]
+ end
+
+ if db.checkSeconds then
+ hhmm, mmss = db.hhmmThreshold, db.mmssThreshold
+ end
+
+ timer.timeColors = colors or E.TimeColors
+ timer.threshold = threshold or E.db.cooldown.threshold or E.TimeThreshold
+ timer.textColors = icolors or (E.db.cooldown.useIndicatorColor and E.TimeIndicatorColors)
+ timer.hhmmThreshold = hhmm or (E.db.cooldown.checkSeconds and E.db.cooldown.hhmmThreshold)
+ timer.mmssThreshold = mmss or (E.db.cooldown.checkSeconds and E.db.cooldown.mmssThreshold)
+
+ if db.reverse ~= nil then
+ timer.reverseToggle = (E.db.cooldown.enable and not db.reverse) or (db.reverse and not E.db.cooldown.enable)
+ else
+ timer.reverseToggle = nil
+ end
+
+ if timer.CooldownOverride ~= "auras" then
+ if (db ~= E.db.cooldown) and db.fonts and db.fonts.enable then
+ fonts = db.fonts -- custom fonts override default fonts
+ elseif E.db.cooldown.fonts and E.db.cooldown.fonts.enable then
+ fonts = E.db.cooldown.fonts -- default global font override
+ end
+
+ if fonts and fonts.enable then
+ timer.customFont = E.Libs.LSM:Fetch("font", fonts.font)
+ timer.customFontSize = fonts.fontSize
+ timer.customFontOutline = fonts.fontOutline
+ else
+ timer.customFont = nil
+ timer.customFontSize = nil
+ timer.customFontOutline = nil
+ end
+ end
+end
+
+function E:CreateCooldownTimer(parent)
+ local timer = CreateFrame("Frame", parent:GetName() and "$parentTimer" or nil, parent)
+ timer:SetFrameLevel(parent:GetFrameLevel() + 1)
+ timer:Hide()
+ timer:SetAllPoints()
+ timer.parent = parent
+ parent.timer = timer
+
+ local text = timer:CreateFontString(nil, "OVERLAY")
+ text:Point("CENTER", 1, 1)
+ text:SetJustifyH("CENTER")
+ timer.text = text
+
+ -- can be used to modify elements created from this function
+ if parent.CooldownPreHook then
+ parent.CooldownPreHook(parent)
+ end
+
+ -- cooldown override settings
+ local db = (parent.CooldownOverride and E.db[parent.CooldownOverride]) or E.db
+ if db and db.cooldown then
+ E:Cooldown_Options(timer, db.cooldown, parent)
+ end
+
+ -- keep an eye on the size so we can rescale the font if needed
+ self:Cooldown_OnSizeChanged(timer, parent:GetWidth())
+ parent:SetScript("OnSizeChanged", function(_, width)
+ self:Cooldown_OnSizeChanged(timer, width)
+ end)
+
+ -- keep this after Cooldown_OnSizeChanged
+ timer:SetScript("OnUpdate", E.Cooldown_OnUpdate)
+
+ return timer
+end
+
+E.RegisteredCooldowns = {}
+function E:OnSetCooldown(start, duration)
+ if (not self.forceDisabled) and (start and duration) and (duration > MIN_DURATION) then
+ local timer = self.timer or E:CreateCooldownTimer(self)
+ timer.start = start
+ timer.duration = duration
+ timer.endTime = start + duration
+ timer.endCooldown = timer.endTime - 0.05
+ timer.nextUpdate = -1
+ timer:Show()
+ elseif self.timer then
+ E:Cooldown_StopTimer(self.timer)
+ end
+end
+
+function E:RegisterCooldown(cooldown)
+ if not cooldown.isHooked then
+ hooksecurefunc(cooldown, "SetCooldown", E.OnSetCooldown)
+ cooldown.isHooked = true
+ end
+
+ if not cooldown.isRegisteredCooldown then
+ local module = (cooldown.CooldownOverride or "global")
+ if not E.RegisteredCooldowns[module] then E.RegisteredCooldowns[module] = {} end
+
+ tinsert(E.RegisteredCooldowns[module], cooldown)
+ cooldown.isRegisteredCooldown = true
+ end
+end
+
+function E:GetCooldownColors(db)
+ if not db then db = E.db.cooldown end -- just incase someone calls this without a first arg use the global
+ local c13 = E:RGBToHex(db.hhmmColorIndicator.r, db.hhmmColorIndicator.g, db.hhmmColorIndicator.b) -- color for timers that are soon to expire
+ local c12 = E:RGBToHex(db.mmssColorIndicator.r, db.mmssColorIndicator.g, db.mmssColorIndicator.b) -- color for timers that are soon to expire
+ local c11 = E:RGBToHex(db.expireIndicator.r, db.expireIndicator.g, db.expireIndicator.b) -- color for timers that are soon to expire
+ local c10 = E:RGBToHex(db.secondsIndicator.r, db.secondsIndicator.g, db.secondsIndicator.b) -- color for timers that have seconds remaining
+ local c9 = E:RGBToHex(db.minutesIndicator.r, db.minutesIndicator.g, db.minutesIndicator.b) -- color for timers that have minutes remaining
+ local c8 = E:RGBToHex(db.hoursIndicator.r, db.hoursIndicator.g, db.hoursIndicator.b) -- color for timers that have hours remaining
+ local c7 = E:RGBToHex(db.daysIndicator.r, db.daysIndicator.g, db.daysIndicator.b) -- color for timers that have days remaining
+ local c6 = db.hhmmColor -- HH:MM color
+ local c5 = db.mmssColor -- MM:SS color
+ local c4 = db.expiringColor -- color for timers that are soon to expire
+ local c3 = db.secondsColor -- color for timers that have seconds remaining
+ local c2 = db.minutesColor -- color for timers that have minutes remaining
+ local c1 = db.hoursColor -- color for timers that have hours remaining
+ local c0 = db.daysColor -- color for timers that have days remaining
+ return c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13
+end
+
+function E:UpdateCooldownOverride(module)
+ local cooldowns = (module and E.RegisteredCooldowns[module])
+ if (not cooldowns) or not next(cooldowns) then return end
+
+ for _, parent in ipairs(cooldowns) do
+ local db = (parent.CooldownOverride and E.db[parent.CooldownOverride]) or self.db
+ if db and db.cooldown then
+ local timer = parent.isHooked and parent.isRegisteredCooldown and parent.timer
+ local cd = timer or parent
+
+ -- cooldown override settings
+ E:Cooldown_Options(cd, db.cooldown, parent)
+
+ -- update font on cooldowns
+ if timer and cd then -- has a parent, these are timers from RegisterCooldown
+ self:Cooldown_OnSizeChanged(cd, parent:GetWidth(), true)
+
+ elseif cd.text then
+ if cd.customFont then
+ cd.text:FontTemplate(cd.customFont, cd.customFontSize, cd.customFontOutline)
+ elseif parent.CooldownOverride == "auras" then
+ -- parent.auraType defined in `A:UpdateHeader` and `A:CreateIcon`
+ local font = E.Libs.LSM:Fetch("font", db.font)
+ if font and parent.auraType then
+ local fontSize = db[parent.auraType] and db[parent.auraType].durationFontSize
+ if fontSize then
+ cd.text:FontTemplate(font, fontSize, db.fontOutline)
+ end
+ end
+ end
+
+ -- force update top aura cooldowns
+ if parent.CooldownOverride == "auras" then
+ parent.nextUpdate = -1
+ end
+ end
+ end
+ end
+end
+
+function E:UpdateCooldownSettings(module)
+ local db, timeColors, textColors = E.db.cooldown, E.TimeColors, E.TimeIndicatorColors
+
+ -- update the module timecolors if the config called it but ignore "global" and "all":
+ -- global is the main call from config, all is the core file calls
+ local isModule = module and (module ~= "global" and module ~= "all") and self.db[module] and self.db[module].cooldown
+ if isModule then
+ if not E.TimeColors[module] then E.TimeColors[module] = {} end
+ if not E.TimeIndicatorColors[module] then E.TimeIndicatorColors[module] = {} end
+ db, timeColors, textColors = self.db[module].cooldown, E.TimeColors[module], E.TimeIndicatorColors[module]
+ end
+
+ timeColors[0], timeColors[1], timeColors[2], timeColors[3], timeColors[4], timeColors[5], timeColors[6], textColors[0], textColors[1], textColors[2], textColors[3], textColors[4], textColors[5], textColors[6] = self:GetCooldownColors(db)
+
+ if isModule then
+ E:UpdateCooldownOverride(module)
+ elseif module == "global" then -- this is only a call from the config change
+ for key in pairs(E.RegisteredCooldowns) do
+ E:UpdateCooldownOverride(key)
+ end
+ end
+
+ -- okay update the other override settings if it was one of the core file calls
+ if module and (module == "all") then
+ E:UpdateCooldownSettings("bags")
+ E:UpdateCooldownSettings("nameplates")
+ E:UpdateCooldownSettings("actionbar")
+ E:UpdateCooldownSettings("unitframe")
+ E:UpdateCooldownSettings("auras")
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Core/Core.lua b/ElvUI/Core/Core.lua
new file mode 100644
index 0000000..8ebbf74
--- /dev/null
+++ b/ElvUI/Core/Core.lua
@@ -0,0 +1,1211 @@
+local ElvUI = select(2, ...)
+
+local gameLocale
+do -- Locale doesn't exist yet, make it exist.
+ local convert = {["enGB"] = "enUS", ["esES"] = "esMX", ["itIT"] = "enUS"}
+ local lang = GetLocale()
+
+ gameLocale = convert[lang] or lang or "enUS"
+ ElvUI[2] = ElvUI[1].Libs.ACL:GetLocale("ElvUI", gameLocale)
+end
+
+local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+local ActionBars = E:GetModule("ActionBars")
+local AFK = E:GetModule("AFK")
+local Auras = E:GetModule("Auras")
+local Bags = E:GetModule("Bags")
+local Blizzard = E:GetModule("Blizzard")
+local Chat = E:GetModule("Chat")
+local DataBars = E:GetModule("DataBars")
+local DataTexts = E:GetModule("DataTexts")
+local Layout = E:GetModule("Layout")
+local Minimap = E:GetModule("Minimap")
+local NamePlates = E:GetModule("NamePlates")
+local Threat = E:GetModule("Threat")
+local Tooltip = E:GetModule("Tooltip")
+local Totems = E:GetModule("Totems")
+local ReminderBuffs = E:GetModule("ReminderBuffs")
+local UnitFrames = E:GetModule("UnitFrames")
+
+local LSM = E.Libs.LSM
+
+--Lua functions
+local _G = _G
+local tonumber, pairs, ipairs, error, unpack, select, tostring = tonumber, pairs, ipairs, error, unpack, select, tostring
+local assert, type, print = assert, type, print
+local twipe, tinsert, tremove, next = table.wipe, tinsert, tremove, next
+local format, find, match, strrep, strlen, sub, gsub, strjoin = string.format, string.find, string.match, strrep, strlen, string.sub, string.gsub, strjoin
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetAddOnInfo = GetAddOnInfo
+local GetCVar = GetCVar
+local GetNumPartyMembers = GetNumPartyMembers
+local GetNumRaidMembers = GetNumRaidMembers
+local InCombatLockdown = InCombatLockdown
+local IsInGuild = IsInGuild
+local IsInInstance = IsInInstance
+local SendAddonMessage = SendAddonMessage
+local UnitGUID = UnitGUID
+local ERR_NOT_IN_COMBAT = ERR_NOT_IN_COMBAT
+
+--Constants
+E.noop = function() end
+E.title = format("|cff1784d1E|r|cffe5e3e3lvUI|r")
+E.myfaction, E.myLocalizedFaction = UnitFactionGroup("player")
+E.mylevel = UnitLevel("player")
+E.myLocalizedClass, E.myclass = UnitClass("player") -- On Ascension, this is always (Hero, HERO)
+E.myLocalizedRace, E.myrace = UnitRace("player")
+E.myname = UnitName("player")
+E.myrealm = GetRealmName()
+E.version = GetAddOnMetadata("ElvUI", "Version")
+E.wowpatch, E.wowbuild = GetBuildInfo()
+E.wowbuild = tonumber(E.wowbuild)
+E.resolution = GetCVar("gxResolution")
+E.screenwidth, E.screenheight = tonumber(match(E.resolution, "(%d+)x+%d")), tonumber(match(E.resolution, "%d+x(%d+)"))
+E.isMacClient = IsMacClient()
+E.NewSign = "|TInterface\\OptionsFrame\\UI-OptionsFrame-NewFeatureIcon:14:14|t"
+E.InfoColor = "|cfffe7b2c"
+
+--Tables
+E.media = {}
+E.frames = {}
+E.unitFrameElements = {}
+E.statusBars = {}
+E.texts = {}
+E.snapBars = {}
+E.RegisteredModules = {}
+E.RegisteredInitialModules = {}
+E.ModuleCallbacks = {["CallPriority"] = {}}
+E.InitialModuleCallbacks = {["CallPriority"] = {}}
+E.valueColorUpdateFuncs = {}
+E.TexCoords = {0, 1, 0, 1}
+E.VehicleLocks = {}
+E.CreditsList = {}
+
+E.InversePoints = {
+ TOP = "BOTTOM",
+ BOTTOM = "TOP",
+ TOPLEFT = "BOTTOMLEFT",
+ TOPRIGHT = "BOTTOMRIGHT",
+ LEFT = "RIGHT",
+ RIGHT = "LEFT",
+ BOTTOMLEFT = "TOPLEFT",
+ BOTTOMRIGHT = "TOPRIGHT",
+ CENTER = "CENTER"
+}
+
+local colorizedName
+function E:ColorizedName(name, arg2)
+ local length = strlen(name)
+ for i = 1, length do
+ local letter = sub(name, i, i)
+ if i == 1 then
+ colorizedName = format("|cff1784d1%s", letter)
+ elseif i == 2 then
+ colorizedName = format("%s|r|cffe5e3e3%s", colorizedName, letter)
+ elseif i == length and arg2 then
+ colorizedName = format("%s%s|r|cff1784d1:|r", colorizedName, letter)
+ else
+ colorizedName = colorizedName..letter
+ end
+ end
+ return colorizedName
+end
+
+--This frame everything in ElvUI should be anchored to for Eyefinity support.
+E.UIParent = CreateFrame("Frame", "ElvUIParent", UIParent)
+E.UIParent:SetFrameLevel(UIParent:GetFrameLevel())
+E.UIParent:SetSize(UIParent:GetSize())
+E.UIParent:SetPoint("CENTER", UIParent, "CENTER")
+E.snapBars[#E.snapBars + 1] = E.UIParent
+
+E.HiddenFrame = CreateFrame("Frame")
+E.HiddenFrame:Hide()
+
+do -- used in optionsUI
+ E.DEFAULT_FILTER = {}
+ for filter, tbl in pairs(G.unitframe.aurafilters) do
+ E.DEFAULT_FILTER[filter] = tbl.type
+ end
+end
+
+function E:Print(...)
+ (_G[self.db.general.messageRedirect] or DEFAULT_CHAT_FRAME):AddMessage(strjoin(" ", self:ColorizedName("ElvUI", true), ...)) -- I put DEFAULT_CHAT_FRAME as a fail safe.
+end
+
+local delayedTimer
+local delayedFuncs = {}
+function E:ShapeshiftDelayedUpdate(func, ...)
+ delayedFuncs[func] = {...}
+
+ if delayedTimer then return end
+
+ delayedTimer = E:ScheduleTimer(function()
+ for f in pairs(delayedFuncs) do
+ f(unpack(delayedFuncs[f]))
+ end
+
+ twipe(delayedFuncs)
+ delayedTimer = nil
+ end, 0.05)
+end
+
+function E:GrabColorPickerValues(r, g, b)
+ -- we must block the execution path to `ColorCallback` in `AceGUIWidget-ColorPicker-ElvUI`
+ -- in order to prevent an infinite loop from `OnValueChanged` when passing into `E.UpdateMedia` which eventually leads here again.
+ ColorPickerFrame.noColorCallback = true
+
+ -- grab old values
+ local oldR, oldG, oldB = ColorPickerFrame:GetColorRGB()
+
+ -- set and define the new values
+ ColorPickerFrame:SetColorRGB(r, g, b)
+ r, g, b = ColorPickerFrame:GetColorRGB()
+
+ -- swap back to the old values
+ if oldR then ColorPickerFrame:SetColorRGB(oldR, oldG, oldB) end
+
+ -- free it up..
+ ColorPickerFrame.noColorCallback = nil
+
+ return r, g, b
+end
+
+function E:SetColorTable(t, data)
+ if not data.r or not data.g or not data.b then
+ error("SetColorTable: Could not unpack color values.")
+ end
+
+ if t and (type(t) == "table") then
+ t[1], t[2], t[3], t[4] = E:UpdateColorTable(data)
+ else
+ t = E:GetColorTable(data)
+ end
+
+ return t
+end
+
+function E:UpdateColorTable(data)
+ if not data.r or not data.g or not data.b then
+ error("UpdateColorTable: Could not unpack color values.")
+ end
+
+ if (data.r > 1 or data.r < 0) then data.r = 1 end
+ if (data.g > 1 or data.g < 0) then data.g = 1 end
+ if (data.b > 1 or data.b < 0) then data.b = 1 end
+ if data.a and (data.a > 1 or data.a < 0) then data.a = 1 end
+
+ if data.a then
+ return data.r, data.g, data.b, data.a
+ else
+ return data.r, data.g, data.b
+ end
+end
+
+function E:GetColorTable(data)
+ if not data.r or not data.g or not data.b then
+ error("GetColorTable: Could not unpack color values.")
+ end
+
+ if (data.r > 1 or data.r < 0) then data.r = 1 end
+ if (data.g > 1 or data.g < 0) then data.g = 1 end
+ if (data.b > 1 or data.b < 0) then data.b = 1 end
+ if data.a and (data.a > 1 or data.a < 0) then data.a = 1 end
+
+ if data.a then
+ return {data.r, data.g, data.b, data.a}
+ else
+ return {data.r, data.g, data.b}
+ end
+end
+
+function E:UpdateMedia()
+ if not self.db.general or not self.private.general then return end --Prevent rare nil value errors
+
+ -- Fonts
+ self.media.normFont = LSM:Fetch("font", self.db.general.font)
+ self.media.combatFont = LSM:Fetch("font", self.private.general.dmgfont)
+
+ -- Textures
+ self.media.blankTex = LSM:Fetch("background", "ElvUI Blank")
+ self.media.normTex = LSM:Fetch("statusbar", self.private.general.normTex)
+ self.media.glossTex = LSM:Fetch("statusbar", self.private.general.glossTex)
+
+ -- Border Color
+ local border = E.db.general.bordercolor
+ self.media.bordercolor = {border.r, border.g, border.b}
+
+ -- UnitFrame Border Color
+ border = E.db.unitframe.colors.borderColor
+ self.media.unitframeBorderColor = {border.r, border.g, border.b}
+
+ -- Backdrop Color
+ self.media.backdropcolor = E:SetColorTable(self.media.backdropcolor, self.db.general.backdropcolor)
+
+ -- Backdrop Fade Color
+ self.media.backdropfadecolor = E:SetColorTable(self.media.backdropfadecolor, self.db.general.backdropfadecolor)
+
+ -- Value Color
+ local value = self.db.general.valuecolor
+
+ self.media.hexvaluecolor = self:RGBToHex(value.r, value.g, value.b)
+ self.media.rgbvaluecolor = {value.r, value.g, value.b}
+
+ -- Hero Color
+ local herocolor = E.db.general.herocolor
+ self.media.herocolor = herocolor
+ self.oUF.herocolor = {herocolor.r, herocolor.g, herocolor. b}
+
+ if LeftChatPanel and LeftChatPanel.tex and RightChatPanel and RightChatPanel.tex then
+ LeftChatPanel.tex:SetTexture(E.db.chat.panelBackdropNameLeft)
+ local a = E.db.general.backdropfadecolor.a or 0.5
+ LeftChatPanel.tex:SetAlpha(a)
+
+ RightChatPanel.tex:SetTexture(E.db.chat.panelBackdropNameRight)
+ RightChatPanel.tex:SetAlpha(a)
+ end
+
+ self:ValueFuncCall()
+ self:UpdateBlizzardFonts()
+end
+
+do --Update font/texture paths when they are registered by the addon providing them
+ --This helps fix most of the issues with fonts or textures reverting to default because the addon providing them is loading after ElvUI.
+ --We use a wrapper to avoid errors in :UpdateMedia because "self" is passed to the function with a value other than ElvUI.
+ local function LSMCallback() E:UpdateMedia() end
+ LSM.RegisterCallback(E, "LibSharedMedia_Registered", LSMCallback)
+end
+
+function E:ValueFuncCall()
+ for func in pairs(self.valueColorUpdateFuncs) do
+ func(self.media.hexvaluecolor, unpack(self.media.rgbvaluecolor))
+ end
+end
+
+function E:UpdateFrameTemplates()
+ for frame in pairs(self.frames) do
+ if frame and frame.template and not frame.ignoreUpdates then
+ if not frame.ignoreFrameTemplates then
+ frame:SetTemplate(frame.template, frame.glossTex, nil, frame.forcePixelMode)
+ end
+ else
+ self.frames[frame] = nil
+ end
+ end
+
+ for frame in pairs(self.unitFrameElements) do
+ if frame and frame.template and not frame.ignoreUpdates then
+ if not frame.ignoreFrameTemplates then
+ frame:SetTemplate(frame.template, frame.glossTex, nil, frame.forcePixelMode, frame.isUnitFrameElement)
+ end
+ else
+ self.unitFrameElements[frame] = nil
+ end
+ end
+end
+
+function E:UpdateBorderColors()
+ for frame in pairs(self.frames) do
+ if frame and not frame.ignoreUpdates then
+ if not frame.ignoreBorderColors then
+ if frame.template == "Default" or frame.template == "Transparent" or frame.template == nil then
+ frame:SetBackdropBorderColor(unpack(self.media.bordercolor))
+ end
+ end
+ else
+ self.frames[frame] = nil
+ end
+ end
+
+ for frame in pairs(self.unitFrameElements) do
+ if frame and not frame.ignoreUpdates then
+ if not frame.ignoreBorderColors then
+ if frame.template == "Default" or frame.template == "Transparent" or frame.template == nil then
+ frame:SetBackdropBorderColor(unpack(self.media.unitframeBorderColor))
+ end
+ end
+ else
+ self.unitFrameElements[frame] = nil
+ end
+ end
+end
+
+function E:UpdateBackdropColors()
+ for frame in pairs(self.frames) do
+ if frame and not frame.ignoreUpdates then
+ if not frame.ignoreBackdropColors then
+ if frame.template == "Default" or frame.template == nil then
+ frame:SetBackdropColor(unpack(self.media.backdropcolor))
+ elseif frame.template == "Transparent" then
+ frame:SetBackdropColor(unpack(self.media.backdropfadecolor))
+ end
+ end
+ else
+ self.frames[frame] = nil
+ end
+ end
+
+ for frame in pairs(self.unitFrameElements) do
+ if frame and not frame.ignoreUpdates then
+ if not frame.ignoreBackdropColors then
+ if frame.template == "Default" or frame.template == nil then
+ frame:SetBackdropColor(unpack(self.media.backdropcolor))
+ elseif frame.template == "Transparent" then
+ frame:SetBackdropColor(unpack(self.media.backdropfadecolor))
+ end
+ end
+ else
+ self.unitFrameElements[frame] = nil
+ end
+ end
+end
+
+function E:UpdateFontTemplates()
+ for text in pairs(self.texts) do
+ if text then
+ text:FontTemplate(text.font, text.fontSize, text.fontStyle)
+ else
+ self.texts[text] = nil
+ end
+ end
+end
+
+function E:RegisterStatusBar(statusBar)
+ tinsert(self.statusBars, statusBar)
+end
+
+function E:UpdateStatusBars()
+ for _, statusBar in pairs(self.statusBars) do
+ if statusBar and statusBar:IsObjectType("StatusBar") then
+ statusBar:SetStatusBarTexture(self.media.normTex)
+ elseif statusBar and statusBar:IsObjectType("Texture") then
+ statusBar:SetTexture(self.media.normTex)
+ end
+ end
+end
+
+function E:IncompatibleAddOn(addon, module)
+ E.PopupDialogs.INCOMPATIBLE_ADDON.button1 = addon
+ E.PopupDialogs.INCOMPATIBLE_ADDON.button2 = "ElvUI "..module
+ E.PopupDialogs.INCOMPATIBLE_ADDON.addon = addon
+ E.PopupDialogs.INCOMPATIBLE_ADDON.module = module
+ E:StaticPopup_Show("INCOMPATIBLE_ADDON", addon, module)
+end
+
+function E:IsAddOnEnabled(addon)
+ local _, _, _, enabled, _, reason = GetAddOnInfo(addon)
+ if reason ~= "MISSING" and enabled then
+ return true
+ end
+end
+
+function E:CheckIncompatible()
+ if E.global.ignoreIncompatible then return end
+
+ if E.private.chat.enable then
+ if self:IsAddOnEnabled("Prat-3.0") then
+ self:IncompatibleAddOn("Prat-3.0", "Chat")
+ elseif self:IsAddOnEnabled("Chatter") then
+ self:IncompatibleAddOn("Chatter", "Chat")
+ end
+ end
+
+ if E.private.nameplates.enable then
+ if self:IsAddOnEnabled("Aloft") then
+ self:IncompatibleAddOn("Aloft", "NamePlates")
+ elseif self:IsAddOnEnabled("Healers-Have-To-Die") then
+ self:IncompatibleAddOn("Healers-Have-To-Die", "NamePlates")
+ elseif self:IsAddOnEnabled("TidyPlates") then
+ self:IncompatibleAddOn("TidyPlates", "NamePlates")
+ end
+ end
+
+ if E.private.tooltip.enable and self:IsAddOnEnabled("TipTac") then
+ self:IncompatibleAddOn("TipTac", "Tooltip")
+ end
+
+ if E.private.worldmap.enable and self:IsAddOnEnabled("Mapster") then
+ self:IncompatibleAddOn("Mapster", "WorldMap")
+ end
+end
+
+function E:CopyTable(currentTable, defaultTable)
+ if type(currentTable) ~= "table" then currentTable = {} end
+
+ if type(defaultTable) == "table" then
+ for option, value in pairs(defaultTable) do
+ if type(value) == "table" then
+ value = self:CopyTable(currentTable[option], value)
+ end
+
+ currentTable[option] = value
+ end
+ end
+
+ return currentTable
+end
+
+function E:RemoveEmptySubTables(tbl)
+ if type(tbl) ~= "table" then
+ E:Print("Bad argument #1 to 'RemoveEmptySubTables' (table expected)")
+ return
+ end
+
+ for k, v in pairs(tbl) do
+ if type(v) == "table" then
+ if next(v) == nil then
+ tbl[k] = nil
+ else
+ self:RemoveEmptySubTables(v)
+ end
+ end
+ end
+end
+
+--Compare 2 tables and remove duplicate key/value pairs
+--param cleanTable : table you want cleaned
+--param checkTable : table you want to check against.
+--return : a copy of cleanTable with duplicate key/value pairs removed
+function E:RemoveTableDuplicates(cleanTable, checkTable)
+ if type(cleanTable) ~= "table" then
+ E:Print("Bad argument #1 to 'RemoveTableDuplicates' (table expected)")
+ return
+ end
+ if type(checkTable) ~= "table" then
+ E:Print("Bad argument #2 to 'RemoveTableDuplicates' (table expected)")
+ return
+ end
+
+ local rtdCleaned = {}
+ for option, value in pairs(cleanTable) do
+ if type(value) == "table" and checkTable[option] and type(checkTable[option]) == "table" then
+ rtdCleaned[option] = self:RemoveTableDuplicates(value, checkTable[option])
+ else
+ -- Add unique data to our clean table
+ if cleanTable[option] ~= checkTable[option] then
+ rtdCleaned[option] = value
+ end
+ end
+ end
+
+ --Clean out empty sub-tables
+ self:RemoveEmptySubTables(rtdCleaned)
+
+ return rtdCleaned
+end
+
+--Compare 2 tables and remove blacklisted key/value pairs
+--param cleanTable : table you want cleaned
+--param blacklistTable : table you want to check against.
+--return : a copy of cleanTable with blacklisted key/value pairs removed
+function E:FilterTableFromBlacklist(cleanTable, blacklistTable)
+ if type(cleanTable) ~= "table" then
+ E:Print("Bad argument #1 to 'FilterTableFromBlacklist' (table expected)")
+ return
+ end
+ if type(blacklistTable) ~= "table" then
+ E:Print("Bad argument #2 to 'FilterTableFromBlacklist' (table expected)")
+ return
+ end
+
+ local tfbCleaned = {}
+ for option, value in pairs(cleanTable) do
+ if type(value) == "table" and blacklistTable[option] and type(blacklistTable[option]) == "table" then
+ tfbCleaned[option] = self:FilterTableFromBlacklist(value, blacklistTable[option])
+ else
+ -- Filter out blacklisted keys
+ if blacklistTable[option] ~= true then
+ tfbCleaned[option] = value
+ end
+ end
+ end
+
+ --Clean out empty sub-tables
+ self:RemoveEmptySubTables(tfbCleaned)
+
+ return tfbCleaned
+end
+
+do --The code in this function is from WeakAuras, credit goes to Mirrored and the WeakAuras Team
+ --Code slightly modified by Simpy
+ local function recurse(table, level, ret)
+ for i, v in pairs(table) do
+ ret = ret..strrep(" ", level).."["
+ if type(i) == "string" then ret = ret..'"'..i..'"' else ret = ret..i end
+ ret = ret.."] = "
+
+ if type(v) == "number" then
+ ret = ret..v..",\n"
+ elseif type(v) == "string" then
+ ret = ret.."\""..gsub(gsub(gsub(gsub(v, "\\", "\\\\"), "\n", "\\n"), "\"", "\\\""), "\124", "\124\124").."\",\n"
+ elseif type(v) == "boolean" then
+ if v then ret = ret.."true,\n" else ret = ret.."false,\n" end
+ elseif type(v) == "table" then
+ ret = ret.."{\n"
+ ret = recurse(v, level + 1, ret)
+ ret = ret..strrep(" ", level).."},\n"
+ else
+ ret = ret.."\""..tostring(v).."\",\n"
+ end
+ end
+
+ return ret
+ end
+
+ function E:TableToLuaString(inTable)
+ if type(inTable) ~= "table" then
+ E:Print("Invalid argument #1 to E:TableToLuaString (table expected)")
+ return
+ end
+
+ local ret = "{\n"
+ if inTable then ret = recurse(inTable, 1, ret) end
+ ret = ret.."}"
+
+ return ret
+ end
+end
+
+do --The code in this function is from WeakAuras, credit goes to Mirrored and the WeakAuras Team
+ --Code slightly modified by Simpy
+ local lineStructureTable, profileFormat = {}, {
+ profile = "E.db",
+ private = "E.private",
+ global = "E.global",
+ filters = "E.global",
+ styleFilters = "E.global"
+ }
+
+ local function buildLineStructure(str) -- str is profileText
+ for _, v in ipairs(lineStructureTable) do
+ if type(v) == "string" then
+ str = str..'["'..v..'"]'
+ else
+ str = str..'['..v..']'
+ end
+ end
+
+ return str
+ end
+
+ local sameLine
+ local function recurse(tbl, ret, profileText)
+ local lineStructure = buildLineStructure(profileText)
+ for k, v in pairs(tbl) do
+ if not sameLine then
+ ret = ret..lineStructure
+ end
+
+ ret = ret.."["
+
+ if type(k) == "string" then
+ ret = ret..'"'..k..'"'
+ else
+ ret = ret..k
+ end
+
+ if type(v) == "table" then
+ tinsert(lineStructureTable, k)
+ sameLine = true
+ ret = ret.."]"
+ ret = recurse(v, ret, profileText)
+ else
+ sameLine = false
+ ret = ret.."] = "
+
+ if type(v) == "number" then
+ ret = ret..v.."\n"
+ elseif type(v) == "string" then
+ ret = ret.."\""..gsub(gsub(gsub(gsub(v, "\\", "\\\\"), "\n", "\\n"), "\"", "\\\""), "\124", "\124\124").."\"\n"
+ elseif type(v) == "boolean" then
+ if v then
+ ret = ret.."true\n"
+ else
+ ret = ret.."false\n"
+ end
+ else
+ ret = ret.."\""..tostring(v).."\"\n"
+ end
+ end
+ end
+
+ tremove(lineStructureTable)
+
+ return ret
+ end
+
+ function E:ProfileTableToPluginFormat(inTable, profileType)
+ local profileText = profileFormat[profileType]
+ if not profileText then return end
+
+ twipe(lineStructureTable)
+ local ret = ""
+ if inTable and profileType then
+ sameLine = false
+ ret = recurse(inTable, ret, profileText)
+ end
+
+ return ret
+ end
+end
+
+do --Split string by multi-character delimiter (the strsplit / string.split function provided by WoW doesn't allow multi-character delimiter)
+ local splitTable = {}
+ function E:SplitString(str, delim)
+ assert(type (delim) == "string" and strlen(delim) > 0, "bad delimiter")
+
+ local start = 1
+ twipe(splitTable) -- results table
+
+ -- find each instance of a string followed by the delimiter
+ while true do
+ local pos = find(str, delim, start, true) -- plain find
+ if not pos then break end
+
+ tinsert(splitTable, sub(str, start, pos - 1))
+ start = pos + strlen(delim)
+ end -- while
+
+ -- insert final one (after last delimiter)
+ tinsert(splitTable, sub(str, start))
+
+ return unpack(splitTable)
+ end
+end
+
+do
+ local SendMessageWaiting
+ local SendRecieveGroupSize = 0
+
+ function E:SendMessage()
+ if GetNumRaidMembers() > 1 then
+ local _, instanceType = IsInInstance()
+ if instanceType == "pvp" then
+ SendAddonMessage("ELVUI_VERSIONCHK", E.version, "BATTLEGROUND")
+ else
+ SendAddonMessage("ELVUI_VERSIONCHK", E.version, "RAID")
+ end
+ elseif GetNumPartyMembers() > 0 then
+ SendAddonMessage("ELVUI_VERSIONCHK", E.version, "PARTY")
+ elseif IsInGuild() then
+ SendAddonMessage("ELVUI_VERSIONCHK", E.version, "GUILD")
+ end
+
+ SendMessageWaiting = nil
+ end
+
+ local function SendRecieve(_, event, prefix, message, _, sender)
+ if event == "CHAT_MSG_ADDON" then
+ if prefix ~= "ELVUI_VERSIONCHK" then return end
+ if not sender or sender == E.myname then return end
+
+ local ver = tonumber(E.version)
+ message = tonumber(message)
+
+ if ver ~= G.general.version then
+ if not E.shownUpdatedWhileRunningPopup and not InCombatLockdown() then
+ E:StaticPopup_Show("ELVUI_UPDATED_WHILE_RUNNING")
+
+ E.shownUpdatedWhileRunningPopup = true
+ end
+ elseif message and (message > ver) then
+ if not E.recievedOutOfDateMessage then
+ E:Print(L["ElvUI is out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"])
+
+ if message and ((message - ver) >= 0.01) and not InCombatLockdown() then
+ E:StaticPopup_Show("ELVUI_UPDATE_AVAILABLE")
+ end
+
+ E.recievedOutOfDateMessage = true
+ end
+ end
+ elseif event == "PARTY_MEMBERS_CHANGED" or event == "RAID_ROSTER_UPDATE" then
+ local numRaid = GetNumRaidMembers()
+ local num = numRaid > 0 and numRaid or (GetNumPartyMembers() + 1)
+ if num ~= SendRecieveGroupSize then
+ if num > 1 and num > SendRecieveGroupSize then
+ if not SendMessageWaiting then
+ SendMessageWaiting = E:Delay(10, E.SendMessage)
+ end
+ end
+ SendRecieveGroupSize = num
+ end
+ elseif event == "PLAYER_ENTERING_WORLD" then
+ if not SendMessageWaiting then
+ SendMessageWaiting = E:Delay(10, E.SendMessage)
+ end
+ end
+ end
+
+ local f = CreateFrame("Frame")
+ f:RegisterEvent("CHAT_MSG_ADDON")
+ f:RegisterEvent("RAID_ROSTER_UPDATE")
+ f:RegisterEvent("PARTY_MEMBERS_CHANGED")
+ f:RegisterEvent("PLAYER_ENTERING_WORLD")
+ f:SetScript("OnEvent", SendRecieve)
+end
+
+function E:UpdateAll(ignoreInstall)
+ E.private = E.charSettings.profile
+ E.db = E.data.profile
+ E.global = E.data.global
+ E.db.theme = nil
+ E.db.install_complete = nil
+
+ E:DBConversions()
+
+ ActionBars.db = E.db.actionbar
+ Auras.db = E.db.auras
+ Bags.db = E.db.bags
+ Chat.db = E.db.chat
+ DataBars.db = E.db.databars
+ DataTexts.db = E.db.datatexts
+ NamePlates.db = E.db.nameplates
+ Threat.db = E.db.general.threat
+ Tooltip.db = E.db.tooltip
+ Totems.db = E.db.general.totems
+ ReminderBuffs.db = E.db.general.reminder
+ UnitFrames.db = E.db.unitframe
+
+ --The mover is positioned before it is resized, which causes issues for unitframes
+ --Allow movers to be "pushed" outside the screen, when they are resized they should be back in the screen area.
+ --We set movers to be clamped again at the bottom of this function.
+ E:SetMoversClampedToScreen(false)
+ E:SetMoversPositions()
+
+ E:UpdateMedia()
+ E:UpdateBorderColors()
+ E:UpdateBackdropColors()
+ E:UpdateFrameTemplates()
+ E:UpdateStatusBars()
+ E:UpdateCooldownSettings("all")
+
+ Layout:ToggleChatPanels()
+ Layout:BottomPanelVisibility()
+ Layout:TopPanelVisibility()
+ Layout:SetDataPanelStyle()
+
+ if E.private.actionbar.enable then
+ ActionBars:ToggleDesaturation()
+ ActionBars:UpdateButtonSettings()
+ ActionBars:UpdateMicroPositionDimensions()
+ end
+
+ AFK:Toggle()
+
+ if E.private.bags.enable then
+ Bags:Layout()
+ Bags:Layout(true)
+ Bags:SizeAndPositionBagBar()
+ Bags:UpdateCountDisplay()
+ Bags:UpdateItemLevelDisplay()
+ end
+
+ if E.private.chat.enable then
+ Chat:PositionChat(true)
+ Chat:SetupChat()
+ Chat:UpdateAnchors()
+ end
+
+ DataBars:EnableDisable_ExperienceBar()
+ DataBars:EnableDisable_ReputationBar()
+ DataBars:UpdateDataBarDimensions()
+
+ DataTexts:LoadDataTexts()
+
+ if E.private.general.minimap.enable then
+ Minimap:UpdateSettings()
+ ReminderBuffs:UpdateSettings()
+ end
+
+ if E.private.nameplates.enable then
+ NamePlates:ConfigureAll()
+ NamePlates:StyleFilterInitialize()
+ end
+
+ Threat:ToggleEnable()
+ Threat:UpdatePosition()
+
+ Totems:ToggleEnable()
+ Totems:PositionAndSize()
+
+ if E.private.unitframe.enable then
+ UnitFrames:Update_AllFrames()
+ end
+
+ if ElvUIPlayerBuffs then
+ Auras:UpdateHeader(ElvUIPlayerBuffs)
+ end
+
+ if ElvUIPlayerDebuffs then
+ Auras:UpdateHeader(ElvUIPlayerDebuffs)
+ end
+
+ if E.RefreshGUI then
+ E:RefreshGUI()
+ end
+
+ if not ignoreInstall and not E.private.install_complete then
+ E:Install()
+ end
+
+ Blizzard:SetWatchFrameHeight()
+ E:SetMoversClampedToScreen(true) -- Go back to using clamp after resizing has taken place.
+end
+
+do
+ E.ObjectEventTable, E.ObjectEventFrame = {}, CreateFrame("Frame")
+ local eventFrame, eventTable = E.ObjectEventFrame, E.ObjectEventTable
+
+ eventFrame:SetScript("OnEvent", function(_, event, ...)
+ local objs = eventTable[event]
+ if objs then
+ for object, funcs in pairs(objs) do
+ for _, func in ipairs(funcs) do
+ func(object, event, ...)
+ end
+ end
+ end
+ end)
+
+ function E:HasFunctionForObject(event, object, func)
+ if not (event and object and func) then
+ E:Print("Error. Usage: HasFunctionForObject(event, object, func)")
+ return
+ end
+
+ local objs = eventTable[event]
+ local funcs = objs and objs[object]
+ return funcs and tContains(funcs, func)
+ end
+
+ function E:IsEventRegisteredForObject(event, object)
+ if not (event and object) then
+ E:Print("Error. Usage: IsEventRegisteredForObject(event, object)")
+ return
+ end
+
+ local objs = eventTable[event]
+ local funcs = objs and objs[object]
+ return funcs ~= nil, funcs
+ end
+
+ --- Registers specified event and adds specified func to be called for the specified object.
+ -- Unless all parameters are supplied it will not register.
+ -- If the specified object has already been registered for the specified event
+ -- then it will just add the specified func to a table of functions that should be called.
+ -- When a registered event is triggered, then the registered function is called with
+ -- the object as first parameter, then event, and then all the parameters for the event itself.
+ -- @param event The event you want to register.
+ -- @param object The object you want to register the event for.
+ -- @param func The function you want executed for this object.
+ function E:RegisterEventForObject(event, object, func)
+ if not (event and object and func) then
+ E:Print("Error. Usage: RegisterEventForObject(event, object, func)")
+ return
+ end
+
+ local objs = eventTable[event]
+ if not objs then
+ objs = {}
+ eventTable[event] = objs
+ eventFrame:RegisterEvent(event)
+ end
+
+ local funcs = objs[object]
+ if not funcs then
+ objs[object] = {func}
+ elseif not tContains(funcs, func) then
+ tinsert(funcs, func)
+ end
+ end
+
+ --- Unregisters specified function for the specified object on the specified event.
+ -- Unless all parameters are supplied it will not unregister.
+ -- @param event The event you want to unregister an object from.
+ -- @param object The object you want to unregister a func from.
+ -- @param func The function you want unregistered for the object.
+ function E:UnregisterEventForObject(event, object, func)
+ if not (event and object and func) then
+ E:Print("Error. Usage: UnregisterEventForObject(event, object, func)")
+ return
+ end
+
+ local objs = eventTable[event]
+ local funcs = objs and objs[object]
+ if funcs then
+ for index, fnc in ipairs(funcs) do
+ if func == fnc then
+ tremove(funcs, index)
+ break
+ end
+ end
+
+ if #funcs == 0 then
+ objs[object] = nil
+ end
+
+ if not next(funcs) then
+ eventFrame:UnregisterEvent(event)
+ eventTable[event] = nil
+ end
+ end
+ end
+end
+
+function E:ResetAllUI()
+ self:ResetMovers()
+
+ if E.db.layoutSet then
+ E:SetupLayout(E.db.layoutSet, true)
+ end
+end
+
+function E:ResetUI(...)
+ if InCombatLockdown() then E:Print(ERR_NOT_IN_COMBAT) return end
+
+ if ... == "" or ... == " " or ... == nil then
+ E:StaticPopup_Show("RESETUI_CHECK")
+ return
+ end
+
+ self:ResetMovers(...)
+end
+
+function E:CallLoadedModule(obj, silent, object, index)
+ local name, func
+ if type(obj) == "table" then name, func = unpack(obj) else name = obj end
+ local module = name and self:GetModule(name, silent)
+
+ if not module then return end
+ if func and type(func) == "string" then
+ E:RegisterCallback(name, module[func], module)
+ elseif func and type(func) == "function" then
+ E:RegisterCallback(name, func, module)
+ elseif module.Initialize then
+ E:RegisterCallback(name, module.Initialize, module)
+ end
+
+ E.callbacks:Fire(name)
+
+ if object and index then object[index] = nil end
+end
+
+function E:RegisterInitialModule(name, func)
+ self.RegisteredInitialModules[#self.RegisteredInitialModules + 1] = (func and {name, func}) or name
+end
+
+function E:RegisterModule(name, func)
+ if self.initialized then
+ E:CallLoadedModule((func and {name, func}) or name)
+ else
+ self.RegisteredModules[#self.RegisteredModules + 1] = (func and {name, func}) or name
+ end
+end
+
+function E:InitializeInitialModules()
+ for index, object in ipairs(E.RegisteredInitialModules) do
+ E:CallLoadedModule(object, true, E.RegisteredInitialModules, index)
+ end
+end
+
+function E:InitializeModules()
+ for index, object in ipairs(E.RegisteredModules) do
+ E:CallLoadedModule(object, true, E.RegisteredModules, index)
+ end
+end
+
+--DATABASE CONVERSIONS
+function E:DBConversions()
+ --Fix issue where UIScale was incorrectly stored as string
+ E.global.general.UIScale = tonumber(E.global.general.UIScale)
+
+ --Not sure how this one happens, but prevent it in any case
+ if E.global.general.UIScale <= 0 then
+ E.global.general.UIScale = G.general.UIScale
+ end
+
+ if gameLocale and E.global.general.locale == "auto" then
+ E.global.general.locale = gameLocale
+ end
+
+ --Combat & Resting Icon options update
+ if E.db.unitframe.units.player.combatIcon ~= nil then
+ E.db.unitframe.units.player.CombatIcon.enable = E.db.unitframe.units.player.combatIcon
+ E.db.unitframe.units.player.combatIcon = nil
+ end
+ if E.db.unitframe.units.player.restIcon ~= nil then
+ E.db.unitframe.units.player.RestIcon.enable = E.db.unitframe.units.player.restIcon
+ E.db.unitframe.units.player.restIcon = nil
+ end
+
+ -- [Fader] Combat Fade options for Player
+ if E.db.unitframe.units.player.combatfade ~= nil then
+ local enabled = E.db.unitframe.units.player.combatfade
+ E.db.unitframe.units.player.fader.enable = enabled
+
+ if enabled then -- use the old min alpha too
+ E.db.unitframe.units.player.fader.minAlpha = 0
+ end
+
+ E.db.unitframe.units.player.combatfade = nil
+ end
+
+ -- [Fader] Range check options for Units
+ do
+ local outsideAlpha
+ if E.db.unitframe.OORAlpha ~= nil then
+ outsideAlpha = E.db.unitframe.OORAlpha
+ E.db.unitframe.OORAlpha = nil
+ end
+
+ local rangeCheckUnits = {"target", "targettarget", "targettargettarget", "focus", "focustarget", "pet", "pettarget", "boss", "arena", "party", "raid", "raid40", "raidpet", "tank", "assist"}
+ for _, unit in pairs(rangeCheckUnits) do
+ if E.db.unitframe.units[unit].rangeCheck ~= nil then
+ local enabled = E.db.unitframe.units[unit].rangeCheck
+ E.db.unitframe.units[unit].fader.enable = enabled
+ E.db.unitframe.units[unit].fader.range = enabled
+
+ if outsideAlpha then
+ E.db.unitframe.units[unit].fader.minAlpha = outsideAlpha
+ end
+
+ E.db.unitframe.units[unit].rangeCheck = nil
+ end
+ end
+ end
+
+ --Convert old "Buffs and Debuffs" font size option to individual options
+ if E.db.auras.fontSize then
+ local fontSize = E.db.auras.fontSize
+ E.db.auras.buffs.countFontSize = fontSize
+ E.db.auras.buffs.durationFontSize = fontSize
+ E.db.auras.debuffs.countFontSize = fontSize
+ E.db.auras.debuffs.durationFontSize = fontSize
+ E.db.auras.fontSize = nil
+ end
+
+ --Convert old private cooldown setting to profile setting
+ if E.private.cooldown and (E.private.cooldown.enable ~= nil) then
+ E.db.cooldown.enable = E.private.cooldown.enable
+ E.private.cooldown.enable = nil
+ E.private.cooldown = nil
+ end
+
+ if not E.db.chat.panelColorConverted then
+ local color = E.db.general.backdropfadecolor
+ E.db.chat.panelColor = {r = color.r, g = color.g, b = color.b, a = color.a}
+ E.db.chat.panelColorConverted = true
+ end
+
+ --Convert cropIcon to tristate
+ local cropIcon = E.db.general.cropIcon
+ if type(cropIcon) == "boolean" then
+ E.db.general.cropIcon = (cropIcon and 2) or 0
+ end
+
+ --Vendor Greys option is now in bags table
+ if E.db.general.vendorGrays then
+ E.db.bags.vendorGrays.enable = E.db.general.vendorGrays
+ E.db.general.vendorGrays = nil
+ E.db.general.vendorGraysDetails = nil
+ end
+
+ --Heal Prediction is now a table instead of a bool
+ local healPredictionUnits = {"player", "target", "focus", "pet", "arena", "party", "raid", "raid40", "raidpet"}
+ for _, unit in pairs(healPredictionUnits) do
+ if type(E.db.unitframe.units[unit].healPrediction) ~= "table" then
+ local enabled = E.db.unitframe.units[unit].healPrediction
+ E.db.unitframe.units[unit].healPrediction = {}
+ E.db.unitframe.units[unit].healPrediction.enable = enabled
+ end
+ end
+
+ --Health Backdrop Multiplier
+ if E.db.unitframe.colors.healthmultiplier ~= nil then
+ if E.db.unitframe.colors.healthmultiplier > 0.75 then
+ E.db.unitframe.colors.healthMultiplier = 0.75
+ else
+ E.db.unitframe.colors.healthMultiplier = E.db.unitframe.colors.healthmultiplier
+ end
+
+ E.db.unitframe.colors.healthmultiplier = nil
+ end
+
+ if sub(E.db.chat.timeStampFormat, -1) == " " then
+ E.db.chat.timeStampFormat = sub(E.db.chat.timeStampFormat, 1, -2)
+ end
+
+ if E.private.skins.blizzard.greeting ~= nil then
+ E.private.skins.blizzard.greeting = nil
+ end
+end
+
+function E:RefreshModulesDB()
+ -- this function is specifically used to reference the new database
+ -- onto the unitframe module, its useful dont delete! D:
+ twipe(UnitFrames.db) --old ref, dont need so clear it
+ UnitFrames.db = self.db.unitframe --new ref
+end
+
+function E:Initialize()
+ twipe(self.db)
+ twipe(self.global)
+ twipe(self.private)
+
+ self.myguid = UnitGUID("player")
+ self.data = E.Libs.AceDB:New("ElvDB", self.DF)
+ self.data.RegisterCallback(self, "OnProfileChanged", "UpdateAll")
+ self.data.RegisterCallback(self, "OnProfileCopied", "UpdateAll")
+ self.data._ResetProfile = self.data.ResetProfile
+ self.data.ResetProfile = self.OnProfileReset
+ self.charSettings = E.Libs.AceDB:New("ElvPrivateDB", self.privateVars)
+ E.Libs.DualSpec:EnhanceDatabase(self.data, "ElvUI")
+ self.private = self.charSettings.profile
+ self.db = self.data.profile
+ self.global = self.data.global
+
+ self:CheckIncompatible()
+ self:DBConversions()
+ self:UIScale()
+ self:BuildPrefixValues()
+ self:LoadAPI()
+ self:LoadCommands()
+ self:InitializeModules()
+ self:RefreshModulesDB()
+ self:LoadMovers()
+ self:UpdateMedia()
+ self:UpdateCooldownSettings("all")
+ self:Tutorials()
+ self.initialized = true
+
+ Minimap:UpdateSettings()
+
+ if E.db.general.smoothingAmount and (E.db.general.smoothingAmount ~= 0.33) then
+ E:SetSmoothingAmount(E.db.general.smoothingAmount)
+ end
+
+ if not self.private.install_complete then
+ self:Install()
+ end
+
+ if self:HelloKittyFixCheck() then
+ self:HelloKittyFix()
+ end
+
+ if self.db.general.kittys then
+ self:CreateKittys()
+ self:Delay(5, self.Print, self, L["Type /hellokitty to revert to old settings."])
+ end
+
+ if self.db.general.loginmessage then
+ local msg = format(L["LOGIN_MSG"], self.media.hexvaluecolor, self.media.hexvaluecolor, self.version)
+ if Chat.Initialized then msg = select(2, Chat:FindURL("CHAT_MSG_DUMMY", msg)) end
+ print(msg)
+ end
+
+ if GetCVar("scriptProfile") ~= "1" then
+ collectgarbage("collect")
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Core/Distributor.lua b/ElvUI/Core/Distributor.lua
new file mode 100644
index 0000000..da185dd
--- /dev/null
+++ b/ElvUI/Core/Distributor.lua
@@ -0,0 +1,602 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local D = E:GetModule("Distributor")
+local LibCompress = E.Libs.Compress
+local LibBase64 = E.Libs.Base64
+
+--Lua functions
+local loadstring = loadstring
+local pcall = pcall
+local setfenv = setfenv
+local tonumber = tonumber
+local type = type
+local format, gsub, len, split, sub = string.format, string.gsub, string.len, string.split, string.sub
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetNumRaidMembers, UnitInRaid = GetNumRaidMembers, UnitInRaid
+local GetNumPartyMembers, UnitInParty = GetNumPartyMembers, UnitInParty
+local ACCEPT, CANCEL, YES, NO = ACCEPT, CANCEL, YES, NO
+
+----------------------------------
+-- CONSTANTS
+----------------------------------
+
+local REQUEST_PREFIX = "ELVUI_REQUEST"
+local REPLY_PREFIX = "ELVUI_REPLY"
+local TRANSFER_PREFIX = "ELVUI_TRANSFER"
+local TRANSFER_COMPLETE_PREFIX = "ELVUI_COMPLETE"
+
+local ACECOMMPREFIXES = {
+ [TRANSFER_PREFIX.."\001"] = true,
+ [TRANSFER_PREFIX.."\002"] = true,
+ [TRANSFER_PREFIX.."\003"] = true,
+}
+
+-- The active downloads
+local Downloads = {}
+local Uploads = {}
+
+function D:Initialize()
+ self.Initialized = true
+ self:RegisterComm(REQUEST_PREFIX)
+ self:RegisterEvent("CHAT_MSG_ADDON")
+
+ self.statusBar = CreateFrame("StatusBar", "ElvUI_Download", E.UIParent)
+ E:RegisterStatusBar(self.statusBar)
+ self.statusBar:CreateBackdrop("Default")
+ self.statusBar:SetStatusBarTexture(E.media.normTex)
+ self.statusBar:SetStatusBarColor(0.95, 0.15, 0.15)
+ self.statusBar:Size(250, 18)
+ self.statusBar.text = self.statusBar:CreateFontString(nil, "OVERLAY")
+ self.statusBar.text:FontTemplate()
+ self.statusBar.text:Point("CENTER")
+ self.statusBar:Hide()
+end
+
+-- Used to start uploads
+function D:Distribute(target, otherServer, isGlobal)
+ local profileKey, data
+ if not isGlobal then
+ if ElvDB.profileKeys then
+ profileKey = ElvDB.profileKeys[E.myname.." - "..E.myrealm]
+ end
+
+ data = ElvDB.profiles[profileKey]
+ else
+ profileKey = "global"
+ data = ElvDB.global
+ end
+
+ if not data or not profileKey then return end
+
+ data = E:RemoveTableDuplicates(data, isGlobal and G or P)
+
+ local serialData = self:Serialize(data)
+ local length = len(serialData)
+ local message = format("%s:%d:%s", profileKey, length, target)
+
+ Uploads[profileKey] = {
+ serialData = serialData,
+ target = target,
+ }
+
+ if otherServer then
+ local numParty, numRaid = GetNumPartyMembers(), GetNumRaidMembers()
+ if numRaid > 0 and UnitInRaid("target") then
+ self:SendCommMessage(REQUEST_PREFIX, message, "RAID")
+ elseif numParty > 0 and UnitInParty("target") then
+ self:SendCommMessage(REQUEST_PREFIX, message, "PARTY")
+ else
+ E:Print(L["Must be in group with the player if he isn't on the same server as you."])
+ return
+ end
+ else
+ self:SendCommMessage(REQUEST_PREFIX, message, "WHISPER", target)
+ end
+ self:RegisterComm(REPLY_PREFIX)
+ E:StaticPopup_Show("DISTRIBUTOR_WAITING")
+end
+
+function D:CHAT_MSG_ADDON(_, prefix, message, _, sender)
+ if not ACECOMMPREFIXES[prefix] or not Downloads[sender] then return end
+
+ local cur = len(message)
+ local max = Downloads[sender].length
+ Downloads[sender].current = Downloads[sender].current + cur
+
+ if Downloads[sender].current > max then
+ Downloads[sender].current = max
+ end
+
+ self.statusBar:SetValue(Downloads[sender].current)
+end
+
+function D:UpdateSendProgress(sentBytes, totalBytes)
+ self.statusBar:SetValue(sentBytes)
+
+ if sentBytes == totalBytes then
+ E:StaticPopupSpecial_Hide(self.statusBar)
+ end
+end
+
+function D:OnCommReceived(prefix, msg, dist, sender)
+ if prefix == REQUEST_PREFIX then
+ local profile, length, sendTo = split(":", msg)
+
+ if dist ~= "WHISPER" and sendTo ~= E.myname then
+ return
+ end
+
+ if self.statusBar:IsShown() then
+ self:SendCommMessage(REPLY_PREFIX, profile..":NO", dist, sender)
+ return
+ end
+
+ local textString = format(L["%s is attempting to share the profile %s with you. Would you like to accept the request?"], sender, profile)
+ if profile == "global" then
+ textString = format(L["%s is attempting to share his filters with you. Would you like to accept the request?"], sender)
+ end
+
+ E.PopupDialogs.DISTRIBUTOR_RESPONSE = {
+ text = textString,
+ OnAccept = function()
+ self.statusBar:SetMinMaxValues(0, length)
+ self.statusBar:SetValue(0)
+ self.statusBar.text:SetFormattedText(L["Data From: %s"], sender)
+ E:StaticPopupSpecial_Show(self.statusBar)
+ self:SendCommMessage(REPLY_PREFIX, profile..":YES", dist, sender)
+ end,
+ OnCancel = function()
+ self:SendCommMessage(REPLY_PREFIX, profile..":NO", dist, sender)
+ end,
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ timeout = 32,
+ whileDead = 1,
+ hideOnEscape = 1
+ }
+ E:StaticPopup_Show("DISTRIBUTOR_RESPONSE")
+
+ Downloads[sender] = {
+ current = 0,
+ length = tonumber(length),
+ profile = profile
+ }
+
+ self:RegisterComm(TRANSFER_PREFIX)
+ elseif prefix == REPLY_PREFIX then
+ self:UnregisterComm(REPLY_PREFIX)
+ E:StaticPopup_Hide("DISTRIBUTOR_WAITING")
+
+ local profileKey, response = split(":", msg)
+ if response == "YES" then
+ self.statusBar:SetMinMaxValues(0, len(Uploads[profileKey].serialData))
+ self.statusBar:SetValue(0)
+ self.statusBar.text:SetFormattedText(L["Data To: %s"], sender)
+ E:StaticPopupSpecial_Show(self.statusBar)
+
+ self:RegisterComm(TRANSFER_COMPLETE_PREFIX)
+ self:SendCommMessage(TRANSFER_PREFIX, Uploads[profileKey].serialData, dist, Uploads[profileKey].target, "BULK", self.UpdateSendProgress, self)
+ Uploads[profileKey] = nil
+ else
+ E:StaticPopup_Show("DISTRIBUTOR_REQUEST_DENIED")
+ Uploads[profileKey] = nil
+ end
+ elseif prefix == TRANSFER_PREFIX then
+ self:UnregisterComm(TRANSFER_PREFIX)
+ E:StaticPopupSpecial_Hide(self.statusBar)
+
+ local profileKey = Downloads[sender].profile
+ local success, data = self:Deserialize(msg)
+
+ if success then
+ local textString = format(L["Profile download complete from %s, would you like to load the profile %s now?"], sender, profileKey)
+
+ if profileKey == "global" then
+ textString = format(L["Filter download complete from %s, would you like to apply changes now?"], sender)
+ else
+ if not ElvDB.profiles[profileKey] then
+ ElvDB.profiles[profileKey] = data
+ else
+ textString = format(L["Profile download complete from %s, but the profile %s already exists. Change the name or else it will overwrite the existing profile."], sender, profileKey)
+ E.PopupDialogs.DISTRIBUTOR_CONFIRM = {
+ text = textString,
+ button1 = ACCEPT,
+ hasEditBox = 1,
+ editBoxWidth = 350,
+ maxLetters = 127,
+ OnAccept = function(popup)
+ ElvDB.profiles[popup.editBox:GetText()] = data
+ E.Libs.AceAddon:GetAddon("ElvUI").data:SetProfile(popup.editBox:GetText())
+ E:UpdateAll(true)
+ Downloads[sender] = nil
+ E:StaticPopup_Show("CONFIG_RL")
+ end,
+ OnShow = function(popup) popup.editBox:SetText(profileKey) popup.editBox:SetFocus() end,
+ timeout = 0,
+ exclusive = 1,
+ whileDead = 1,
+ hideOnEscape = 1,
+ preferredIndex = 3
+ }
+
+ E:StaticPopup_Show("DISTRIBUTOR_CONFIRM")
+ self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, "COMPLETE", dist, sender)
+ return
+ end
+ end
+
+ E.PopupDialogs.DISTRIBUTOR_CONFIRM = {
+ text = textString,
+ OnAccept = function()
+ if profileKey == "global" then
+ E:CopyTable(ElvDB.global, data)
+ E:UpdateAll(true)
+ else
+ E.Libs.AceAddon:GetAddon("ElvUI").data:SetProfile(profileKey)
+ end
+ Downloads[sender] = nil
+ end,
+ OnCancel = function()
+ Downloads[sender] = nil
+ end,
+ button1 = YES,
+ button2 = NO,
+ whileDead = 1,
+ hideOnEscape = 1
+ }
+
+ E:StaticPopup_Show("DISTRIBUTOR_CONFIRM")
+ self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, "COMPLETE", dist, sender)
+ else
+ E:StaticPopup_Show("DISTRIBUTOR_FAILED")
+ self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, "FAILED", dist, sender)
+ end
+ elseif prefix == TRANSFER_COMPLETE_PREFIX then
+ self:UnregisterComm(TRANSFER_COMPLETE_PREFIX)
+ if msg == "COMPLETE" then
+ E:StaticPopup_Show("DISTRIBUTOR_SUCCESS")
+ else
+ E:StaticPopup_Show("DISTRIBUTOR_FAILED")
+ end
+ end
+end
+
+--Keys that should not be exported
+local blacklistedKeys = {
+ profile = {
+ general = {
+ numberPrefixStyle = true,
+ }
+ },
+ private = {},
+ global = {
+ general = {
+ UIScale = true,
+ locale = true,
+ eyefinity = true,
+ ignoreScalePopup = true
+ },
+ chat = {
+ classColorMentionExcludedNames = true
+ },
+ unitframe = {
+ spellRangeCheck = true
+ }
+ }
+}
+
+local function GetProfileData(profileType)
+ if not profileType or type(profileType) ~= "string" then
+ E:Print("Bad argument #1 to 'GetProfileData' (string expected)")
+ return
+ end
+
+ local profileKey
+ local profileData = {}
+
+ if profileType == "profile" then
+ if ElvDB.profileKeys then
+ profileKey = ElvDB.profileKeys[E.myname.." - "..E.myrealm]
+ end
+
+ --Copy current profile data
+ profileData = E:CopyTable(profileData, ElvDB.profiles[profileKey])
+ --This table will also hold all default values, not just the changed settings.
+ --This makes the table huge, and will cause the WoW client to lock up for several seconds.
+ --We compare against the default table and remove all duplicates from our table. The table is now much smaller.
+ profileData = E:RemoveTableDuplicates(profileData, P)
+ profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.profile)
+ elseif profileType == "private" then
+ local privateProfileKey = E.myname.." - "..E.myrealm
+ profileKey = "private"
+
+ profileData = E:CopyTable(profileData, ElvPrivateDB.profiles[privateProfileKey])
+ profileData = E:RemoveTableDuplicates(profileData, V)
+ profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.private)
+ elseif profileType == "global" then
+ profileKey = "global"
+
+ profileData = E:CopyTable(profileData, ElvDB.global)
+ profileData = E:RemoveTableDuplicates(profileData, G)
+ profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.global)
+ elseif profileType == "filters" then
+ profileKey = "filters"
+
+ profileData.unitframe = {}
+ profileData.unitframe.aurafilters = {}
+ profileData.unitframe.aurafilters = E:CopyTable(profileData.unitframe.aurafilters, ElvDB.global.unitframe.aurafilters)
+ profileData.unitframe.buffwatch = {}
+ profileData.unitframe.buffwatch = E:CopyTable(profileData.unitframe.buffwatch, ElvDB.global.unitframe.buffwatch)
+ profileData = E:RemoveTableDuplicates(profileData, G)
+ elseif profileType == "styleFilters" then
+ profileKey = "styleFilters"
+
+ profileData.nameplates = {}
+ profileData.nameplates.filters = {}
+ profileData.nameplates.filters = E:CopyTable(profileData.nameplates.filters, ElvDB.global.nameplates.filters)
+ profileData = E:RemoveTableDuplicates(profileData, G)
+ end
+
+ return profileKey, profileData
+end
+
+local function GetProfileExport(profileType, exportFormat)
+ local profileExport, exportString
+ local profileKey, profileData = GetProfileData(profileType)
+
+ if not profileKey or not profileData or (profileData and type(profileData) ~= "table") then
+ E:Print("Error getting data from 'GetProfileData'")
+ return
+ end
+
+ if exportFormat == "text" then
+ local serialData = D:Serialize(profileData)
+ exportString = D:CreateProfileExport(serialData, profileType, profileKey)
+ local compressedData = LibCompress:Compress(exportString)
+ local encodedData = LibBase64:Encode(compressedData)
+ profileExport = encodedData
+ elseif exportFormat == "luaTable" then
+ exportString = E:TableToLuaString(profileData)
+ profileExport = D:CreateProfileExport(exportString, profileType, profileKey)
+ elseif exportFormat == "luaPlugin" then
+ profileExport = E:ProfileTableToPluginFormat(profileData, profileType)
+ end
+
+ return profileKey, profileExport
+end
+
+function D:CreateProfileExport(dataString, profileType, profileKey)
+ local returnString
+
+ if profileType == "profile" then
+ returnString = format("%s::%s::%s", dataString, profileType, profileKey)
+ else
+ returnString = format("%s::%s", dataString, profileType)
+ end
+
+ return returnString
+end
+
+function D:GetImportStringType(dataString)
+ local stringType = ""
+
+ if LibBase64:IsBase64(dataString) then
+ stringType = "Base64"
+ elseif sub(dataString, 1, 1) == "{" then --Basic check to weed out obviously wrong strings
+ stringType = "Table"
+ end
+
+ return stringType
+end
+
+function D:Decode(dataString)
+ local profileInfo, profileType, profileKey, profileData
+ local stringType = self:GetImportStringType(dataString)
+
+ if stringType == "Base64" then
+ local decodedData = LibBase64:Decode(dataString)
+ local decompressedData, decompressedMessage = LibCompress:Decompress(decodedData)
+
+ if not decompressedData then
+ E:Print("Error decompressing data:", decompressedMessage)
+ return
+ end
+
+ local serializedData, success
+ serializedData, profileInfo = E:SplitString(decompressedData, "^^::") -- "^^" indicates the end of the AceSerializer string
+
+ if not profileInfo then
+ E:Print("Error importing profile. String is invalid or corrupted!")
+ return
+ end
+
+ serializedData = format("%s%s", serializedData, "^^") --Add back the AceSerializer terminator
+ profileType, profileKey = E:SplitString(profileInfo, "::")
+ success, profileData = D:Deserialize(serializedData)
+
+ if not success then
+ E:Print("Error deserializing:", profileData)
+ return
+ end
+ elseif stringType == "Table" then
+ local profileDataAsString
+ profileDataAsString, profileInfo = E:SplitString(dataString, "}::") -- "}::" indicates the end of the table
+
+ if not profileInfo then
+ E:Print("Error extracting profile info. Invalid import string!")
+ return
+ end
+
+ if not profileDataAsString then
+ E:Print("Error extracting profile data. Invalid import string!")
+ return
+ end
+
+ profileDataAsString = format("%s%s", profileDataAsString, "}") --Add back the missing "}"
+ profileDataAsString = gsub(profileDataAsString, "\124\124", "\124") --Remove escape pipe characters
+ profileType, profileKey = E:SplitString(profileInfo, "::")
+
+ local func, err = loadstring(format("%s %s", "return", profileDataAsString))
+
+ if func then
+ setfenv(func, {}) -- execute code in an empty environment
+ local success, res = pcall(func)
+
+ if success then
+ profileData = res
+ else
+ err = res
+ end
+ end
+
+ if err then
+ E:Print("Error converting lua string to table:", err)
+ return
+ end
+ end
+
+ return profileType, profileKey, profileData
+end
+
+local function SetImportedProfile(profileType, profileKey, profileData, force)
+ D.profileType = nil
+ D.profileKey = nil
+ D.profileData = nil
+
+ if profileType == "profile" then
+ profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.profile) --Remove unwanted options from import
+ if not ElvDB.profiles[profileKey] or force then
+ if force and E.data.keys.profile == profileKey then
+ --Overwriting an active profile doesn't update when calling SetProfile
+ --So make it look like we use a different profile
+ local tempKey = profileKey.."_Temp"
+ E.data.keys.profile = tempKey
+ end
+ ElvDB.profiles[profileKey] = profileData
+ --Calling SetProfile will now update all settings correctly
+ E.data:SetProfile(profileKey)
+ else
+ D.profileType = profileType
+ D.profileKey = profileKey
+ D.profileData = profileData
+ E:StaticPopup_Show("IMPORT_PROFILE_EXISTS")
+
+ return
+ end
+ elseif profileType == "private" then
+ profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.private) --Remove unwanted options from import
+ local pfKey = ElvPrivateDB.profileKeys[E.myname.." - "..E.myrealm]
+ ElvPrivateDB.profiles[pfKey] = profileData
+ E:StaticPopup_Show("IMPORT_RL")
+ elseif profileType == "global" then
+ profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.global) --Remove unwanted options from import
+ E:CopyTable(ElvDB.global, profileData)
+ E:StaticPopup_Show("IMPORT_RL")
+ elseif profileType == "filters" then
+ E:CopyTable(ElvDB.global.unitframe, profileData.unitframe)
+ elseif profileType == "styleFilters" then
+ E:CopyTable(ElvDB.global.nameplates, profileData.nameplates)
+ end
+
+ --Update all ElvUI modules
+ E:UpdateAll(true)
+end
+
+function D:ExportProfile(profileType, exportFormat)
+ if not profileType or not exportFormat then
+ E:Print("Bad argument to 'ExportProfile' (string expected)")
+ return
+ end
+
+ local profileKey, profileExport = GetProfileExport(profileType, exportFormat)
+
+ return profileKey, profileExport
+end
+
+function D:ImportProfile(dataString)
+ local profileType, profileKey, profileData = self:Decode(dataString)
+
+ if not profileData or type(profileData) ~= "table" then
+ E:Print("Error: something went wrong when converting string to table!")
+ return
+ end
+
+ if profileType and ((profileType == "profile" and profileKey) or profileType ~= "profile") then
+ SetImportedProfile(profileType, profileKey, profileData)
+ end
+
+ return true
+end
+
+E.PopupDialogs.DISTRIBUTOR_SUCCESS = {
+ text = L["Your profile was successfully recieved by the player."],
+ whileDead = 1,
+ hideOnEscape = 1,
+ button1 = OKAY
+}
+
+E.PopupDialogs.DISTRIBUTOR_WAITING = {
+ text = L["Profile request sent. Waiting for response from player."],
+ whileDead = 1,
+ hideOnEscape = 1,
+ timeout = 35
+}
+
+E.PopupDialogs.DISTRIBUTOR_REQUEST_DENIED = {
+ text = L["Request was denied by user."],
+ whileDead = 1,
+ hideOnEscape = 1,
+ button1 = OKAY
+}
+
+E.PopupDialogs.DISTRIBUTOR_FAILED = {
+ text = L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"],
+ whileDead = 1,
+ hideOnEscape = 1,
+ button1 = OKAY
+}
+
+E.PopupDialogs.DISTRIBUTOR_RESPONSE = {}
+E.PopupDialogs.DISTRIBUTOR_CONFIRM = {}
+
+E.PopupDialogs.IMPORT_PROFILE_EXISTS = {
+ text = L["The profile you tried to import already exists. Choose a new name or accept to overwrite the existing profile."],
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ hasEditBox = 1,
+ editBoxWidth = 350,
+ maxLetters = 127,
+ OnAccept = function(self)
+ local profileType = D.profileType
+ local profileKey = self.editBox:GetText()
+ local profileData = D.profileData
+ SetImportedProfile(profileType, profileKey, profileData, true)
+ end,
+ EditBoxOnTextChanged = function(self)
+ if self:GetText() == "" then
+ self:GetParent().button1:Disable()
+ else
+ self:GetParent().button1:Enable()
+ end
+ end,
+ OnShow = function(self) self.editBox:SetText(D.profileKey) self.editBox:SetFocus() end,
+ whileDead = 1,
+ hideOnEscape = true,
+ preferredIndex = 3
+}
+
+E.PopupDialogs.IMPORT_RL = {
+ text = L["You have imported settings which may require a UI reload to take effect. Reload now?"],
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = ReloadUI,
+ whileDead = 1,
+ hideOnEscape = false,
+ preferredIndex = 3
+}
+
+local function InitializeCallback()
+ D:Initialize()
+end
+
+E:RegisterModule(D:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Core/Dropdown.lua b/ElvUI/Core/Dropdown.lua
new file mode 100644
index 0000000..ded9a9d
--- /dev/null
+++ b/ElvUI/Core/Dropdown.lua
@@ -0,0 +1,88 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+--Lua functions
+local tinsert = tinsert
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local ToggleFrame = ToggleFrame
+local GetCursorPosition = GetCursorPosition
+
+local PADDING = 10
+local BUTTON_HEIGHT = 16
+local BUTTON_WIDTH = 135
+
+local function OnClick(btn)
+ btn.func()
+
+ btn:GetParent():Hide()
+end
+
+local function OnEnter(btn)
+ btn.hoverTex:Show()
+end
+
+local function OnLeave(btn)
+ btn.hoverTex:Hide()
+end
+
+function E:DropDown(list, frame, xOffset, yOffset)
+ if not frame.buttons then
+ frame.buttons = {}
+ frame:SetFrameStrata("DIALOG")
+ frame:SetClampedToScreen(true)
+ tinsert(UISpecialFrames, frame:GetName())
+ frame:Hide()
+ end
+
+ xOffset = xOffset or 0
+ yOffset = yOffset or 0
+
+ for i = 1, #frame.buttons do
+ frame.buttons[i]:Hide()
+ end
+
+ for i = 1, #list do
+ if not frame.buttons[i] then
+ frame.buttons[i] = CreateFrame("Button", nil, frame)
+
+ frame.buttons[i].hoverTex = frame.buttons[i]:CreateTexture(nil, "OVERLAY")
+ frame.buttons[i].hoverTex:SetAllPoints()
+ frame.buttons[i].hoverTex:SetTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]])
+ frame.buttons[i].hoverTex:SetBlendMode("ADD")
+ frame.buttons[i].hoverTex:Hide()
+
+ frame.buttons[i].text = frame.buttons[i]:CreateFontString(nil, "BORDER")
+ frame.buttons[i].text:SetAllPoints()
+ frame.buttons[i].text:FontTemplate()
+ frame.buttons[i].text:SetJustifyH("LEFT")
+
+ frame.buttons[i]:SetScript("OnEnter", OnEnter)
+ frame.buttons[i]:SetScript("OnLeave", OnLeave)
+ end
+
+ frame.buttons[i]:Show()
+ frame.buttons[i]:Height(BUTTON_HEIGHT)
+ frame.buttons[i]:Width(BUTTON_WIDTH)
+ frame.buttons[i].text:SetText(list[i].text)
+ frame.buttons[i].func = list[i].func
+ frame.buttons[i]:SetScript("OnClick", OnClick)
+
+ if i == 1 then
+ frame.buttons[i]:Point("TOPLEFT", frame, "TOPLEFT", PADDING, -PADDING)
+ else
+ frame.buttons[i]:Point("TOPLEFT", frame.buttons[i-1], "BOTTOMLEFT")
+ end
+ end
+
+ frame:Height((#list * BUTTON_HEIGHT) + PADDING * 2)
+ frame:Width(BUTTON_WIDTH + PADDING * 2)
+
+ local UIScale = UIParent:GetScale()
+ local x, y = GetCursorPosition()
+ x = x/UIScale
+ y = y/UIScale
+ frame:ClearAllPoints()
+ frame:Point("TOPLEFT", UIParent, "BOTTOMLEFT", x + xOffset, y + yOffset)
+
+ ToggleFrame(frame)
+end
\ No newline at end of file
diff --git a/ElvUI/Core/Fonts.lua b/ElvUI/Core/Fonts.lua
new file mode 100644
index 0000000..942460f
--- /dev/null
+++ b/ElvUI/Core/Fonts.lua
@@ -0,0 +1,99 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local LSM = E.Libs.LSM
+
+--Lua functions
+--WoW API / Variables
+local SetCVar = SetCVar
+
+local function SetFont(obj, font, size, style, sr, sg, sb, sa, sox, soy, r, g, b)
+ if not obj then return end
+
+ obj:SetFont(font, size, style)
+ if sr and sg and sb then obj:SetShadowColor(sr, sg, sb, sa) end
+ if sox and soy then obj:SetShadowOffset(sox, soy) end
+ if r and g and b then obj:SetTextColor(r, g, b)
+ elseif r then obj:SetAlpha(r) end
+end
+
+function E:UpdateBlizzardFonts()
+ local NORMAL = self.media.normFont
+ local NUMBER = self.media.normFont
+ local COMBAT = LSM:Fetch("font", self.private.general.dmgfont)
+ local NAMEFONT = LSM:Fetch("font", self.private.general.namefont)
+ local MONOCHROME = ""
+
+ UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT = 12
+ CHAT_FONT_HEIGHTS = {6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+
+ if self.db.general.font == "Homespun" then
+ MONOCHROME = "MONOCHROME"
+ end
+
+ if self.eyefinity then
+ InterfaceOptionsCombatTextPanelTargetDamage:Hide()
+ InterfaceOptionsCombatTextPanelPeriodicDamage:Hide()
+ InterfaceOptionsCombatTextPanelPetDamage:Hide()
+ InterfaceOptionsCombatTextPanelHealing:Hide()
+ SetCVar("CombatLogPeriodicSpells", 0)
+ SetCVar("PetMeleeDamage", 0)
+ SetCVar("CombatDamage", 0)
+ SetCVar("CombatHealing", 0)
+
+ -- set an invisible font for xp, honor kill, etc
+ COMBAT = E.Media.Fonts.Invisible
+ end
+
+ UNIT_NAME_FONT = NAMEFONT
+ NAMEPLATE_FONT = NAMEFONT
+ DAMAGE_TEXT_FONT = COMBAT
+ STANDARD_TEXT_FONT = NORMAL
+
+ if self.private.general.replaceBlizzFonts then
+ SetFont(GameTooltipHeader, NORMAL, self.db.general.fontSize)
+ SetFont(NumberFont_OutlineThick_Mono_Small, NUMBER, self.db.general.fontSize, "OUTLINE")
+ SetFont(NumberFont_Outline_Huge, NUMBER, 28, MONOCHROME.."THICKOUTLINE", 28)
+ SetFont(NumberFont_Outline_Large, NUMBER, 15, MONOCHROME.."OUTLINE")
+ SetFont(NumberFont_Outline_Med, NUMBER, self.db.general.fontSize, "OUTLINE")
+ SetFont(NumberFont_Shadow_Med, NORMAL, self.db.general.fontSize)
+ SetFont(NumberFont_Shadow_Small, NORMAL, self.db.general.fontSize)
+ SetFont(ChatFontSmall, NORMAL, self.db.general.fontSize)
+ SetFont(QuestFontHighlight, NORMAL, self.db.general.fontSize)
+ SetFont(QuestFont, NORMAL, self.db.general.fontSize)
+ SetFont(QuestFont_Large, NORMAL, 14)
+ SetFont(QuestTitleFont, NORMAL, self.db.general.fontSize + 8)
+ SetFont(QuestTitleFontBlackShadow, NORMAL, self.db.general.fontSize + 8)
+ SetFont(SystemFont_Large, NORMAL, 15)
+ SetFont(GameFontNormalMed3, NORMAL, 15)
+ SetFont(SystemFont_Shadow_Huge1, NORMAL, 20, MONOCHROME.."OUTLINE")
+ SetFont(SystemFont_Med1, NORMAL, self.db.general.fontSize)
+ SetFont(SystemFont_Med3, NORMAL, self.db.general.fontSize)
+ SetFont(SystemFont_OutlineThick_Huge2, NORMAL, 20, MONOCHROME.."THICKOUTLINE")
+ SetFont(SystemFont_Outline_Small, NUMBER, self.db.general.fontSize, "OUTLINE")
+ SetFont(SystemFont_Shadow_Large, NORMAL, 15)
+ SetFont(SystemFont_Shadow_Med1, NORMAL, self.db.general.fontSize)
+ SetFont(SystemFont_Shadow_Med3, NORMAL, self.db.general.fontSize)
+ SetFont(SystemFont_Shadow_Outline_Huge2, NORMAL, 20, MONOCHROME.."OUTLINE")
+ SetFont(SystemFont_Shadow_Small, NORMAL, self.db.general.fontSize)
+ SetFont(SystemFont_Small, NORMAL, self.db.general.fontSize)
+ SetFont(SystemFont_Tiny, NORMAL, self.db.general.fontSize)
+ SetFont(Tooltip_Med, NORMAL, self.db.general.fontSize)
+ SetFont(Tooltip_Small, NORMAL, self.db.general.fontSize)
+ SetFont(FriendsFont_Normal, NORMAL, self.db.general.fontSize)
+ SetFont(FriendsFont_Small, NORMAL, self.db.general.fontSize)
+ SetFont(FriendsFont_Large, NORMAL, self.db.general.fontSize)
+ SetFont(FriendsFont_UserText, NORMAL, self.db.general.fontSize)
+ SetFont(SpellFont_Small, NORMAL, self.db.general.fontSize*0.9)
+ SetFont(ZoneTextString, NORMAL, 32, MONOCHROME.."OUTLINE")
+ SetFont(SubZoneTextString, NORMAL, 25, MONOCHROME.."OUTLINE")
+ SetFont(PVPInfoTextString, NORMAL, 22, MONOCHROME.."OUTLINE")
+ SetFont(PVPArenaTextString, NORMAL, 22, MONOCHROME.."OUTLINE")
+ SetFont(CombatTextFont, COMBAT, 100, MONOCHROME.."OUTLINE")
+ SetFont(SystemFont_OutlineThick_WTF, NORMAL, 32, MONOCHROME.."OUTLINE")
+ SetFont(SubZoneTextFont, NORMAL, 24, MONOCHROME.."OUTLINE")
+ SetFont(MailFont_Large, NORMAL, 14)
+ SetFont(InvoiceFont_Med, NORMAL, 12)
+ SetFont(InvoiceFont_Small, NORMAL, self.db.general.fontSize)
+ SetFont(AchievementFont_Small, NORMAL, self.db.general.fontSize)
+ SetFont(ReputationDetailFont, NORMAL, self.db.general.fontSize)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Core/Install.lua b/ElvUI/Core/Install.lua
new file mode 100644
index 0000000..c4442c6
--- /dev/null
+++ b/ElvUI/Core/Install.lua
@@ -0,0 +1,936 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local format = format
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local SetCVar = SetCVar
+local PlaySoundFile = PlaySoundFile
+local ReloadUI = ReloadUI
+local UIFrameFadeOut = UIFrameFadeOut
+local ChatFrame_AddMessageGroup = ChatFrame_AddMessageGroup
+local ChatFrame_RemoveAllMessageGroups = ChatFrame_RemoveAllMessageGroups
+local ChatFrame_AddChannel = ChatFrame_AddChannel
+local ChatFrame_RemoveChannel = ChatFrame_RemoveChannel
+local ChangeChatColor = ChangeChatColor
+local ToggleChatColorNamesByClassGroup = ToggleChatColorNamesByClassGroup
+local FCF_ResetChatWindows = FCF_ResetChatWindows
+local FCF_SetLocked = FCF_SetLocked
+local FCF_DockFrame, FCF_UnDockFrame = FCF_DockFrame, FCF_UnDockFrame
+local FCF_OpenNewWindow = FCF_OpenNewWindow
+local FCF_SavePositionAndDimensions = FCF_SavePositionAndDimensions
+local FCF_SetWindowName = FCF_SetWindowName
+local FCF_StopDragging = FCF_StopDragging
+local FCF_SetChatWindowFontSize = FCF_SetChatWindowFontSize
+local CLASS, CONTINUE, PREVIOUS = CLASS, CONTINUE, PREVIOUS
+local NUM_CHAT_WINDOWS = NUM_CHAT_WINDOWS
+local LOOT, GENERAL, TRADE, GUILD, WHISPER = LOOT, GENERAL, TRADE, GUILD, WHISPER
+local GUILD_EVENT_LOG = GUILD_EVENT_LOG
+
+local CURRENT_PAGE = 0
+local MAX_PAGE = 8
+
+local function SetupChat(noDisplayMsg)
+ FCF_ResetChatWindows() -- Monitor this
+ FCF_SetLocked(ChatFrame1, 1)
+ FCF_DockFrame(ChatFrame2)
+ FCF_SetLocked(ChatFrame2, 1)
+
+ FCF_OpenNewWindow(LOOT)
+ FCF_UnDockFrame(ChatFrame3)
+ FCF_SetLocked(ChatFrame3, 1)
+ ChatFrame3:Show()
+
+ FCF_OpenNewWindow(GUILD)
+ FCF_OpenNewWindow(WHISPER)
+ FCF_DockFrame(ChatFrame4)
+ FCF_SetLocked(ChatFrame4, 1)
+ FCF_DockFrame(ChatFrame5)
+ FCF_SetLocked(ChatFrame5, 1)
+
+ FCF_SelectDockFrame(ChatFrame1)
+
+ for i = 1, NUM_CHAT_WINDOWS do
+ local frame = _G[format("ChatFrame%s", i)]
+
+ -- move general bottom left
+ if i == 1 then
+ frame:ClearAllPoints()
+ frame:Point("BOTTOMLEFT", LeftChatToggleButton, "TOPLEFT", 1, 3)
+ elseif i == 3 then
+ frame:ClearAllPoints()
+ frame:Point("BOTTOMLEFT", RightChatDataPanel, "TOPLEFT", 1, 3)
+ end
+
+ FCF_SavePositionAndDimensions(frame)
+ FCF_StopDragging(frame)
+
+ -- set default Elvui font size
+ FCF_SetChatWindowFontSize(nil, frame, 12)
+
+ -- rename windows general because moved to chat #3
+ if i == 1 then
+ FCF_SetWindowName(frame, GENERAL)
+ elseif i == 2 then
+ FCF_SetWindowName(frame, GUILD_EVENT_LOG)
+ elseif i == 3 then
+ FCF_SetWindowName(frame, LOOT.." / "..TRADE)
+ elseif i == 4 then
+ FCF_SetWindowName(frame, GUILD)
+ elseif i == 5 then
+ FCF_SetWindowName(frame, WHISPER)
+ end
+ end
+
+ local chatGroup = {"SYSTEM", "CHANNEL", "SAY", "EMOTE", "YELL", "WHISPER", "PARTY", "PARTY_LEADER", "RAID", "RAID_LEADER", "RAID_WARNING", "BATTLEGROUND", "BATTLEGROUND_LEADER", "GUILD", "OFFICER", "MONSTER_SAY", "MONSTER_YELL", "MONSTER_EMOTE", "MONSTER_WHISPER", "MONSTER_BOSS_EMOTE", "MONSTER_BOSS_WHISPER", "ERRORS", "AFK", "DND", "IGNORED", "BG_HORDE", "BG_ALLIANCE", "BG_NEUTRAL", "ACHIEVEMENT", "GUILD_ACHIEVEMENT", "BN_WHISPER", "BN_CONVERSATION", "BN_INLINE_TOAST_ALERT"}
+ ChatFrame_RemoveAllMessageGroups(ChatFrame1)
+ for _, v in ipairs(chatGroup) do
+ ChatFrame_AddMessageGroup(ChatFrame1, v)
+ end
+
+ chatGroup = {"COMBAT_XP_GAIN", "COMBAT_HONOR_GAIN", "COMBAT_FACTION_CHANGE", "SKILL", "LOOT", "MONEY"}
+ ChatFrame_RemoveAllMessageGroups(ChatFrame3)
+ for _, v in ipairs(chatGroup) do
+ ChatFrame_AddMessageGroup(ChatFrame3, v)
+ end
+
+ local chatGroup = {"GUILD", "OFFICER", "GUILD_ACHIEVEMENT"}
+ ChatFrame_RemoveAllMessageGroups(ChatFrame4)
+ for _, v in ipairs(chatGroup) do
+ ChatFrame_AddMessageGroup(ChatFrame4, v)
+ end
+
+ local chatGroup = {"WHISPER", "BN_WHISPER"}
+ ChatFrame_RemoveAllMessageGroups(ChatFrame5)
+ for _, v in ipairs(chatGroup) do
+ ChatFrame_AddMessageGroup(ChatFrame5, v)
+ end
+
+ ChatFrame_AddChannel(ChatFrame1, GENERAL)
+ ChatFrame_RemoveChannel(ChatFrame1, TRADE)
+ ChatFrame_RemoveChannel(ChatFrame1, "Ascension")
+ ChatFrame_RemoveChannel(ChatFrame1, "World")
+ ChatFrame_AddChannel(ChatFrame3, TRADE)
+ ChatFrame_AddChannel(ChatFrame3, "Ascension")
+ ChatFrame_AddChannel(ChatFrame3, "World")
+
+ chatGroup = {"SAY", "EMOTE", "YELL", "WHISPER", "PARTY", "PARTY_LEADER", "RAID", "RAID_LEADER", "RAID_WARNING", "BATTLEGROUND", "BATTLEGROUND_LEADER", "GUILD", "OFFICER", "ACHIEVEMENT", "GUILD_ACHIEVEMENT"}
+ for i = 1, MAX_WOW_CHAT_CHANNELS do
+ tinsert(chatGroup, "CHANNEL"..i)
+ end
+ for _, v in ipairs(chatGroup) do
+ ToggleChatColorNamesByClassGroup(true, v)
+ end
+
+ -- Create a list of replacement colors
+ local replacementColors = {
+ ["General"] = {195/255, 230/255, 232/255},
+ ["Trade"] = {232/255, 158/255, 121/255},
+ ["LocalDefense"] = {232/255, 228/255, 121/255},
+ ["GuildRecruitment"] = {64/255, 255/255, 64/255},
+ ["LookingForGroup"] = {0/255, 206/255, 255/255},
+ ["Ascension"] = {255/255, 248/255, 163/255},
+ ["World"] = {255/255, 248/255, 163/255},
+ }
+
+ -- Itterate through the channel list, and set the colors for each specific channel
+ -- We need to do this because the channels change around so much
+ -- low level characters start off with channel 1 being Ascension
+ local chanList = { GetChannelList() }
+ for i=1, #chanList, 2 do
+ if replacementColors[chanList[i+1]] ~= nil then
+ ChangeChatColor("CHANNEL"..chanList[i], unpack(replacementColors[chanList[i+1]]))
+ end
+ if chanList[i+1] == "GuildRecruitment" then
+ ChatFrame_AddChannel(ChatFrame1, "GuildRecruitment")
+ end
+ end
+
+ if E.Chat then
+ E.Chat:PositionChat(true)
+ if E.db.RightChatPanelFaded then
+ RightChatToggleButton:Click()
+ end
+
+ if E.db.LeftChatPanelFaded then
+ LeftChatToggleButton:Click()
+ end
+ end
+
+ if InstallStepComplete and not noDisplayMsg then
+ InstallStepComplete.message = L["Chat Set"]
+ InstallStepComplete:Show()
+ end
+end
+
+local function SetupCVars(noDisplayMsg)
+ SetCVar("mapQuestDifficulty", 1)
+ SetCVar("ShowClassColorInNameplate", 1)
+ SetCVar("screenshotQuality", 10)
+ SetCVar("chatMouseScroll", 1)
+ SetCVar("chatStyle", "classic")
+ SetCVar("WholeChatWindowClickable", 0)
+ SetCVar("ConversationMode", "inline")
+ SetCVar("showTutorials", 0)
+ SetCVar("showNewbieTips", 0)
+ SetCVar("showLootSpam", 1)
+ SetCVar("UberTooltips", 1)
+ SetCVar("threatWarning", 3)
+ SetCVar("alwaysShowActionBars", 1)
+ SetCVar("lockActionBars", 1)
+ SetCVar("SpamFilter", 0)
+
+ if InstallStepComplete and not noDisplayMsg then
+ InstallStepComplete.message = L["CVars Set"]
+ InstallStepComplete:Show()
+ end
+end
+
+function E:GetColor(r, g, b, a)
+ return {r = r, g = g, b = b, a = a}
+end
+
+function E:SetupTheme(theme, noDisplayMsg)
+ E.private.theme = theme
+
+ local classColor
+
+ --Set colors
+ if theme == "classic" then
+ E.db.general.bordercolor = (E.PixelMode and E:GetColor(0, 0, 0) or E:GetColor(0.31, 0.31, 0.31))
+ E.db.general.backdropcolor = E:GetColor(0.1, 0.1, 0.1)
+ E.db.general.backdropfadecolor = E:GetColor(13/255, 13/255, 13/255, 0.69)
+ E.db.unitframe.colors.borderColor = (E.PixelMode and E:GetColor(0, 0, 0) or E:GetColor(0.31, 0.31, 0.31))
+ E.db.unitframe.colors.healthclass = false
+ E.db.unitframe.colors.health = E:GetColor(0.31, 0.31, 0.31)
+ E.db.unitframe.colors.auraBarBuff = E:GetColor(0.31, 0.31, 0.31)
+ E.db.unitframe.colors.castColor = E:GetColor(0.31, 0.31, 0.31)
+ E.db.unitframe.colors.castClassColor = false
+ elseif theme == "class" then
+ classColor = E.media.herocolor
+
+ E.db.general.bordercolor = (E.PixelMode and E:GetColor(0, 0, 0) or E:GetColor(0.31, 0.31, 0.31))
+ E.db.general.backdropcolor = E:GetColor(0.1, 0.1, 0.1)
+ E.db.general.backdropfadecolor = E:GetColor(0.06, 0.06, 0.06, 0.8)
+ E.db.unitframe.colors.borderColor = (E.PixelMode and E:GetColor(0, 0, 0) or E:GetColor(0.31, 0.31, 0.31))
+ E.db.unitframe.colors.auraBarBuff = E:GetColor(classColor.r, classColor.g, classColor.b)
+ E.db.unitframe.colors.healthclass = true
+ E.db.unitframe.colors.castClassColor = true
+ else
+ E.db.general.bordercolor = (E.PixelMode and E:GetColor(0, 0, 0) or E:GetColor(0.1, 0.1, 0.1))
+ E.db.general.backdropcolor = E:GetColor(0.1, 0.1, 0.1)
+ E.db.general.backdropfadecolor = E:GetColor(0.054, 0.054, 0.054, 0.8)
+ E.db.unitframe.colors.borderColor = (E.PixelMode and E:GetColor(0, 0, 0) or E:GetColor(0.1, 0.1, 0.1))
+ E.db.unitframe.colors.auraBarBuff = E:GetColor(0.1, 0.1, 0.1)
+ E.db.unitframe.colors.healthclass = false
+ E.db.unitframe.colors.health = E:GetColor(0.1, 0.1, 0.1)
+ E.db.unitframe.colors.castColor = E:GetColor(0.1, 0.1, 0.1)
+ E.db.unitframe.colors.castClassColor = false
+ end
+
+ --Value Color
+ if theme == "class" then
+ E.db.general.valuecolor = E:GetColor(classColor.r, classColor.g, classColor.b)
+ else
+ E.db.general.valuecolor = E:GetColor(254/255, 123/255, 44/255)
+ end
+
+ E:UpdateAll(true)
+
+ if InstallStepComplete and not noDisplayMsg then
+ InstallStepComplete.message = L["Theme Set"]
+ InstallStepComplete:Show()
+ end
+end
+
+function E:SetupLayout(layout, noDataReset, noDisplayMsg)
+ if not noDataReset then
+ E.db.layoutSet = layout
+
+ --Unitframes
+ E:CopyTable(E.db.unitframe.units, P.unitframe.units)
+
+ --Shared base layout, tweaks to individual layouts will be below
+ E:ResetMovers("")
+ if not E.db.movers then E.db.movers = {} end
+
+ --ActionBars
+ E.db.actionbar.backdropSpacingConverted = true
+ E.db.actionbar.bar1.buttons = 8
+ E.db.actionbar.bar1.buttonsize = 50
+ E.db.actionbar.bar1.buttonspacing = 1
+ E.db.actionbar.bar2.buttons = 9
+ E.db.actionbar.bar2.buttonsize = 38
+ E.db.actionbar.bar2.buttonspacing = 1
+ E.db.actionbar.bar2.enabled = true
+ E.db.actionbar.bar2.visibility = "[vehicleui] hide; show"
+ E.db.actionbar.bar3.buttons = 8
+ E.db.actionbar.bar3.buttonsize = 50
+ E.db.actionbar.bar3.buttonspacing = 1
+ E.db.actionbar.bar3.buttonsPerRow = 10
+ E.db.actionbar.bar3.visibility = "[vehicleui] hide; show"
+ E.db.actionbar.bar4.enabled = false
+ E.db.actionbar.bar4.visibility = "[vehicleui] hide; show"
+ E.db.actionbar.bar5.enabled = false
+ E.db.actionbar.bar5.visibility = "[vehicleui] hide; show"
+ E.db.actionbar.bar6.visibility = "[vehicleui] hide; show"
+ --Auras
+ E.db.auras.buffs.countFontSize = 10
+ E.db.auras.buffs.size = 40
+ E.db.auras.debuffs.countFontSize = 10
+ E.db.auras.debuffs.size = 40
+ --Bags
+ E.db.bags.bagSize = 42
+ E.db.bags.bagWidth = 472
+ E.db.bags.bankSize = 42
+ E.db.bags.bankWidth = 472
+ --Chat
+ E.db.chat.fontSize = 10
+ E.db.chat.panelColorConverted = true
+ E.db.chat.separateSizes = false
+ E.db.chat.panelHeight = 236
+ E.db.chat.panelWidth = 472
+ E.db.chat.tapFontSize = 10
+ --DataBars
+ E.db.databars.experience.height = 10
+ E.db.databars.experience.orientation = "HORIZONTAL"
+ E.db.databars.experience.textSize = 12
+ E.db.databars.experience.width = 350
+ E.db.databars.reputation.enable = true
+ E.db.databars.reputation.height = 10
+ E.db.databars.reputation.orientation = "HORIZONTAL"
+ E.db.databars.reputation.width = 222
+ --General
+ E.db.general.minimap.size = 220
+ E.db.general.watchFrameHeight = 400
+ E.db.general.totems.growthDirection = "HORIZONTAL"
+ E.db.general.totems.size = 50
+ E.db.general.totems.spacing = 8
+ E.db.general.reminder.enable = false
+ --Movers
+ E.db.movers.AlertFrameMover = "TOP,ElvUIParent,TOP,-1,-18"
+ E.db.movers.BNETMover = "TOPRIGHT,ElvUIParent,TOPRIGHT,-4,-274"
+ E.db.movers.ElvAB_1 = "BOTTOM,ElvUIParent,BOTTOM,0,190"
+ E.db.movers.ElvAB_2 = "BOTTOM,ElvUIParent,BOTTOM,0,4"
+ E.db.movers.ElvAB_3 = "BOTTOM,ElvUIParent,BOTTOM,0,138"
+ E.db.movers.ElvAB_5 = "BOTTOM,ElvUIParent,BOTTOM,-92,57"
+ E.db.movers.ElvBar_Totem = "BOTTOM,ElvUIParent,BOTTOM,0,55"
+ E.db.movers.ElvUF_FocusMover = "BOTTOM,ElvUIParent,BOTTOM,342,59"
+ E.db.movers.ElvUF_PartyMover = "BOTTOMLEFT,ElvUIParent,BOTTOMLEFT,4,248"
+ E.db.movers.ElvUF_PetMover = "BOTTOM,ElvUIParent,BOTTOM,-341,99"
+ E.db.movers.ElvUF_PlayerCastbarMover = "BOTTOM,ElvUIParent,BOTTOM,0,96"
+ E.db.movers.ElvUF_PlayerMover = "BOTTOM,ElvUIParent,BOTTOM,-341,138"
+ E.db.movers.ElvUF_Raid40Mover = "TOPLEFT,ElvUIParent,BOTTOMLEFT,4,482"
+ E.db.movers.ElvUF_RaidMover = "BOTTOMLEFT,ElvUIParent,BOTTOMLEFT,4,248"
+ E.db.movers.ElvUF_RaidpetMover = "TOPLEFT,ElvUIParent,BOTTOMLEFT,4,737"
+ E.db.movers.ElvUF_TargetCastbarMover = "BOTTOM,ElvUIParent,BOTTOM,0,242"
+ E.db.movers.ElvUF_TargetMover = "BOTTOM,ElvUIParent,BOTTOM,342,138"
+ E.db.movers.ElvUF_TargetTargetMover = "BOTTOM,ElvUIParent,BOTTOM,342,99"
+ E.db.movers.ExperienceBarMover = "BOTTOM,ElvUIParent,BOTTOM,0,43"
+ E.db.movers.LootFrameMover = "TOPLEFT,ElvUIParent,TOPLEFT,418,-186"
+ E.db.movers.MirrorTimer1Mover = "TOP,ElvUIParent,TOP,-1,-96"
+ E.db.movers.WatchFrameMover = "TOPRIGHT,ElvUIParent,TOPRIGHT,-163,-325"
+ E.db.movers.ReputationBarMover = "TOPRIGHT,ElvUIParent,TOPRIGHT,-2,-245"
+ E.db.movers.ShiftAB = "TOPLEFT,ElvUIParent,BOTTOMLEFT,4,769"
+ E.db.movers.TempEnchantMover = "TOPRIGHT,ElvUIParent,TOPRIGHT,-4,-257"
+ E.db.movers.TotemBarMover = "BOTTOMLEFT,ElvUIParent,BOTTOMLEFT,485,4"
+ E.db.movers.VehicleSeatMover = "TOPLEFT,ElvUIParent,TOPLEFT,4,-4"
+ --Tooltip
+ E.db.tooltip.fontSize = 10
+ E.db.tooltip.healthBar.fontOutline = "MONOCHROMEOUTLINE"
+ E.db.tooltip.healthBar.height = 12
+ --UnitFrames
+ E.db.unitframe.smoothbars = true
+ E.db.unitframe.thinBorders = true
+ --Player
+ E.db.unitframe.units.player.aurabar.height = 26
+ E.db.unitframe.units.player.buffs.perrow = 7
+ E.db.unitframe.units.player.castbar.height = 40
+ E.db.unitframe.units.player.castbar.insideInfoPanel = false
+ E.db.unitframe.units.player.castbar.width = 407
+ E.db.unitframe.units.player.classbar.height = 14
+ E.db.unitframe.units.player.debuffs.perrow = 7
+ E.db.unitframe.units.player.disableMouseoverGlow = true
+ E.db.unitframe.units.player.health.attachTextTo = "InfoPanel"
+ E.db.unitframe.units.player.height = 82
+ E.db.unitframe.units.player.infoPanel.enable = true
+ E.db.unitframe.units.player.power.attachTextTo = "InfoPanel"
+ E.db.unitframe.units.player.power.height = 22
+ --Target
+ E.db.unitframe.units.target.aurabar.height = 26
+ E.db.unitframe.units.target.buffs.anchorPoint = "TOPLEFT"
+ E.db.unitframe.units.target.buffs.perrow = 7
+ E.db.unitframe.units.target.castbar.height = 40
+ E.db.unitframe.units.target.castbar.insideInfoPanel = false
+ E.db.unitframe.units.target.castbar.width = 407
+ E.db.unitframe.units.target.debuffs.anchorPoint = "TOPLEFT"
+ E.db.unitframe.units.target.debuffs.attachTo = "FRAME"
+ E.db.unitframe.units.target.debuffs.enable = false
+ E.db.unitframe.units.target.debuffs.maxDuration = 0
+ E.db.unitframe.units.target.debuffs.perrow = 7
+ E.db.unitframe.units.target.disableMouseoverGlow = true
+ E.db.unitframe.units.target.health.attachTextTo = "InfoPanel"
+ E.db.unitframe.units.target.height = 82
+ E.db.unitframe.units.target.infoPanel.enable = true
+ E.db.unitframe.units.target.name.attachTextTo = "InfoPanel"
+ E.db.unitframe.units.target.name.text_format = "[namecolor][name]"
+ E.db.unitframe.units.target.orientation = "LEFT"
+ E.db.unitframe.units.target.power.attachTextTo = "InfoPanel"
+ E.db.unitframe.units.target.power.height = 22
+ --TargetTarget
+ E.db.unitframe.units.targettarget.debuffs.anchorPoint = "TOPRIGHT"
+ E.db.unitframe.units.targettarget.debuffs.enable = false
+ E.db.unitframe.units.targettarget.disableMouseoverGlow = true
+ E.db.unitframe.units.targettarget.power.enable = false
+ E.db.unitframe.units.targettarget.raidicon.attachTo = "LEFT"
+ E.db.unitframe.units.targettarget.raidicon.enable = false
+ E.db.unitframe.units.targettarget.raidicon.xOffset = 2
+ E.db.unitframe.units.targettarget.raidicon.yOffset = 0
+ E.db.unitframe.units.targettarget.threatStyle = "GLOW"
+ E.db.unitframe.units.targettarget.width = 270
+ --Focus
+ E.db.unitframe.units.focus.castbar.width = 270
+ E.db.unitframe.units.focus.width = 270
+ --Pet
+ E.db.unitframe.units.pet.castbar.iconSize = 32
+ E.db.unitframe.units.pet.castbar.width = 270
+ E.db.unitframe.units.pet.debuffs.anchorPoint = "TOPRIGHT"
+ E.db.unitframe.units.pet.debuffs.enable = true
+ E.db.unitframe.units.pet.disableTargetGlow = false
+ E.db.unitframe.units.pet.infoPanel.height = 14
+ E.db.unitframe.units.pet.portrait.camDistanceScale = 2
+ E.db.unitframe.units.pet.width = 270
+ --Boss
+ E.db.unitframe.units.boss.buffs.maxDuration = 300
+ E.db.unitframe.units.boss.buffs.sizeOverride = 27
+ E.db.unitframe.units.boss.buffs.yOffset = 16
+ E.db.unitframe.units.boss.castbar.width = 246
+ E.db.unitframe.units.boss.debuffs.maxDuration = 300
+ E.db.unitframe.units.boss.debuffs.numrows = 1
+ E.db.unitframe.units.boss.debuffs.sizeOverride = 27
+ E.db.unitframe.units.boss.debuffs.yOffset = -16
+ E.db.unitframe.units.boss.height = 60
+ E.db.unitframe.units.boss.infoPanel.height = 17
+ E.db.unitframe.units.boss.portrait.camDistanceScale = 2
+ E.db.unitframe.units.boss.portrait.width = 45
+ E.db.unitframe.units.boss.width = 246
+ --Party
+ E.db.unitframe.units.party.height = 74
+ E.db.unitframe.units.party.power.height = 13
+ E.db.unitframe.units.party.rdebuffs.font = "PT Sans Narrow"
+ E.db.unitframe.units.party.width = 231
+ --Raid
+ E.db.unitframe.units.raid.growthDirection = "RIGHT_UP"
+ E.db.unitframe.units.raid.health.frequentUpdates = true
+ E.db.unitframe.units.raid.infoPanel.enable = true
+ E.db.unitframe.units.raid.name.attachTextTo = "InfoPanel"
+ E.db.unitframe.units.raid.name.position = "BOTTOMLEFT"
+ E.db.unitframe.units.raid.name.xOffset = 2
+ E.db.unitframe.units.raid.numGroups = 8
+ E.db.unitframe.units.raid.rdebuffs.font = "PT Sans Narrow"
+ E.db.unitframe.units.raid.rdebuffs.size = 30
+ E.db.unitframe.units.raid.rdebuffs.xOffset = 30
+ E.db.unitframe.units.raid.rdebuffs.yOffset = 25
+ E.db.unitframe.units.raid.resurrectIcon.attachTo = "BOTTOMRIGHT"
+ E.db.unitframe.units.raid.visibility = "[@raid6,noexists] hide;show"
+ E.db.unitframe.units.raid.width = 92
+ --Raid40
+ E.db.unitframe.units.raid40.enable = false
+ E.db.unitframe.units.raid40.rdebuffs.font = "PT Sans Narrow"
+
+ --[[
+ -- Layout Tweaks will be handled below.
+ -- These are changes that deviate from the shared base layout
+ --]]
+
+ if layout == "dpsCaster" then
+ E.db.movers.ElvUF_PlayerCastbarMover = "BOTTOM,ElvUIParent,BOTTOM,0,243"
+ E.db.movers.ElvUF_TargetCastbarMover = "BOTTOM,ElvUIParent,BOTTOM,0,97"
+ elseif layout == "healer" then
+ E.db.movers.ElvUF_PlayerCastbarMover = "BOTTOM,ElvUIParent,BOTTOM,0,243"
+ E.db.movers.ElvUF_TargetCastbarMover = "BOTTOM,ElvUIParent,BOTTOM,0,97"
+ E.db.movers.ElvUF_RaidMover = "BOTTOMLEFT,ElvUIParent,BOTTOMLEFT,202,373"
+ E.db.movers.LootFrameMover = "TOPLEFT,ElvUIParent,TOPLEFT,250,-104"
+ E.db.movers.ShiftAB = "TOPLEFT,ElvUIParent,BOTTOMLEFT,4,273"
+ E.db.unitframe.units.party.enable = false
+ E.db.unitframe.units.party.health.frequentUpdates = true
+ E.db.unitframe.units.raid.visibility = "[nogroup] hide;show"
+ E.db.unitframe.units.raid40.health.frequentUpdates = true
+ end
+ end
+
+ E:UpdateAll(true)
+
+ if InstallStepComplete and not noDisplayMsg then
+ InstallStepComplete.message = L["Layout Set"]
+ InstallStepComplete:Show()
+ end
+end
+
+local function SetupAuras(style, noDisplayMsg)
+ local frame = UF.player
+ E:CopyTable(E.db.unitframe.units.player.buffs, P.unitframe.units.player.buffs)
+ E:CopyTable(E.db.unitframe.units.player.debuffs, P.unitframe.units.player.debuffs)
+ E:CopyTable(E.db.unitframe.units.player.aurabar, P.unitframe.units.player.aurabar)
+ if frame then
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+ UF:Configure_AuraBars(frame)
+ end
+
+ frame = UF.target
+ E:CopyTable(E.db.unitframe.units.target.buffs, P.unitframe.units.target.buffs)
+ E:CopyTable(E.db.unitframe.units.target.debuffs, P.unitframe.units.target.debuffs)
+ E:CopyTable(E.db.unitframe.units.target.aurabar, P.unitframe.units.target.aurabar)
+ if frame then
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+ UF:Configure_AuraBars(frame)
+ end
+
+ frame = UF.focus
+ E:CopyTable(E.db.unitframe.units.focus.buffs, P.unitframe.units.focus.buffs)
+ E:CopyTable(E.db.unitframe.units.focus.debuffs, P.unitframe.units.focus.debuffs)
+ E:CopyTable(E.db.unitframe.units.focus.aurabar, P.unitframe.units.focus.aurabar)
+ if frame then
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+ UF:Configure_AuraBars(frame)
+ end
+
+ if not style then
+ --PLAYER
+ E.db.unitframe.units.player.buffs.enable = true
+ E.db.unitframe.units.player.buffs.attachTo = "FRAME"
+ E.db.unitframe.units.player.debuffs.attachTo = "BUFFS"
+ E.db.unitframe.units.player.aurabar.enable = false
+ if E.private.unitframe.enable then
+ UF:CreateAndUpdateUF("player")
+ end
+
+ --TARGET
+ E.db.unitframe.units.target.debuffs.enable = true
+ E.db.unitframe.units.target.aurabar.enable = false
+ if E.private.unitframe.enable then
+ UF:CreateAndUpdateUF("target")
+ end
+ end
+
+ if InstallStepComplete and not noDisplayMsg then
+ InstallStepComplete.message = L["Auras Set"]
+ InstallStepComplete:Show()
+ end
+end
+
+local function InstallComplete()
+ E.private.install_complete = E.version
+
+ ReloadUI()
+end
+
+local function ResetAll()
+ InstallNextButton:Disable()
+ InstallPrevButton:Disable()
+ InstallOption1Button:Hide()
+ InstallOption1Button:SetScript("OnClick", nil)
+ InstallOption1Button:SetText("")
+ InstallOption2Button:Hide()
+ InstallOption2Button:SetScript("OnClick", nil)
+ InstallOption2Button:SetText("")
+ InstallOption3Button:Hide()
+ InstallOption3Button:SetScript("OnClick", nil)
+ InstallOption3Button:SetText("")
+ InstallOption4Button:Hide()
+ InstallOption4Button:SetScript("OnClick", nil)
+ InstallOption4Button:SetText("")
+ InstallSlider:Hide()
+ InstallSlider.Min:SetText("")
+ InstallSlider.Max:SetText("")
+ InstallSlider.Cur:SetText("")
+ ElvUIInstallFrame.SubTitle:SetText("")
+ ElvUIInstallFrame.Desc1:SetText("")
+ ElvUIInstallFrame.Desc2:SetText("")
+ ElvUIInstallFrame.Desc3:SetText("")
+ ElvUIInstallFrame:Size(550, 400)
+end
+
+local function SetPage(PageNum)
+ CURRENT_PAGE = PageNum
+ ResetAll()
+
+ InstallStatus.anim.progress:SetChange(PageNum)
+ InstallStatus.anim.progress:Play()
+ InstallStatus.text:SetText(CURRENT_PAGE.." / "..MAX_PAGE)
+
+ local r, g, b = E:ColorGradient(CURRENT_PAGE / MAX_PAGE, 1, 0, 0, 1, 1, 0, 0, 1, 0)
+ ElvUIInstallFrame.Status:SetStatusBarColor(r, g, b)
+
+ if PageNum == MAX_PAGE then
+ InstallNextButton:Disable()
+ else
+ InstallNextButton:Enable()
+ end
+
+ if PageNum == 1 then
+ InstallPrevButton:Disable()
+ else
+ InstallPrevButton:Enable()
+ end
+
+ local f = ElvUIInstallFrame
+ if PageNum == 1 then
+ f.SubTitle:SetFormattedText(L["Welcome to ElvUI version %s!"], E.version)
+ f.Desc1:SetText(L["This install process will help you learn some of the features in ElvUI has to offer and also prepare your user interface for usage."])
+ f.Desc2:SetText(L["The in-game configuration menu can be accessed by typing the /ec command or by clicking the 'C' button on the minimap. Press the button below if you wish to skip the installation process."])
+ f.Desc3:SetText(L["Please press the continue button to go onto the next step."])
+ InstallOption1Button:Show()
+ InstallOption1Button:SetScript("OnClick", InstallComplete)
+ InstallOption1Button:SetText(L["Skip Process"])
+ elseif PageNum == 2 then
+ f.SubTitle:SetText(L["CVars"])
+ f.Desc1:SetText(L["This part of the installation process sets up your World of Warcraft default options it is recommended you should do this step for everything to behave properly."])
+ f.Desc2:SetText(L["Please click the button below to setup your CVars."])
+ f.Desc3:SetText(L["Importance: |cff07D400High|r"])
+ InstallOption1Button:Show()
+ InstallOption1Button:SetScript("OnClick", function() SetupCVars() end)
+ InstallOption1Button:SetText(L["Setup CVars"])
+ elseif PageNum == 3 then
+ f.SubTitle:SetText(L["Chat"])
+ f.Desc1:SetText(L["This part of the installation process sets up your chat windows names, positions and colors."])
+ f.Desc2:SetText(L["The chat windows function the same as Blizzard standard chat windows, you can right click the tabs and drag them around, rename, etc. Please click the button below to setup your chat windows."])
+ f.Desc3:SetText(L["Importance: |cffD3CF00Medium|r"])
+ InstallOption1Button:Show()
+ InstallOption1Button:SetScript("OnClick", function() SetupChat() end)
+ InstallOption1Button:SetText(L["Setup Chat"])
+ elseif PageNum == 4 then
+ f.SubTitle:SetText(L["Theme Setup"])
+ f.Desc1:SetText(L["Choose a theme layout you wish to use for your initial setup."])
+ f.Desc2:SetText(L["You can always change fonts and colors of any element of ElvUI from the in-game configuration."])
+ f.Desc3:SetText(L["Importance: |cffFF0000Low|r"])
+ InstallOption1Button:Show()
+ InstallOption1Button:SetScript("OnClick", function() E:SetupTheme("classic") end)
+ InstallOption1Button:SetText(L["Classic"])
+ InstallOption2Button:Show()
+ InstallOption2Button:SetScript("OnClick", function() E:SetupTheme("default") end)
+ InstallOption2Button:SetText(L["Dark"])
+ InstallOption3Button:Show()
+ InstallOption3Button:SetScript("OnClick", function() E:SetupTheme("class") end)
+ InstallOption3Button:SetText(CLASS)
+ elseif PageNum == 5 then
+ f.SubTitle:SetText(L["UI Scale"])
+ f.Desc1:SetFormattedText(L["Adjust the UI Scale to fit your screen, press the autoscale button to set the UI Scale automatically."])
+ InstallSlider:Show()
+ InstallSlider:SetValueStep(0.01)
+ InstallSlider:SetMinMaxValues(0.4, 1.15)
+
+ local value = E.global.general.UIScale
+ InstallSlider:SetValue(value)
+ InstallSlider.Cur:SetText(value)
+ InstallSlider:SetScript("OnValueChanged", function(self)
+ E.global.general.UIScale = self:GetValue()
+ InstallSlider.Cur:SetText(E.global.general.UIScale)
+ end)
+
+ InstallSlider.Min:SetText(0.4)
+ InstallSlider.Max:SetText(1.15)
+ InstallOption1Button:Show()
+ InstallOption1Button:SetScript("OnClick", function()
+ local scale = E:PixelBestSize()
+
+ -- this is to just keep the slider in place, the values need updated again afterwards
+ InstallSlider:SetValue(scale)
+
+ -- update the values with deeper accuracy
+ E.global.general.UIScale = scale
+ InstallSlider.Cur:SetText(E.global.general.UIScale)
+ end)
+
+ InstallOption1Button:SetText(L["Auto Scale"])
+ InstallOption2Button:Show()
+ InstallOption2Button:SetScript("OnClick", function()
+ E:PixelScaleChanged(nil, true)
+ end)
+
+ InstallOption2Button:SetText(L["Preview"])
+ f.Desc3:SetText(L["Importance: |cff07D400High|r"])
+ elseif PageNum == 6 then
+ f.SubTitle:SetText(L["Layout"])
+ f.Desc1:SetText(L["You can now choose what layout you wish to use based on your combat role."])
+ f.Desc2:SetText(L["This will change the layout of your unitframes and actionbars."])
+ f.Desc3:SetText(L["Importance: |cffD3CF00Medium|r"])
+ InstallOption1Button:Show()
+ InstallOption1Button:SetScript("OnClick", function() E.db.layoutSet = nil E:SetupLayout("tank") end)
+ InstallOption1Button:SetText(L["Tank / Physical DPS"])
+ InstallOption2Button:Show()
+ InstallOption2Button:SetScript("OnClick", function() E.db.layoutSet = nil E:SetupLayout("healer") end)
+ InstallOption2Button:SetText(L["Healer"])
+ InstallOption3Button:Show()
+ InstallOption3Button:SetScript("OnClick", function() E.db.layoutSet = nil E:SetupLayout("dpsCaster") end)
+ InstallOption3Button:SetText(L["Caster DPS"])
+ elseif PageNum == 7 then
+ f.SubTitle:SetText(L["Auras"])
+ f.Desc1:SetText(L["Select the type of aura system you want to use with ElvUI's unitframes. Set to Aura Bar & Icons to use both aura bars and icons, set to icons only to only see icons."])
+ f.Desc2:SetText(L["If you have an icon or aurabar that you don't want to display simply hold down shift and right click the icon for it to disapear."])
+ f.Desc3:SetText(L["Importance: |cffD3CF00Medium|r"])
+ InstallOption1Button:Show()
+ InstallOption1Button:SetScript("OnClick", function() SetupAuras(true) end)
+ InstallOption1Button:SetText(L["Aura Bars & Icons"])
+ InstallOption2Button:Show()
+ InstallOption2Button:SetScript("OnClick", function() SetupAuras() end)
+ InstallOption2Button:SetText(L["Icons Only"])
+ elseif PageNum == 8 then
+ f.SubTitle:SetText(L["Installation Complete"])
+ f.Desc1:SetText(L["You are now finished with the installation process. If you are in need of technical support please visit us at https://github.com/ElvUI-WotLK."])
+ f.Desc2:SetText(L["Please click the button below so you can setup variables and ReloadUI."])
+ InstallOption1Button:Show()
+ InstallOption1Button:SetScript("OnClick", function() E:StaticPopup_Show("ELVUI_EDITBOX", nil, nil, "https://discord.gg/UXSc7nt") end)
+ InstallOption1Button:SetText(L["Discord"])
+ InstallOption2Button:Show()
+ InstallOption2Button:SetScript("OnClick", InstallComplete)
+ InstallOption2Button:SetText(L["Finished"])
+ ElvUIInstallFrame:Size(550, 350)
+ end
+end
+
+local function NextPage()
+ if CURRENT_PAGE ~= MAX_PAGE then
+ CURRENT_PAGE = CURRENT_PAGE + 1
+ SetPage(CURRENT_PAGE)
+ end
+end
+
+local function PreviousPage()
+ if CURRENT_PAGE ~= 1 then
+ CURRENT_PAGE = CURRENT_PAGE - 1
+ SetPage(CURRENT_PAGE)
+ end
+end
+
+--Install UI
+function E:Install()
+ if not InstallStepComplete then
+ local imsg = CreateFrame("Frame", "InstallStepComplete", E.UIParent)
+ imsg:Size(418, 72)
+ imsg:Point("TOP", 0, -190)
+ imsg:Hide()
+ imsg:SetScript("OnShow", function(f)
+ if f.message then
+ PlaySoundFile([[Sound\Interface\LevelUp.wav]])
+ f.text:SetText(f.message)
+ UIFrameFadeOut(f, 3.5, 1, 0)
+ E:Delay(4, f.Hide, f)
+ f.message = nil
+ else
+ f:Hide()
+ end
+ end)
+
+ imsg.firstShow = false
+
+ imsg.bg = imsg:CreateTexture(nil, "BACKGROUND")
+ imsg.bg:SetTexture([[Interface\AddOns\ElvUI\media\textures\LevelUpTex]])
+ imsg.bg:Point("BOTTOM")
+ imsg.bg:Size(326, 103)
+ imsg.bg:SetTexCoord(0.00195313, 0.63867188, 0.03710938, 0.23828125)
+ imsg.bg:SetVertexColor(1, 1, 1, 0.6)
+
+ imsg.lineTop = imsg:CreateTexture(nil, "BACKGROUND")
+ imsg.lineTop:SetDrawLayer("BACKGROUND")
+ imsg.lineTop:SetTexture([[Interface\AddOns\ElvUI\media\textures\LevelUpTex]])
+ imsg.lineTop:Point("TOP")
+ imsg.lineTop:Size(418, 7)
+ imsg.lineTop:SetTexCoord(0.00195313, 0.81835938, 0.01953125, 0.03320313)
+
+ imsg.lineBottom = imsg:CreateTexture(nil, "BACKGROUND")
+ imsg.lineBottom:SetDrawLayer("BACKGROUND")
+ imsg.lineBottom:SetTexture([[Interface\AddOns\ElvUI\media\textures\LevelUpTex]])
+ imsg.lineBottom:Point("BOTTOM")
+ imsg.lineBottom:Size(418, 7)
+ imsg.lineBottom:SetTexCoord(0.00195313, 0.81835938, 0.01953125, 0.03320313)
+
+ imsg.text = imsg:CreateFontString(nil, "OVERLAY")
+ imsg.text:FontTemplate(E.media.normFont, 32, "OUTLINE")
+ imsg.text:Point("BOTTOM", 0, 16)
+ imsg.text:SetTextColor(1, 0.82, 0)
+ imsg.text:SetJustifyH("CENTER")
+ end
+
+ --Create Frame
+ if not ElvUIInstallFrame then
+ local f = CreateFrame("Button", "ElvUIInstallFrame", E.UIParent)
+ f.SetPage = SetPage
+ f:Size(550, 400)
+ f:SetTemplate("Transparent")
+ f:Point("CENTER")
+ f:SetFrameStrata("TOOLTIP")
+
+ f:SetMovable(true)
+ f:EnableMouse(true)
+ f:RegisterForDrag("LeftButton")
+ f:SetScript("OnDragStart", function(frame) frame:StartMoving() frame:SetUserPlaced(false) end)
+ f:SetScript("OnDragStop", function(frame) frame:StopMovingOrSizing() end)
+
+ f.Title = f:CreateFontString(nil, "OVERLAY")
+ f.Title:FontTemplate(nil, 17, nil)
+ f.Title:Point("TOP", 0, -5)
+ f.Title:SetText(L["ElvUI Installation"])
+
+ f.Next = CreateFrame("Button", "InstallNextButton", f, "UIPanelButtonTemplate")
+ f.Next:Size(110, 25)
+ f.Next:Point("BOTTOMRIGHT", -5, 5)
+ f.Next:SetText(CONTINUE)
+ f.Next:Disable()
+ f.Next:SetScript("OnClick", NextPage)
+ S:HandleButton(f.Next, true)
+
+ f.Prev = CreateFrame("Button", "InstallPrevButton", f, "UIPanelButtonTemplate")
+ f.Prev:Size(110, 25)
+ f.Prev:Point("BOTTOMLEFT", 5, 5)
+ f.Prev:SetText(PREVIOUS)
+ f.Prev:Disable()
+ f.Prev:SetScript("OnClick", PreviousPage)
+ S:HandleButton(f.Prev, true)
+
+ f.Status = CreateFrame("StatusBar", "InstallStatus", f)
+ f.Status:SetFrameLevel(f.Status:GetFrameLevel() + 2)
+ f.Status:CreateBackdrop()
+ f.Status:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(f.Status)
+ f.Status:SetMinMaxValues(0, MAX_PAGE)
+ f.Status:Point("TOPLEFT", f.Prev, "TOPRIGHT", 6, -2)
+ f.Status:Point("BOTTOMRIGHT", f.Next, "BOTTOMLEFT", -6, 2)
+
+ -- Setup StatusBar Animation
+ f.Status.anim = CreateAnimationGroup(f.Status)
+ f.Status.anim.progress = f.Status.anim:CreateAnimation("Progress")
+ f.Status.anim.progress:SetEasing("Out")
+ f.Status.anim.progress:SetDuration(0.3)
+
+ f.Status.text = f.Status:CreateFontString(nil, "OVERLAY")
+ f.Status.text:FontTemplate()
+ f.Status.text:Point("CENTER")
+ f.Status.text:SetText(CURRENT_PAGE.." / "..MAX_PAGE)
+
+ f.Slider = CreateFrame("Slider", "InstallSlider", f)
+ f.Slider:SetOrientation("HORIZONTAL")
+ f.Slider:Height(15)
+ f.Slider:Width(400)
+ f.Slider:SetHitRectInsets(0, 0, -10, 0)
+ f.Slider:SetPoint("CENTER", 0, 45)
+ S:HandleSliderFrame(f.Slider)
+ f.Slider:Hide()
+
+ f.Slider.Min = f.Slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ f.Slider.Min:SetPoint("RIGHT", f.Slider, "LEFT", -3, 0)
+ f.Slider.Max = f.Slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ f.Slider.Max:SetPoint("LEFT", f.Slider, "RIGHT", 3, 0)
+ f.Slider.Cur = f.Slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ f.Slider.Cur:SetPoint("BOTTOM", f.Slider, "TOP", 0, 10)
+ f.Slider.Cur:FontTemplate(nil, 30, nil)
+
+ f.Option1 = CreateFrame("Button", "InstallOption1Button", f, "UIPanelButtonTemplate")
+ f.Option1:Size(160, 30)
+ f.Option1:Point("BOTTOM", 0, 45)
+ f.Option1:SetText("")
+ f.Option1:Hide()
+ S:HandleButton(f.Option1, true)
+
+ f.Option2 = CreateFrame("Button", "InstallOption2Button", f, "UIPanelButtonTemplate")
+ f.Option2:Size(110, 30)
+ f.Option2:Point("BOTTOMLEFT", f, "BOTTOM", 4, 45)
+ f.Option2:SetText("")
+ f.Option2:Hide()
+ f.Option2:SetScript("OnShow", function()
+ f.Option1:Width(110)
+ f.Option1:ClearAllPoints()
+ f.Option1:Point("BOTTOMRIGHT", f, "BOTTOM", -4, 45)
+ end)
+ f.Option2:SetScript("OnHide", function()
+ f.Option1:Width(160)
+ f.Option1:ClearAllPoints()
+ f.Option1:Point("BOTTOM", 0, 45)
+ end)
+ S:HandleButton(f.Option2, true)
+
+ f.Option3 = CreateFrame("Button", "InstallOption3Button", f, "UIPanelButtonTemplate")
+ f.Option3:Size(100, 30)
+ f.Option3:Point("LEFT", f.Option2, "RIGHT", 4, 0)
+ f.Option3:SetText("")
+ f.Option3:Hide()
+ f.Option3:SetScript("OnShow", function()
+ f.Option1:Width(100)
+ f.Option1:ClearAllPoints()
+ f.Option1:Point("RIGHT", f.Option2, "LEFT", -4, 0)
+ f.Option2:Width(100)
+ f.Option2:ClearAllPoints()
+ f.Option2:Point("BOTTOM", f, "BOTTOM", 0, 45)
+ end)
+ f.Option3:SetScript("OnHide", function()
+ f.Option1:Width(160)
+ f.Option1:ClearAllPoints()
+ f.Option1:Point("BOTTOM", 0, 45)
+ f.Option2:Width(110)
+ f.Option2:ClearAllPoints()
+ f.Option2:Point("BOTTOMLEFT", f, "BOTTOM", 4, 45)
+ end)
+ S:HandleButton(f.Option3, true)
+
+ f.Option4 = CreateFrame("Button", "InstallOption4Button", f, "UIPanelButtonTemplate")
+ f.Option4:Size(100, 30)
+ f.Option4:Point("LEFT", f.Option3, "RIGHT", 4, 0)
+ f.Option4:SetText("")
+ f.Option4:Hide()
+ f.Option4:SetScript("OnShow", function()
+ f.Option1:Width(100)
+ f.Option1:ClearAllPoints()
+ f.Option1:Point("RIGHT", f.Option2, "LEFT", -4, 0)
+ f.Option2:Width(100)
+ f.Option2:ClearAllPoints()
+ f.Option2:Point("BOTTOMRIGHT", f, "BOTTOM", -4, 45)
+ end)
+ f.Option4:SetScript("OnHide", function()
+ f.Option1:Width(160)
+ f.Option1:ClearAllPoints()
+ f.Option1:Point("BOTTOM", 0, 45)
+ f.Option2:Width(110)
+ f.Option2:ClearAllPoints()
+ f.Option2:Point("BOTTOMLEFT", f, "BOTTOM", 4, 45)
+ end)
+ S:HandleButton(f.Option4, true)
+
+ f.SubTitle = f:CreateFontString(nil, "OVERLAY")
+ f.SubTitle:FontTemplate(nil, 15, nil)
+ f.SubTitle:Point("TOP", 0, -40)
+
+ f.Desc1 = f:CreateFontString(nil, "OVERLAY")
+ f.Desc1:FontTemplate()
+ f.Desc1:Point("TOPLEFT", 20, -75)
+ f.Desc1:Width(f:GetWidth() - 40)
+
+ f.Desc2 = f:CreateFontString(nil, "OVERLAY")
+ f.Desc2:FontTemplate()
+ f.Desc2:Point("TOPLEFT", 20, -125)
+ f.Desc2:Width(f:GetWidth() - 40)
+
+ f.Desc3 = f:CreateFontString(nil, "OVERLAY")
+ f.Desc3:FontTemplate()
+ f.Desc3:Point("TOPLEFT", 20, -175)
+ f.Desc3:Width(f:GetWidth() - 40)
+
+ local closeButton = CreateFrame("Button", "InstallCloseButton", f, "UIPanelCloseButton")
+ closeButton:Point("TOPRIGHT", f, "TOPRIGHT")
+ closeButton:SetScript("OnClick", function() f:Hide() end)
+ S:HandleCloseButton(closeButton)
+
+ f.tutorialImage = f:CreateTexture("InstallTutorialImage", "OVERLAY")
+ f.tutorialImage:Size(256, 128)
+ f.tutorialImage:SetTexture(E.Media.Textures.Logo)
+ f.tutorialImage:Point("BOTTOM", 0, 70)
+ end
+
+ ElvUIInstallFrame:Show()
+ NextPage()
+end
\ No newline at end of file
diff --git a/ElvUI/Core/Load_Core.xml b/ElvUI/Core/Load_Core.xml
new file mode 100644
index 0000000..a679d66
--- /dev/null
+++ b/ElvUI/Core/Load_Core.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Core/Math.lua b/ElvUI/Core/Math.lua
new file mode 100644
index 0000000..3395956
--- /dev/null
+++ b/ElvUI/Core/Math.lua
@@ -0,0 +1,460 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+--Lua functions
+local pairs, ipairs = pairs, ipairs
+local next, select, type, unpack = next, select, type, unpack
+local tonumber, tostring = tonumber, tostring
+local abs, ceil, floor, fmod, modf = math.abs, math.ceil, math.floor, math.fmod, math.modf
+local byte, format, gmatch, gsub, strupper, strsub = string.byte, string.format, string.gmatch, string.gsub, strupper, strsub
+local utf8sub = string.utf8sub
+local tinsert, tremove, wipe = table.insert, table.remove, table.wipe
+
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetScreenWidth, GetScreenHeight = GetScreenWidth, GetScreenHeight
+
+E.ShortPrefixValues = {}
+E.ShortPrefixStyles = {
+ ["CHINESE"] = {{1e8, "Y"}, {1e4, "W"}},
+ ["ENGLISH"] = {{1e12, "T"}, {1e9, "B"}, {1e6, "M"}, {1e3, "K"}},
+ ["GERMAN"] = {{1e12, "Bio"}, {1e9, "Mrd"}, {1e6, "Mio"}, {1e3, "Tsd"}},
+ ["KOREAN"] = {{1e8, "억"}, {1e4, "만"}, {1e3, "천"}},
+ ["METRIC"] = {{1e12, "T"}, {1e9, "G"}, {1e6, "M"}, {1e3, "k"}}
+}
+
+E.GetFormattedTextStyles = {
+ ["CURRENT"] = "%s",
+ ["CURRENT_MAX"] = "%s - %s",
+ ["CURRENT_PERCENT"] = "%s - %.1f%%",
+ ["CURRENT_MAX_PERCENT"] = "%s - %s | %.1f%%",
+ ["PERCENT"] = "%.1f%%",
+ ["DEFICIT"] = "-%s"
+}
+
+function E:BuildPrefixValues()
+ if next(E.ShortPrefixValues) then wipe(E.ShortPrefixValues) end
+
+ E.ShortPrefixValues = E:CopyTable(E.ShortPrefixValues, E.ShortPrefixStyles[E.db.general.numberPrefixStyle])
+ E.ShortValueDec = format("%%.%df", E.db.general.decimalLength or 1)
+
+ for _, style in ipairs(E.ShortPrefixValues) do
+ style[2] = E.ShortValueDec..style[2]
+ end
+
+ local gftDec = tostring(E.db.general.decimalLength or 1)
+ for style, str in pairs(E.GetFormattedTextStyles) do
+ E.GetFormattedTextStyles[style] = gsub(str, "%d", gftDec)
+ end
+end
+
+--Return short value of a number
+function E:ShortValue(v)
+ local abs_v = v < 0 and -v or v
+ for i = 1, #E.ShortPrefixValues do
+ if abs_v >= E.ShortPrefixValues[i][1] then
+ return format(E.ShortPrefixValues[i][2], v / E.ShortPrefixValues[i][1])
+ end
+ end
+
+ return format("%.0f", v)
+end
+
+function E:IsEvenNumber(num)
+ return num % 2 == 0
+end
+
+-- http://www.wowwiki.com/ColorGradient
+function E:ColorGradient(perc, ...)
+ if perc >= 1 then
+ return select(select("#", ...) - 2, ...)
+ elseif perc <= 0 then
+ return ...
+ end
+
+ local num = select("#", ...) / 3
+ local segment, relperc = modf(perc*(num - 1))
+ local r1, g1, b1, r2, g2, b2 = select((segment*3) + 1, ...)
+
+ return r1 + (r2 - r1)*relperc, g1 + (g2 - g1)*relperc, b1 + (b2 - b1)*relperc
+end
+
+--Return rounded number
+function E:Round(num, idp)
+ if idp and idp > 0 then
+ local mult = 10 ^ idp
+ return floor(num * mult + 0.5) / mult
+ end
+ return floor(num + 0.5)
+end
+
+--Truncate a number off to n places
+function E:Truncate(v, decimals)
+ return v - (v % (0.1 ^ (decimals or 0)))
+end
+
+--RGB to Hex
+function E:RGBToHex(r, g, b)
+ r = r <= 1 and r >= 0 and r or 1
+ g = g <= 1 and g >= 0 and g or 1
+ b = b <= 1 and b >= 0 and b or 1
+ return format("|cff%02x%02x%02x", r*255, g*255, b*255)
+end
+
+--Hex to RGB
+function E:HexToRGB(hex)
+ local rhex, ghex, bhex = strsub(hex, 1, 2), strsub(hex, 3, 4), strsub(hex, 5, 6)
+ return tonumber(rhex, 16), tonumber(ghex, 16), tonumber(bhex, 16)
+end
+
+--From http://wow.gamepedia.com/UI_coordinates
+function E:FramesOverlap(frameA, frameB)
+ if not frameA or not frameB then return end
+
+ local sA, sB = frameA:GetEffectiveScale(), frameB:GetEffectiveScale()
+ if not sA or not sB then return end
+
+ local frameALeft, frameARight, frameABottom, frameATop = frameA:GetLeft(), frameA:GetRight(), frameA:GetBottom(), frameA:GetTop()
+ local frameBLeft, frameBRight, frameBBottom, frameBTop = frameB:GetLeft(), frameB:GetRight(), frameB:GetBottom(), frameB:GetTop()
+ if not (frameALeft and frameARight and frameABottom and frameATop) then return end
+ if not (frameBLeft and frameBRight and frameBBottom and frameBTop) then return end
+
+ return ((frameALeft*sA) < (frameBRight*sB)) and ((frameBLeft*sB) < (frameARight*sA)) and ((frameABottom*sA) < (frameBTop*sB)) and ((frameBBottom*sB) < (frameATop*sA))
+end
+
+function E:GetScreenQuadrant(frame)
+ local x, y = frame:GetCenter()
+ local screenWidth = GetScreenWidth()
+ local screenHeight = GetScreenHeight()
+
+ if not (x and y) then
+ return "UNKNOWN", frame:GetName()
+ end
+
+ local point
+ if (x > (screenWidth / 3) and x < (screenWidth / 3)*2) and y > (screenHeight / 3)*2 then
+ point = "TOP"
+ elseif x < (screenWidth / 3) and y > (screenHeight / 3)*2 then
+ point = "TOPLEFT"
+ elseif x > (screenWidth / 3)*2 and y > (screenHeight / 3)*2 then
+ point = "TOPRIGHT"
+ elseif (x > (screenWidth / 3) and x < (screenWidth / 3)*2) and y < (screenHeight / 3) then
+ point = "BOTTOM"
+ elseif x < (screenWidth / 3) and y < (screenHeight / 3) then
+ point = "BOTTOMLEFT"
+ elseif x > (screenWidth / 3)*2 and y < (screenHeight / 3) then
+ point = "BOTTOMRIGHT"
+ elseif x < (screenWidth / 3) and (y > (screenHeight / 3) and y < (screenHeight / 3)*2) then
+ point = "LEFT"
+ elseif x > (screenWidth / 3)*2 and y < (screenHeight / 3)*2 and y > (screenHeight / 3) then
+ point = "RIGHT"
+ else
+ point = "CENTER"
+ end
+
+ return point
+end
+
+function E:GetXYOffset(position, override)
+ local default = E.Spacing
+ local x, y = override or default, override or default
+
+ if position == "TOP" then
+ return 0, y
+ elseif position == "TOPLEFT" then
+ return x, y
+ elseif position == "TOPRIGHT" then
+ return -x, y
+ elseif position == "BOTTOM" then
+ return 0, -y
+ elseif position == "BOTTOMLEFT" then
+ return x, -y
+ elseif position == "BOTTOMRIGHT" then
+ return -x, -y
+ elseif position == "LEFT" then
+ return -x, 0
+ elseif position == "RIGHT" then
+ return x, 0
+ elseif position == "CENTER" then
+ return 0, 0
+ end
+end
+
+function E:GetFormattedText(style, min, max, dec)
+ if max == 0 then max = 1 end
+
+ if style == "CURRENT" or ((style == "CURRENT_MAX" or style == "CURRENT_MAX_PERCENT" or style == "CURRENT_PERCENT") and min == max) then
+ return format(E.GetFormattedTextStyles.CURRENT, E:ShortValue(min, dec))
+ else
+ local useStyle = E.GetFormattedTextStyles[style]
+ if not useStyle then return end
+
+ if style == "DEFICIT" then
+ local deficit = max - min
+ return (deficit > 0 and format(useStyle, E:ShortValue(deficit, dec))) or ""
+ elseif style == "CURRENT_MAX" then
+ return format(useStyle, E:ShortValue(min, dec), E:ShortValue(max, dec))
+ elseif style == "PERCENT" or style == "CURRENT_PERCENT" or style == "CURRENT_MAX_PERCENT" then
+ if dec then useStyle = gsub(useStyle, "%d", tonumber(dec) or 0) end
+ local perc = min / max * 100
+
+ if style == "PERCENT" then
+ return format(useStyle, perc)
+ elseif style == "CURRENT_PERCENT" then
+ return format(useStyle, E:ShortValue(min, dec), perc)
+ elseif style == "CURRENT_MAX_PERCENT" then
+ return format(useStyle, E:ShortValue(min, dec), E:ShortValue(max, dec), perc)
+ end
+ end
+ end
+end
+
+function E:ShortenString(str, numChars, dots)
+ local bytes = #str
+ if bytes <= numChars then
+ return str
+ else
+ local len, pos = 0, 1
+ while pos <= bytes do
+ len = len + 1
+ local c = byte(str, pos)
+ if c > 0 and c <= 127 then
+ pos = pos + 1
+ elseif c >= 192 and c <= 223 then
+ pos = pos + 2
+ elseif c >= 224 and c <= 239 then
+ pos = pos + 3
+ elseif c >= 240 and c <= 247 then
+ pos = pos + 4
+ end
+ if len == numChars then
+ break
+ end
+ end
+
+ if len == numChars and pos <= bytes then
+ return strsub(str, 1, pos - 1)..(dots and "..." or "")
+ else
+ return str
+ end
+ end
+end
+
+function E:AbbreviateString(str, allUpper)
+ local newString = ""
+ for word in gmatch(str, "[^%s]+") do
+ word = utf8sub(word, 1, 1) --get only first letter of each word
+ if allUpper then word = strupper(word) end
+ newString = newString..word
+ end
+
+ return newString
+end
+
+function E:WaitFunc(elapsed)
+ local total = #E.WaitTable
+ local i = 1
+
+ while i <= total do
+ local data = E.WaitTable[i]
+
+ if data[1] > elapsed then
+ data[1] = data[1] - elapsed
+ i = i + 1
+ else
+ tremove(E.WaitTable, i)
+
+ if data[3] then
+ if data[3] > 1 then
+ data[2](unpack(data[4], 1, data[3]))
+ else
+ data[2](data[4])
+ end
+ else
+ data[2]()
+ end
+
+ total = total - 1
+ end
+ end
+
+ if #E.WaitTable == 0 then
+ self:Hide()
+ end
+end
+
+E.WaitTable = {}
+E.WaitFrame = CreateFrame("Frame", "ElvUI_WaitFrame", UIParent)
+E.WaitFrame:SetScript("OnUpdate", E.WaitFunc)
+
+--Add time before calling a function
+function E:Delay(delay, func, ...)
+ if type(delay) ~= "number" then
+ error(format("Bad argument #1 to 'Delay' (number expected, got %s)", delay ~= nil and type(delay) or "no value"), 2)
+ elseif type(func) ~= "function" then
+ error(format("Bad argument #2 to 'Delay' (function expected, got %s)", func ~= nil and type(func) or "no value"), 2)
+ end
+
+ local argCount = select("#", ...)
+
+ tinsert(E.WaitTable, {
+ delay,
+ func,
+ argCount > 0 and argCount,
+ argCount == 1 and (...) or argCount > 1 and {...}
+ })
+
+ E.WaitFrame:Show()
+
+ return true
+end
+
+function E:StringTitle(str)
+ return gsub(str, "(.)", strupper, 1)
+end
+
+E.TimeThreshold = 3
+
+E.TimeColors = { --aura time colors
+ [0] = "|cffeeeeee", --days
+ [1] = "|cffeeeeee", --hours
+ [2] = "|cffeeeeee", --minutes
+ [3] = "|cffeeeeee", --seconds
+ [4] = "|cfffe0000", --expire (fade timer)
+ [5] = "|cff909090", --mmss
+ [6] = "|cff707070", --hhmm
+}
+
+E.TimeFormats = { -- short / indicator color
+ [0] = {"%dd", "%d%sd|r"},
+ [1] = {"%dh", "%d%sh|r"},
+ [2] = {"%dm", "%d%sm|r"},
+ [3] = {"%ds", "%d%ss|r"},
+ [4] = {"%.1fs", "%.1f%ss|r"},
+ [5] = {"%d:%02d", "%d%s:|r%02d"}, --mmss
+ [6] = {"%d:%02d", "%d%s:|r%02d"}, --hhmm
+}
+
+for _, x in pairs(E.TimeFormats) do
+ x[3] = gsub(x[1], "s$", "") -- 1 without seconds
+ x[4] = gsub(x[2], "%%ss", "%%s") -- 2 without seconds
+end
+
+E.TimeIndicatorColors = {
+ [0] = "|cff00b3ff",
+ [1] = "|cff00b3ff",
+ [2] = "|cff00b3ff",
+ [3] = "|cff00b3ff",
+ [4] = "|cff00b3ff",
+ [5] = "|cff00b3ff",
+ [6] = "|cff00b3ff",
+}
+
+local DAY, HOUR, MINUTE = 86400, 3600, 60 --used for calculating aura time text
+local DAYISH, HOURISH, MINUTEISH = HOUR * 23.5, MINUTE * 59.5, 59.5 --used for caclculating aura time at transition points
+local HALFDAYISH, HALFHOURISH, HALFMINUTEISH = DAY/2 + 0.5, HOUR/2 + 0.5, MINUTE/2 + 0.5 --used for calculating next update times
+
+-- will return the the value to display, the formatter id to use and calculates the next update for the Aura
+function E:GetTimeInfo(s, threshhold, hhmm, mmss)
+ if s < MINUTE then
+ if s >= threshhold then
+ return floor(s), 3, 0.51
+ else
+ return s, 4, 0.051
+ end
+ elseif s < HOUR then
+ if mmss and s < mmss then
+ return s/MINUTE, 5, 0.51, s%MINUTE
+ else
+ local minutes = floor((s/MINUTE)+.5)
+ if hhmm and s < (hhmm * MINUTE) and 60 < minutes then
+ return s/HOUR, 6, minutes > 1 and (s - (minutes*MINUTE - HALFMINUTEISH)) or (s - MINUTEISH), minutes%MINUTE
+ else
+ return ceil(s / MINUTE), 2, minutes > 1 and (s - (minutes*MINUTE - HALFMINUTEISH)) or (s - MINUTEISH)
+ end
+ end
+ elseif s < DAY then
+ if mmss and s < mmss then
+ return s/MINUTE, 5, 0.51, s%MINUTE
+ else
+ local minutes = floor((s/MINUTE)+.5)
+ if hhmm and s < (hhmm * MINUTE) and 60 < minutes then
+ return s/HOUR, 6, minutes > 1 and (s - (minutes*MINUTE - HALFMINUTEISH)) or (s - MINUTEISH), minutes%MINUTE
+ else
+ local hours = floor((s/HOUR)+.5)
+ return ceil(s / HOUR), 1, hours > 1 and (s - (hours*HOUR - HALFHOURISH)) or (s - HOURISH)
+ end
+ end
+ else
+ local days = floor((s/DAY)+.5)
+ return ceil(s / DAY), 0, days > 1 and (s - (days*DAY - HALFDAYISH)) or (s - DAYISH)
+ end
+end
+
+--Money text formatting, code taken from Scrooge by thelibrarian (http://www.wowace.com/addons/scrooge/)
+local COLOR_COPPER, COLOR_SILVER, COLOR_GOLD = "|cffeda55f", "|cffc7c7cf", "|cffffd700"
+local ICON_COPPER = "|TInterface\\MoneyFrame\\UI-CopperIcon:12:12|t"
+local ICON_SILVER = "|TInterface\\MoneyFrame\\UI-SilverIcon:12:12|t"
+local ICON_GOLD = "|TInterface\\MoneyFrame\\UI-GoldIcon:12:12|t"
+function E:FormatMoney(amount, style, textonly)
+ local coppername = textonly and L["copperabbrev"] or ICON_COPPER
+ local silvername = textonly and L["silverabbrev"] or ICON_SILVER
+ local goldname = textonly and L["goldabbrev"] or ICON_GOLD
+
+ local value = abs(amount)
+ local gold = floor(value / 10000)
+ local silver = floor(fmod(value / 100, 100))
+ local copper = floor(fmod(value, 100))
+
+ if not style or style == "SMART" then
+ local str = ""
+ if gold > 0 then str = format("%d%s%s", gold, goldname, (silver > 0 or copper > 0) and " " or "") end
+ if silver > 0 then str = format("%s%d%s%s", str, silver, silvername, copper > 0 and " " or "") end
+ if copper > 0 or value == 0 then str = format("%s%d%s", str, copper, coppername) end
+ return str
+ end
+
+ if style == "FULL" then
+ if gold > 0 then
+ return format("%d%s %d%s %d%s", gold, goldname, silver, silvername, copper, coppername)
+ elseif silver > 0 then
+ return format("%d%s %d%s", silver, silvername, copper, coppername)
+ else
+ return format("%d%s", copper, coppername)
+ end
+ elseif style == "SHORT" then
+ if gold > 0 then
+ return format("%.1f%s", amount / 10000, goldname)
+ elseif silver > 0 then
+ return format("%.1f%s", amount / 100, silvername)
+ else
+ return format("%d%s", amount, coppername)
+ end
+ elseif style == "SHORTINT" then
+ if gold > 0 then
+ return format("%d%s", gold, goldname)
+ elseif silver > 0 then
+ return format("%d%s", silver, silvername)
+ else
+ return format("%d%s", copper, coppername)
+ end
+ elseif style == "CONDENSED" then
+ if gold > 0 then
+ return format("%s%d|r.%s%02d|r.%s%02d|r", COLOR_GOLD, gold, COLOR_SILVER, silver, COLOR_COPPER, copper)
+ elseif silver > 0 then
+ return format("%s%d|r.%s%02d|r", COLOR_SILVER, silver, COLOR_COPPER, copper)
+ else
+ return format("%s%d|r", COLOR_COPPER, copper)
+ end
+ elseif style == "BLIZZARD" then
+ if gold > 0 then
+ return format("%s%s %d%s %d%s", gold, goldname, silver, silvername, copper, coppername)
+ elseif silver > 0 then
+ return format("%d%s %d%s", silver, silvername, copper, coppername)
+ else
+ return format("%d%s", copper, coppername)
+ end
+ end
+
+ -- Shouldn't be here; punt
+ return self:FormatMoney(amount, "SMART")
+end
\ No newline at end of file
diff --git a/ElvUI/Core/ModuleCopy.lua b/ElvUI/Core/ModuleCopy.lua
new file mode 100644
index 0000000..d039a9d
--- /dev/null
+++ b/ElvUI/Core/ModuleCopy.lua
@@ -0,0 +1,276 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local MC = E:GetModule("ModuleCopy")
+
+--Lua functions
+local pairs, next, type = pairs, next, type
+local format, error = format, error
+--WoW API / Variables
+-- GLOBALS: ElvDB
+
+--This table to reserve settings names in E.global.profileCopy. Used in export/imports functions
+--Pligins can add own values for their internal settings for safechecks here
+MC.InternalOptions = {
+ ["selected"] = true,
+ ["movers"] = true,
+}
+
+--Default template for a config group for a single module.
+--Contains header, general group toggle (shown only if the setting actually exists) and imports button.
+--Usage as seen in ElvUI_OptionsUI\modulecopy.lua
+function MC:CreateModuleConfigGroup(Name, section, pluginSection)
+ local config = {
+ order = 10,
+ type = "group",
+ name = Name,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = Name
+ },
+ general = {
+ order = 1,
+ type = "toggle",
+ name = L["General"]
+ },
+ PreButtonSpacer = {
+ order = 200,
+ type = "description",
+ name = ""
+ },
+ import = {
+ order = 201,
+ type = "execute",
+ name = L["Import Now"],
+ func = function()
+ E.PopupDialogs.MODULE_COPY_CONFIRM.text = format(L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"], Name, E.global.profileCopy.selected, ElvDB.profileKeys[E.myname.." - "..E.myrealm])
+ E.PopupDialogs.MODULE_COPY_CONFIRM.OnAccept = function()
+ MC:ImportFromProfile(section, pluginSection)
+ end
+ E:StaticPopup_Show("MODULE_COPY_CONFIRM")
+ end
+ },
+ export = {
+ order = 202,
+ type = "execute",
+ name = L["Export Now"],
+ func = function()
+ E.PopupDialogs.MODULE_COPY_CONFIRM.text = format(L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"], Name, ElvDB.profileKeys[E.myname.." - "..E.myrealm], E.global.profileCopy.selected)
+ E.PopupDialogs.MODULE_COPY_CONFIRM.OnAccept = function()
+ MC:ExportToProfile(section, pluginSection)
+ end
+ E:StaticPopup_Show("MODULE_COPY_CONFIRM")
+ end
+ }
+ }
+ }
+ if pluginSection then
+ config.args.general.hidden = function(info) return E.global.profileCopy[pluginSection][section][ info[#info] ] == nil end
+ config.args.general.get = function(info) return E.global.profileCopy[pluginSection][section][ info[#info] ] end
+ config.args.general.set = function(info, value) E.global.profileCopy[pluginSection][section][ info[#info] ] = value end
+ else
+ config.args.general.hidden = function(info) return E.global.profileCopy[section][ info[#info] ] == nil end
+ config.args.general.get = function(info) return E.global.profileCopy[section][ info[#info] ] end
+ config.args.general.set = function(info, value) E.global.profileCopy[section][ info[#info] ] = value end
+ end
+
+ return config
+end
+
+function MC:CreateMoversConfigGroup()
+ local config = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["On screen positions for different elements."]
+ },
+ PreButtonSpacer = {
+ order = 200,
+ type = "description",
+ name = ""
+ },
+ import = {
+ order = 201,
+ type = "execute",
+ name = L["Import Now"],
+ func = function()
+ E.PopupDialogs.MODULE_COPY_CONFIRM.text = format(L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"], L["Movers"], E.global.profileCopy.selected, ElvDB.profileKeys[E.myname.." - "..E.myrealm])
+ E.PopupDialogs.MODULE_COPY_CONFIRM.OnAccept = function()
+ MC:CopyMovers("import")
+ end
+ E:StaticPopup_Show("MODULE_COPY_CONFIRM")
+ end
+ },
+ export = {
+ order = 202,
+ type = "execute",
+ name = L["Export Now"],
+ func = function()
+ E.PopupDialogs.MODULE_COPY_CONFIRM.text = format(L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"], L["Movers"], ElvDB.profileKeys[E.myname.." - "..E.myrealm], E.global.profileCopy.selected)
+ E.PopupDialogs.MODULE_COPY_CONFIRM.OnAccept = function()
+ MC:CopyMovers("export")
+ end
+ E:StaticPopup_Show("MODULE_COPY_CONFIRM")
+ end
+ }
+ }
+ for moverName, data in pairs(E.CreatedMovers) do
+ if not G.profileCopy.movers[moverName] then G.profileCopy.movers[moverName] = false end
+ config[moverName] = {
+ order = 1,
+ type = "toggle",
+ name = data.text,
+ get = function(info) return E.global.profileCopy.movers[moverName] end,
+ set = function(info, value) E.global.profileCopy.movers[moverName] = value end
+ }
+ end
+ for moverName, data in pairs(E.DisabledMovers) do
+ if not G.profileCopy.movers[moverName] then G.profileCopy.movers[moverName] = false end
+ config[moverName] = {
+ order = 1,
+ type = "toggle",
+ name = data.text,
+ get = function(info) return E.global.profileCopy.movers[moverName] end,
+ set = function(info, value) E.global.profileCopy.movers[moverName] = value end
+ }
+ end
+
+ return config
+end
+
+function MC:CopyTable(CopyFrom, CopyTo, CopyDefault, module)
+ for key, value in pairs(CopyTo) do
+ if type(value) ~= "table" then
+ if module == true or (type(module) == "table" and (module.general == nil or (not CopyTo.general and module.general))) then --Some dark magic of a logic to figure out stuff
+ --This check is to see if the profile we are copying from has keys absent from defaults.
+ --If key exists, then copy. If not, then clear obsolite key from the profile.
+ if CopyDefault[key] ~= nil then
+ CopyTo[key] = CopyFrom[key] or CopyDefault[key]
+ else
+ CopyFrom[key] = nil
+ end
+ end
+ else
+ if module == true then --Copy over entire section of profile subgroup
+ E:CopyTable(CopyTo, CopyDefault)
+ E:CopyTable(CopyTo, CopyFrom)
+ elseif type(module) == "table" and module[key] ~= nil then
+ --Making sure tables actually exist in profiles (e.g absent values in ElvDB.profiles are for default values)
+ CopyFrom[key], CopyTo[key] = MC:TablesExist(CopyFrom[key], CopyTo[key], CopyDefault[key])
+ --If key exists, then copy. If not, then clear obsolite key from the profile.
+ --Someone should double check this logic. Cause for single keys it is fine, but I'm no sure bout whole tables @Darth
+ if CopyFrom[key] ~= nil then
+ MC:CopyTable(CopyFrom[key], CopyTo[key], CopyDefault[key], module[key])
+ else
+ CopyTo[key] = nil
+ end
+ end
+ end
+ end
+end
+
+--[[
+* Valid copy templates should be as follows
+G.profileCopy[YourOptionGroupName] = {
+ [SubGroupName1] = true,
+ [SubGroupName2] = true,
+ ...
+}
+* For example
+G.profileCopy.auras = {
+ ["general"] = true,
+ ["buffs"] = true,
+ ["debuffs"] = true,
+ ["cooldown"] = true,
+}
+* "general" key can refer to a similar named subtable or all non-table variables inside your group
+* If you leave the table as G.profileCopy[YourOptionGroupName] = {}, this will result in no valid copy template error.
+* If set to G.profileCopy[YourOptionGroupName] = true, then this will copy everything without selecting
+any particular subcategory from your settings table.
+* Plugins can use "pluginSection" argument to determain their own table if they keep settings apart from core ElvUI settings.
+Examples S&L uses "sle" table, MerathilisUI uses "mui" table, BenikUI uses "benikui" and core table
+]]
+
+function MC:TablesExist(CopyFrom, CopyTo, CopyDefault)
+ if not CopyFrom then CopyFrom = CopyDefault end
+ if not CopyTo then CopyTo = CopyDefault end
+ return CopyFrom, CopyTo
+end
+
+function MC:ImportFromProfile(section, pluginSection)
+ --Some checks for the occasion someone passes wrong stuff
+ if not section then error("No profile section provided. Usage MC:ImportFromProfile(\"section\")") end
+ if not pluginSection and MC.InternalOptions[section] then error(format("Section name could not be \"%s\". This name is reserved for internal setting"), section) end
+ if pluginSection and (MC.InternalOptions[pluginSection] and MC.InternalOptions[pluginSection][section]) then error(format("Section name for plugin group \"%s\" could not be \"%s\". This name is reserved for internal setting"), pluginSection, section) end
+
+ local module = pluginSection and E.global.profileCopy[pluginSection][section] or E.global.profileCopy[section]
+ if not module then error(format("Provided section name \"%s\" does not have a template for profile copy.", section)) end
+ --Starting digging through the settings
+ local CopyFrom = pluginSection and (ElvDB.profiles[E.global.profileCopy.selected][pluginSection] and ElvDB.profiles[E.global.profileCopy.selected][pluginSection][section] or P[pluginSection][section]) or ElvDB.profiles[E.global.profileCopy.selected][section]
+ local CopyTo = pluginSection and E.db[pluginSection][section] or E.db[section]
+ local CopyDefault = pluginSection and P[pluginSection][section] or P[section]
+ --Making sure tables actually exist in profiles (e.g absent values in ElvDB.profiles are for default values)
+ CopyFrom, CopyTo = MC:TablesExist(CopyFrom, CopyTo, CopyDefault)
+ if type(module) == "table" and next(module) then --This module is not an empty table
+ MC:CopyTable(CopyFrom, CopyTo, CopyDefault, module)
+ elseif type(module) == "boolean" then --Copy over entire section of profile subgroup
+ E:CopyTable(CopyTo, CopyDefault)
+ E:CopyTable(CopyTo, CopyFrom)
+ else
+ error(format("Provided section name \"%s\" does not have a valid copy template.", section))
+ end
+ E:UpdateAll(true)
+end
+
+function MC:ExportToProfile(section, pluginSection)
+ --Some checks for the occasion someone passes wrong stuff
+ if not section then error("No profile section provided. Usage MC:ExportToProfile(\"section\")") end
+ if not pluginSection and MC.InternalOptions[section] then error(format("Section name could not be \"%s\". This name is reserved for internal setting"), section) end
+ if pluginSection and MC.InternalOptions[pluginSection][section] then error(format("Section name for plugin group \"%s\" could not be \"%s\". This name is reserved for internal setting"), pluginSection, section) end
+
+ local module = pluginSection and E.global.profileCopy[pluginSection][section] or E.global.profileCopy[section]
+ if not module then error(format("Provided section name \"%s\" does not have a template for profile copy.", section)) end
+ --Making sure tables actually exist
+ if not ElvDB.profiles[E.global.profileCopy.selected][section] then ElvDB.profiles[E.global.profileCopy.selected][section] = {} end
+ if not E.db[section] then E.db[section] = {} end
+ --Starting digging through the settings
+ local CopyFrom = pluginSection and E.db[pluginSection][section] or E.db[section]
+ local CopyTo = pluginSection and ElvDB.profiles[E.global.profileCopy.selected][pluginSection][section] or ElvDB.profiles[E.global.profileCopy.selected][section]
+ local CopyDefault = pluginSection and P[pluginSection][section] or P[section]
+ if type(module) == "table" and next(module) then --This module is not an empty table
+ MC:CopyTable(CopyFrom, CopyTo, CopyDefault, module)
+ elseif type(module) == "boolean" then --Copy over entire section of profile subgroup
+ E:CopyTable(CopyTo, CopyDefault)
+ E:CopyTable(CopyTo, CopyFrom)
+ else
+ error(format("Provided section name \"%s\" does not have a valid copy template.", section))
+ end
+end
+
+function MC:CopyMovers(mode)
+ if not E.db.movers then E.db.movers = {} end --Nothing was moved in cutrrent profile
+ if not ElvDB.profiles[E.global.profileCopy.selected].movers then ElvDB.profiles[E.global.profileCopy.selected].movers = {} end --Nothing was moved in selected profile
+ local CopyFrom, CopyTo
+ if mode == "export" then
+ CopyFrom, CopyTo = E.db.movers, ElvDB.profiles[E.global.profileCopy.selected].movers
+ else
+ CopyFrom, CopyTo = ElvDB.profiles[E.global.profileCopy.selected].movers or {}, E.db.movers
+ end
+
+ for moverName in pairs(E.CreatedMovers) do
+ if E.global.profileCopy.movers[moverName] then
+ CopyTo[moverName] = CopyFrom[moverName]
+ end
+ end
+ E:SetMoversPositions()
+end
+
+function MC:Initialize()
+ self.Initialized = true
+end
+
+local function InitializeCallback()
+ MC:Initialize()
+end
+
+E:RegisterModule(MC:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Core/Movers.lua b/ElvUI/Core/Movers.lua
new file mode 100644
index 0000000..cbce9dd
--- /dev/null
+++ b/ElvUI/Core/Movers.lua
@@ -0,0 +1,527 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local Sticky = E.Libs.SimpleSticky
+
+--Lua functions
+local _G = _G
+local type, unpack, pairs, error = type, unpack, pairs, error
+local format, split, find = format, strsplit, strfind
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local InCombatLockdown = InCombatLockdown
+local IsControlKeyDown = IsControlKeyDown
+local IsShiftKeyDown = IsShiftKeyDown
+local ERR_NOT_IN_COMBAT = ERR_NOT_IN_COMBAT
+
+E.CreatedMovers = {}
+E.DisabledMovers = {}
+
+local function SizeChanged(frame)
+ if InCombatLockdown() then return end
+
+ if frame.dirtyWidth and frame.dirtyHeight then
+ frame.mover:Size(frame.dirtyWidth, frame.dirtyHeight)
+ else
+ frame.mover:Size(frame:GetSize())
+ end
+end
+
+local function GetPoint(obj)
+ local point, anchor, secondaryPoint, x, y = obj:GetPoint()
+ if not anchor then anchor = E.UIParent end
+
+ return format("%s,%s,%s,%d,%d", point, anchor:GetName(), secondaryPoint, E:Round(x), E:Round(y))
+end
+
+local function UpdateCoords(self)
+ local mover = self.child
+ local x, y, _, nudgePoint, nudgeInversePoint = E:CalculateMoverPoints(mover)
+
+ local coordX, coordY = E:GetXYOffset(nudgeInversePoint, 1)
+ ElvUIMoverNudgeWindow:ClearAllPoints()
+ ElvUIMoverNudgeWindow:Point(nudgePoint, mover, nudgeInversePoint, coordX, coordY)
+ E:UpdateNudgeFrame(mover, x, y)
+end
+
+local isDragging = false
+local coordFrame = CreateFrame("Frame")
+coordFrame:SetScript("OnUpdate", UpdateCoords)
+coordFrame:Hide()
+
+local function CreateMover(parent, name, text, overlay, snapOffset, postdrag, shouldDisable, configString)
+ if not parent then return end --If for some reason the parent isnt loaded yet
+ if E.CreatedMovers[name].Created then return end
+
+ if overlay == nil then overlay = true end
+ local point, anchor, secondaryPoint, x, y = split(",", GetPoint(parent))
+
+ --Use dirtyWidth / dirtyHeight to set initial size if possible
+ local width = parent.dirtyWidth or parent:GetWidth()
+ local height = parent.dirtyHeight or parent:GetHeight()
+
+ local f = CreateFrame("Button", name, E.UIParent)
+ f:SetClampedToScreen(true)
+ f:RegisterForDrag("LeftButton", "RightButton")
+ f:EnableMouseWheel(true)
+ f:SetMovable(true)
+ f:Width(width)
+ f:Height(height)
+ f:SetTemplate("Transparent", nil, nil, true)
+ f:Hide()
+ f.parent = parent
+ f.name = name
+ f.textString = text
+ f.postdrag = postdrag
+ f.overlay = overlay
+ f.snapOffset = snapOffset or -2
+ f.shouldDisable = shouldDisable
+ f.configString = configString
+
+ f:SetFrameLevel(parent:GetFrameLevel() + 1)
+ if overlay == true then
+ f:SetFrameStrata("DIALOG")
+ else
+ f:SetFrameStrata("BACKGROUND")
+ end
+
+ E.CreatedMovers[name].mover = f
+ E.snapBars[#E.snapBars + 1] = f
+
+ local fs = f:CreateFontString(nil, "OVERLAY")
+ fs:FontTemplate()
+ fs:SetJustifyH("CENTER")
+ fs:Point("CENTER")
+ fs:SetText(text or name)
+ fs:SetTextColor(unpack(E.media.rgbvaluecolor))
+ f:SetFontString(fs)
+ f.text = fs
+
+ if E.db.movers and E.db.movers[name] then
+ if type(E.db.movers[name]) == "table" then
+ f:Point(E.db.movers[name].p, E.UIParent, E.db.movers[name].p2, E.db.movers[name].p3, E.db.movers[name].p4)
+ E.db.movers[name] = GetPoint(f)
+ f:ClearAllPoints()
+ end
+
+ --Backward compatibility
+ local delim
+ local anchorString = E.db.movers[name]
+ if find(anchorString, "\031") then
+ delim = "\031"
+ elseif find(anchorString, ",") then
+ delim = ","
+ end
+
+ local point1, anchor1, secondaryPoint1, x1, y1 = split(delim, anchorString)
+ f:Point(point1, anchor1, secondaryPoint1, x1, y1)
+ f.anchor = anchor
+ else
+ f:Point(point, anchor, secondaryPoint, x, y)
+ end
+
+ local function OnDragStart(self)
+ if InCombatLockdown() then E:Print(ERR_NOT_IN_COMBAT) return end
+
+ if E.db.general.stickyFrames then
+ Sticky:StartMoving(self, E.snapBars, f.snapOffset, f.snapOffset, f.snapOffset, f.snapOffset)
+ else
+ self:StartMoving()
+ end
+
+ coordFrame.child = self
+ coordFrame:Show()
+ isDragging = true
+ end
+
+ local function OnDragStop(self)
+ if InCombatLockdown() then E:Print(ERR_NOT_IN_COMBAT) return end
+ isDragging = false
+ if E.db.general.stickyFrames then
+ Sticky:StopMoving(self)
+ else
+ self:StopMovingOrSizing()
+ end
+
+ local x2, y2, point2 = E:CalculateMoverPoints(self)
+ self:ClearAllPoints()
+ local overridePoint
+ if self.positionOverride then
+ if self.positionOverride == "BOTTOM" or self.positionOverride == "TOP" then
+ overridePoint = "BOTTOM"
+ else
+ overridePoint = "BOTTOMLEFT"
+ end
+ end
+
+ self:Point(self.positionOverride or point2, E.UIParent, overridePoint and overridePoint or point2, x2, y2)
+ if self.positionOverride then
+ self.parent:ClearAllPoints()
+ self.parent:Point(self.positionOverride, self, self.positionOverride)
+ end
+
+ E:SaveMoverPosition(name)
+
+ if ElvUIMoverNudgeWindow then
+ E:UpdateNudgeFrame(self, x, y)
+ end
+
+ coordFrame.child = nil
+ coordFrame:Hide()
+
+ if postdrag ~= nil and (type(postdrag) == "function") then
+ postdrag(self, E:GetScreenQuadrant(self))
+ end
+
+ self:SetUserPlaced(false)
+ end
+
+ local function OnEnter(self)
+ if isDragging then return end
+
+ self.text:SetTextColor(1, 1, 1)
+ E.AssignFrameToNudge(self)
+ coordFrame.child = self
+ coordFrame:GetScript("OnUpdate")(coordFrame)
+ end
+
+ local function OnMouseDown(self, button)
+ if button == "LeftButton" and not isDragging then
+ if ElvUIMoverNudgeWindow:IsShown() then
+ ElvUIMoverNudgeWindow:Hide()
+ else
+ ElvUIMoverNudgeWindow:Show()
+ end
+ elseif button == "RightButton" then
+ isDragging = false
+ if E.db.general.stickyFrames then
+ Sticky:StopMoving(self)
+ else
+ self:StopMovingOrSizing()
+ end
+
+ --Allow resetting of anchor by Ctrl+RightClick
+ if IsControlKeyDown() and self.textString then
+ E:ResetMovers(self.textString)
+ elseif IsShiftKeyDown() then --Allow hiding a mover temporarily
+ self:Hide()
+ elseif self.configString then --OpenConfig
+ E:ToggleOptionsUI(self.configString)
+ end
+ end
+ end
+
+ local function OnLeave(self)
+ if isDragging then return end
+ self.text:SetTextColor(unpack(E.media.rgbvaluecolor))
+ end
+
+ local function OnShow(self)
+ self:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
+ end
+
+ local function OnMouseWheel(_, delta)
+ if IsShiftKeyDown() then
+ E:NudgeMover(delta)
+ else
+ E:NudgeMover(nil, delta)
+ end
+ end
+
+ f:SetScript("OnDragStart", OnDragStart)
+ f:SetScript("OnMouseUp", E.AssignFrameToNudge)
+ f:SetScript("OnDragStop", OnDragStop)
+ f:SetScript("OnEnter", OnEnter)
+ f:SetScript("OnMouseDown", OnMouseDown)
+ f:SetScript("OnLeave", OnLeave)
+ f:SetScript("OnShow", OnShow)
+ f:SetScript("OnMouseWheel", OnMouseWheel)
+
+ parent:SetScript("OnSizeChanged", SizeChanged)
+ parent.mover = f
+
+ parent:ClearAllPoints()
+ parent:Point(point, f, 0, 0)
+
+ if postdrag ~= nil and type(postdrag) == "function" then
+ f:RegisterEvent("PLAYER_ENTERING_WORLD")
+ f:SetScript("OnEvent", function(self)
+ postdrag(f, E:GetScreenQuadrant(f))
+ self:UnregisterAllEvents()
+ end)
+ end
+
+ E.CreatedMovers[name].Created = true
+end
+
+function E:CalculateMoverPoints(mover, nudgeX, nudgeY)
+ local screenWidth, screenHeight, screenCenter = E.UIParent:GetRight(), E.UIParent:GetTop(), E.UIParent:GetCenter()
+ local x, y = mover:GetCenter()
+
+ local LEFT = screenWidth / 3
+ local RIGHT = screenWidth * 2 / 3
+ local TOP = screenHeight / 2
+ local point, nudgePoint, nudgeInversePoint
+
+ if y >= TOP then
+ point = "TOP"
+ nudgePoint = "TOP"
+ nudgeInversePoint = "BOTTOM"
+ y = -(screenHeight - mover:GetTop())
+ else
+ point = "BOTTOM"
+ nudgePoint = "BOTTOM"
+ nudgeInversePoint = "TOP"
+ y = mover:GetBottom()
+ end
+
+ if x >= RIGHT then
+ point = point.."RIGHT"
+ nudgePoint = "RIGHT"
+ nudgeInversePoint = "LEFT"
+ x = mover:GetRight() - screenWidth
+ elseif x <= LEFT then
+ point = point.."LEFT"
+ nudgePoint = "LEFT"
+ nudgeInversePoint = "RIGHT"
+ x = mover:GetLeft()
+ else
+ x = x - screenCenter
+ end
+
+ if mover.positionOverride and (E.diffGetLeft and E.diffGetRight and E.diffGetTop and E.diffGetBottom) then
+ if mover.positionOverride == "TOPLEFT" then
+ x = mover:GetLeft() - E.diffGetLeft
+ y = mover:GetTop() - E.diffGetTop
+ elseif mover.positionOverride == "TOPRIGHT" then
+ x = mover:GetRight() - E.diffGetRight
+ y = mover:GetTop() - E.diffGetTop
+ elseif mover.positionOverride == "BOTTOMLEFT" then
+ x = mover:GetLeft() - E.diffGetLeft
+ y = mover:GetBottom() - E.diffGetBottom
+ elseif mover.positionOverride == "BOTTOMRIGHT" then
+ x = mover:GetRight() - E.diffGetRight
+ y = mover:GetBottom() - E.diffGetBottom
+ elseif mover.positionOverride == "BOTTOM" then
+ x = mover:GetCenter() - screenCenter
+ y = mover:GetBottom() - E.diffGetBottom
+ elseif mover.positionOverride == "TOP" then
+ x = mover:GetCenter() - screenCenter
+ y = mover:GetTop() - E.diffGetTop
+ end
+ end
+
+ --Update coordinates if nudged
+ x = x + (nudgeX or 0)
+ y = y + (nudgeY or 0)
+
+ return x, y, point, nudgePoint, nudgeInversePoint
+end
+
+function E:UpdatePositionOverride(name)
+ local frame = _G[name]
+ local OnDragStop = frame and frame.GetScript and frame:GetScript("OnDragStop")
+ if OnDragStop then OnDragStop(frame) end
+end
+
+function E:HasMoverBeenMoved(name)
+ if E.db.movers and E.db.movers[name] then
+ return true
+ else
+ return false
+ end
+end
+
+function E:SaveMoverPosition(name)
+ if not _G[name] then return end
+ if not E.db.movers then E.db.movers = {} end
+
+ local mover = _G[name]
+ local _, anchor = mover:GetPoint()
+ mover.anchor = anchor:GetName()
+
+ E.db.movers[name] = GetPoint(mover)
+end
+
+function E:SetMoverSnapOffset(name, offset)
+ if not _G[name] or not E.CreatedMovers[name] then return end
+ E.CreatedMovers[name].mover.snapOffset = offset or -2
+ E.CreatedMovers[name].snapoffset = offset or -2
+end
+
+function E:SaveMoverDefaultPosition(name)
+ if not _G[name] then return end
+
+ E.CreatedMovers[name].point = GetPoint(_G[name])
+ E.CreatedMovers[name].postdrag(_G[name], E:GetScreenQuadrant(_G[name]))
+end
+
+function E:CreateMover(parent, name, text, overlay, snapoffset, postdrag, moverTypes, shouldDisable, configString)
+ if not moverTypes then moverTypes = "ALL,GENERAL" end
+
+ if E.CreatedMovers[name] == nil then
+ E.CreatedMovers[name] = {}
+ E.CreatedMovers[name].parent = parent
+ E.CreatedMovers[name].text = text
+ E.CreatedMovers[name].overlay = overlay
+ E.CreatedMovers[name].postdrag = postdrag
+ E.CreatedMovers[name].snapoffset = snapoffset
+ E.CreatedMovers[name].point = GetPoint(parent)
+ E.CreatedMovers[name].shouldDisable = shouldDisable
+ E.CreatedMovers[name].configString = configString
+
+ E.CreatedMovers[name].type = {}
+ local types = {split(",", moverTypes)}
+ for i = 1, #types do
+ local moverType = types[i]
+ E.CreatedMovers[name].type[moverType] = true
+ end
+ end
+
+ CreateMover(parent, name, text, overlay, snapoffset, postdrag, shouldDisable, configString)
+end
+
+function E:ToggleMovers(show, moverType)
+ self.configMode = show
+
+ for name in pairs(E.CreatedMovers) do
+ if not show then
+ _G[name]:Hide()
+ else
+ if E.CreatedMovers[name].type[moverType] then
+ _G[name]:Show()
+ else
+ _G[name]:Hide()
+ end
+ end
+ end
+end
+
+function E:DisableMover(name)
+ if self.DisabledMovers[name] then return end
+
+ if not self.CreatedMovers[name] then
+ error("mover doesn't exist")
+ end
+
+ self.DisabledMovers[name] = {}
+ for x, y in pairs(self.CreatedMovers[name]) do
+ self.DisabledMovers[name][x] = y
+ end
+
+ if self.configMode then
+ _G[name]:Hide()
+ end
+
+ self.CreatedMovers[name] = nil
+end
+
+function E:EnableMover(name)
+ if self.CreatedMovers[name] then return end
+
+ if not self.DisabledMovers[name] then
+ error("mover doesn't exist")
+ end
+
+ self.CreatedMovers[name] = {}
+ for x, y in pairs(self.DisabledMovers[name]) do
+ self.CreatedMovers[name][x] = y
+ end
+
+ --Make sure we add anchor information from a potential profile switch
+ --Commented out, as it created an issue with trying to reset a mover after having used EnableMover on it. Not sure if this code is even needed anymore.
+ -- if E.db.movers and E.db.movers[name] and type(E.db.movers[name]) == 'string' then
+ -- self.CreatedMovers[name].point = E.db.movers[name]
+ -- end
+
+ if self.configMode then
+ _G[name]:Show()
+ end
+
+ self.DisabledMovers[name] = nil
+end
+
+function E:ResetMovers(arg)
+ if arg == "" or arg == nil then
+ for name in pairs(E.CreatedMovers) do
+ local f = _G[name]
+ local point, anchor, secondaryPoint, x, y = split(",", E.CreatedMovers[name].point)
+ f:ClearAllPoints()
+ f:Point(point, anchor, secondaryPoint, x, y)
+
+ for key, value in pairs(E.CreatedMovers[name]) do
+ if key == "postdrag" and type(value) == "function" then
+ value(f, E:GetScreenQuadrant(f))
+ end
+ end
+ end
+ self.db.movers = nil
+ else
+ for name in pairs(E.CreatedMovers) do
+ for key, value in pairs(E.CreatedMovers[name]) do
+ if key == "text" then
+ if arg == value then
+ local f = _G[name]
+ local point, anchor, secondaryPoint, x, y = split(",", E.CreatedMovers[name].point)
+ f:ClearAllPoints()
+ f:Point(point, anchor, secondaryPoint, x, y)
+
+ if self.db.movers then
+ self.db.movers[name] = nil
+ end
+
+ if E.CreatedMovers[name].postdrag ~= nil and type(E.CreatedMovers[name].postdrag) == "function" then
+ E.CreatedMovers[name].postdrag(f, E:GetScreenQuadrant(f))
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+--Profile Change
+function E:SetMoversPositions()
+ --E:SetMoversPositions() is the first function called in E:UpdateAll().
+ --Because of that, we can allow ourselves to re-enable all disabled movers here,
+ --as the subsequent updates to these elements will disable them again if needed.
+ for name in pairs(E.DisabledMovers) do
+ local shouldDisable = ((E.DisabledMovers[name].shouldDisable and E.DisabledMovers[name].shouldDisable()) or false)
+ if not shouldDisable then
+ E:EnableMover(name)
+ end
+ end
+
+ for name in pairs(E.CreatedMovers) do
+ local f = _G[name]
+ local point, anchor, secondaryPoint, x, y
+ if E.db.movers and E.db.movers[name] and type(E.db.movers[name]) == "string" then
+ --Backward compatibility
+ local delim
+ local anchorString = E.db.movers[name]
+ if find(anchorString, "\031") then
+ delim = "\031"
+ elseif find(anchorString, ",") then
+ delim = ","
+ end
+ point, anchor, secondaryPoint, x, y = split(delim, anchorString)
+ f:ClearAllPoints()
+ f:Point(point, anchor, secondaryPoint, x, y)
+ elseif f then
+ point, anchor, secondaryPoint, x, y = split(",", E.CreatedMovers[name].point)
+ f:ClearAllPoints()
+ f:Point(point, anchor, secondaryPoint, x, y)
+ end
+ end
+end
+
+function E:SetMoversClampedToScreen(value)
+ for name in pairs(E.CreatedMovers) do
+ _G[name]:SetClampedToScreen(value)
+ end
+end
+
+--Called from core.lua
+function E:LoadMovers()
+ for name, t in pairs(E.CreatedMovers) do
+ CreateMover(t.parent, name, t.text, t.overlay, t.snapoffset, t.postdrag, t.shouldDisable, t.configString)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Core/PixelPerfect.lua b/ElvUI/Core/PixelPerfect.lua
new file mode 100644
index 0000000..ab85b8c
--- /dev/null
+++ b/ElvUI/Core/PixelPerfect.lua
@@ -0,0 +1,91 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+--Lua functions
+local min, max, abs, floor = min, max, abs, floor
+--WoW API / Variables
+local UIParent = UIParent
+
+function E:IsEyefinity(width, height)
+ if E.global.general.eyefinity and width >= 3840 then
+ --HQ resolution
+ if width >= 9840 then return 3280 end --WQSXGA
+ if width >= 7680 and width < 9840 then return 2560 end --WQXGA
+ if width >= 5760 and width < 7680 then return 1920 end --WUXGA & HDTV
+ if width >= 5040 and width < 5760 then return 1680 end --WSXGA+
+
+ --adding height condition here to be sure it work with bezel compensation because WSXGA+ and UXGA/HD+ got approx same width
+ if width >= 4800 and width < 5760 and height == 900 then return 1600 end --UXGA & HD+
+
+ --low resolution screen
+ if width >= 4320 and width < 4800 then return 1440 end --WSXGA
+ if width >= 4080 and width < 4320 then return 1360 end --WXGA
+ if width >= 3840 and width < 4080 then return 1224 end --SXGA & SXGA (UVGA) & WXGA & HDTV
+ end
+end
+
+function E:UIScale(init)
+ local scale = E.global.general.UIScale
+ if init then --E.OnInitialize
+ --Set variables for pixel scaling
+ local pixel, ratio = 1, 768 / E.screenheight
+ E.mult = (pixel / scale) - ((pixel - ratio) / scale)
+ E.Spacing = (E.PixelMode and 0) or E.mult
+ E.Border = ((not E.twoPixelsPlease) and E.PixelMode and E.mult) or E.mult*2
+ else --E.Initialize
+ UIParent:SetScale(scale)
+
+ --Check if we are using `E.eyefinity`
+ local width, height = E.screenwidth, E.screenheight
+ E.eyefinity = E:IsEyefinity(width, height)
+
+ --Resize E.UIParent if Eyefinity is on.
+ local testingEyefinity = false
+ if testingEyefinity then
+ --Eyefinity Test: Resize the E.UIParent to be smaller than it should be, all objects inside should relocate.
+ --Dragging moveable frames outside the box and reloading the UI ensures that they are saving position correctly.
+ local uiWidth, uiHeight = UIParent:GetSize()
+ width, height = uiWidth - 250, uiHeight - 250
+ elseif E.eyefinity then
+ --find a new width value of E.UIParent for screen #1.
+ local uiHeight = UIParent:GetHeight()
+ width, height = E.eyefinity / (height / uiHeight), uiHeight
+ else
+ width, height = UIParent:GetSize()
+ end
+
+ E.UIParent:SetSize(width, height)
+ E.UIParent.origHeight = E.UIParent:GetHeight()
+
+ --Calculate potential coordinate differences
+ E.diffGetLeft = E:Round(abs(UIParent:GetLeft() - E.UIParent:GetLeft()))
+ E.diffGetRight = E:Round(abs(UIParent:GetRight() - E.UIParent:GetRight()))
+ E.diffGetBottom = E:Round(abs(UIParent:GetBottom() - E.UIParent:GetBottom()))
+ E.diffGetTop = E:Round(abs(UIParent:GetTop() - E.UIParent:GetTop()))
+ end
+end
+
+function E:PixelBestSize()
+ return max(0.4, min(1.15, 768 / E.screenheight))
+end
+
+function E:PixelScaleChanged(event, skip)
+ E:UIScale(true) -- repopulate variables
+ E:UIScale() -- setup the scale
+
+ E:UpdateConfigSize(true) -- reposition config
+
+ if skip or E.global.general.ignoreScalePopup then return end
+
+ if event == "UPDATE_FLOATING_CHAT_WINDOWS" then return end
+
+ if event == "UISCALE_CHANGE" then
+ E:Delay(0.5, E.StaticPopup_Show, E, event)
+ else
+ E:StaticPopup_Show("UISCALE_CHANGE")
+ end
+end
+
+function E:Scale(x)
+ local mult = E.mult
+ return mult * floor(x / mult + 0.5)
+end
\ No newline at end of file
diff --git a/ElvUI/Core/PluginInstaller.lua b/ElvUI/Core/PluginInstaller.lua
new file mode 100644
index 0000000..0a5a9bd
--- /dev/null
+++ b/ElvUI/Core/PluginInstaller.lua
@@ -0,0 +1,458 @@
+--Plugins pass their info using the table like:
+--[[
+ addon = {
+ Title = "Your Own Title",
+ Name = "AddOnName",
+ tutorialImage = "TexturePath",
+ Pages = {
+ [1] = function1,
+ [2] = function2,
+ [3] = function3,
+ },
+ StepTitles = {
+ [1] = "Title 1",
+ [2] = "Title 2",
+ [3] = "Title 3",
+ },
+ StepTitlesColor = {r,g,b},
+ StepTitlesColorSelected = {r,g,b},
+ StepTitleWidth = 140,
+ StepTitleButtonWidth = 130,
+ StepTitleTextJustification = "CENTER",
+ }
+ E:GetModule("PluginInstaller"):Queue(addon)
+
+ Title is wat displayed on top of the window. By default it's ""ElvUI Plugin Installation""
+ Name is how your installation will be showin in "pending list", Default is "Unknown"
+ tutorialImage is a path to your own texture to use in frame. if not specified, then it will use ElvUI's one
+ Pages is a table to set up pages of your install where numbers are representing actual pages' order and function is what previously was used to set layout. For example
+ function function1()
+ PluginInstallFrame.SubTitle:SetText("Title Text")
+ PluginInstallFrame.Desc1:SetText("Desc 1 Tet")
+ PluginInstallFrame.Desc2:SetText("Desc 2 Tet")
+ PluginInstallFrame.Desc3:SetText("Desc 3 Tet")
+
+ PluginInstallFrame.Option1:Show()
+ PluginInstallFrame.Option1:SetScript("OnClick", function() end)
+ PluginInstallFrame.Option1:SetText("Text 1")
+
+ PluginInstallFrame.Option2:Show()
+ PluginInstallFrame.Option2:SetScript("OnClick", function() end)
+ PluginInstallFrame.Option2:SetText("Text 2")
+ end
+ StepTitles - a table to specify "titles" for your install steps. If specified and number of lines here = number of pages then you'll get an additional frame to the right of main frame
+ with a list of steps (current one being highlighted), clicking on those will open respective step. BenikUI style of doing stuff.
+ StepTitlesColor - a table with color values to color "titles" when they are not active
+ StepTitlesColorSelected - a table with color values to color "titles" when they are active
+ StepTitleWidth - Width of the steps frame on the right side
+ StepTitleButtonWidth - Width of each step button in the steps frame
+ StepTitleTextJustification - The justification of the text on each step button ("LEFT", "RIGHT", "CENTER"). Default: "CENTER"
+]]
+
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB, Localize Underscore
+local PI = E:GetModule("PluginInstaller")
+local S = E:GetModule("Skins")
+
+--Lua functions
+local pairs, unpack = pairs, unpack
+local tinsert, tremove = tinsert, tremove
+local format = string.format
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local PlaySoundFile = PlaySoundFile
+local UIFrameFadeOut = UIFrameFadeOut
+local CONTINUE, PREVIOUS, UNKNOWN = CONTINUE, PREVIOUS, UNKNOWN
+
+--Global variables that we don't cache, list them here for the mikk's Find Globals script
+-- GLOBALS: PluginInstallFrame
+
+--Installation Functions
+PI.Installs = {}
+local f
+local BUTTON_HEIGHT = 20
+
+local function ResetAll()
+ f.Next:Disable()
+ f.Prev:Disable()
+ f.Option1:Hide()
+ f.Option1:SetScript("OnClick", nil)
+ f.Option1:SetText("")
+ f.Option2:Hide()
+ f.Option2:SetScript("OnClick", nil)
+ f.Option2:SetText("")
+ f.Option3:Hide()
+ f.Option3:SetScript("OnClick", nil)
+ f.Option3:SetText("")
+ f.Option4:Hide()
+ f.Option4:SetScript("OnClick", nil)
+ f.Option4:SetText("")
+ f.SubTitle:SetText("")
+ f.Desc1:SetText("")
+ f.Desc2:SetText("")
+ f.Desc3:SetText("")
+ f.Desc4:SetText("")
+ f:Size(550, 400)
+ if f.StepTitles then
+ for i = 1, #f.side.Lines do f.side.Lines[i].text:SetText("") end
+ end
+end
+
+local function SetPage(PageNum, PrevPage)
+ f.CurrentPage = PageNum
+ f.PrevPage = PrevPage
+ ResetAll()
+ f.Status.anim.progress:SetChange(PageNum)
+ f.Status.anim.progress:Play()
+
+ local r, g, b = E:ColorGradient(f.CurrentPage / f.MaxPage, 1, 0, 0, 1, 1, 0, 0, 1, 0)
+ f.Status:SetStatusBarColor(r, g, b)
+
+ if PageNum == f.MaxPage then
+ f.Next:Disable()
+ else
+ f.Next:Enable()
+ end
+
+ if PageNum == 1 then
+ f.Prev:Disable()
+ else
+ f.Prev:Enable()
+ end
+
+ f.Pages[f.CurrentPage]()
+ f.Status.text:SetFormattedText("%d / %d", f.CurrentPage, f.MaxPage)
+ if f.StepTitles then
+ for i = 1, #f.side.Lines do
+ local button = f.side.Lines[i]
+ local color
+ button.text:SetText(f.StepTitles[i])
+ if i == f.CurrentPage then
+ color = f.StepTitlesColorSelected or {0.09, 0.52, 0.82}
+ else
+ color = f.StepTitlesColor or {1, 1, 1}
+ end
+ button.text:SetTextColor(color[1] or color.r, color[2] or color.g, color[3] or color.b)
+ end
+ end
+end
+
+local function NextPage()
+ if f.CurrentPage ~= f.MaxPage then
+ f.CurrentPage = f.CurrentPage + 1
+ SetPage(f.CurrentPage, f.CurrentPage - 1)
+ end
+end
+
+local function PreviousPage()
+ if f.CurrentPage ~= 1 then
+ f.CurrentPage = f.CurrentPage - 1
+ SetPage(f.CurrentPage, f.CurrentPage + 1)
+ end
+end
+
+function PI:CreateStepComplete()
+ local imsg = CreateFrame("Frame", "PluginInstallStepComplete", E.UIParent)
+ imsg:Size(418, 72)
+ imsg:Point("TOP", 0, -190)
+ imsg:Hide()
+ imsg:SetScript("OnShow", function(frame)
+ if frame.message then
+ PlaySoundFile([[Sound\Interface\LevelUp.wav]])
+ frame.text:SetText(frame.message)
+ UIFrameFadeOut(frame, 3.5, 1, 0)
+ E:Delay(4, frame.Hide, frame)
+ frame.message = nil
+ else
+ frame:Hide()
+ end
+ end)
+
+ imsg.firstShow = false
+
+ imsg.bg = imsg:CreateTexture(nil, "BACKGROUND")
+ imsg.bg:SetTexture([[Interface\LevelUp\LevelUpTex]])
+ imsg.bg:SetPoint("BOTTOM")
+ imsg.bg:Size(326, 103)
+ imsg.bg:SetTexCoord(0.00195313, 0.63867188, 0.03710938, 0.23828125)
+ imsg.bg:SetVertexColor(1, 1, 1, 0.6)
+
+ imsg.lineTop = imsg:CreateTexture(nil, "BACKGROUND")
+ imsg.lineTop:SetDrawLayer("BACKGROUND", 2)
+ imsg.lineTop:SetTexture([[Interface\LevelUp\LevelUpTex]])
+ imsg.lineTop:SetPoint("TOP")
+ imsg.lineTop:Size(418, 7)
+ imsg.lineTop:SetTexCoord(0.00195313, 0.81835938, 0.01953125, 0.03320313)
+
+ imsg.lineBottom = imsg:CreateTexture(nil, "BACKGROUND")
+ imsg.lineBottom:SetDrawLayer("BACKGROUND", 2)
+ imsg.lineBottom:SetTexture([[Interface\LevelUp\LevelUpTex]])
+ imsg.lineBottom:SetPoint("BOTTOM")
+ imsg.lineBottom:Size(418, 7)
+ imsg.lineBottom:SetTexCoord(0.00195313, 0.81835938, 0.01953125, 0.03320313)
+
+ imsg.text = imsg:CreateFontString(nil, "ARTWORK")
+ imsg.text:FontTemplate(E.media.normFont, 32, "OUTLINE")
+ imsg.text:Point("BOTTOM", 0, 12)
+ imsg.text:SetTextColor(1, 0.82, 0)
+ imsg.text:SetJustifyH("CENTER")
+end
+
+function PI:CreateFrame()
+ f = CreateFrame("Button", "PluginInstallFrame", E.UIParent)
+ f.SetPage = SetPage
+ f:Size(550, 400)
+ f:SetTemplate("Transparent")
+ f:SetPoint("CENTER")
+ f:SetFrameStrata("TOOLTIP")
+
+ f.Title = f:CreateFontString(nil, "OVERLAY")
+ f.Title:FontTemplate(nil, 17, nil)
+ f.Title:Point("TOP", 0, -5)
+
+ f.Next = CreateFrame("Button", "PluginInstallNextButton", f, "UIPanelButtonTemplate")
+ f.Next:Size(110, 25)
+ f.Next:Point("BOTTOMRIGHT", -5, 5)
+ f.Next:SetText(CONTINUE)
+ f.Next:Disable()
+ f.Next:SetScript("OnClick", NextPage)
+ S:HandleButton(f.Next, true)
+
+ f.Prev = CreateFrame("Button", "PluginInstallPrevButton", f, "UIPanelButtonTemplate")
+ f.Prev:Size(110, 25)
+ f.Prev:Point("BOTTOMLEFT", 5, 5)
+ f.Prev:SetText(PREVIOUS)
+ f.Prev:Disable()
+ f.Prev:SetScript("OnClick", PreviousPage)
+ S:HandleButton(f.Prev, true)
+
+ f.Status = CreateFrame("StatusBar", "PluginInstallStatus", f)
+ f.Status:SetFrameLevel(f.Status:GetFrameLevel() + 2)
+ f.Status:CreateBackdrop("Default", true)
+ f.Status:SetStatusBarTexture(E.media.normTex)
+ f.Status:SetStatusBarColor(unpack(E.media.rgbvaluecolor))
+ f.Status:Point("TOPLEFT", f.Prev, "TOPRIGHT", 6, -2)
+ f.Status:Point("BOTTOMRIGHT", f.Next, "BOTTOMLEFT", -6, 2)
+ -- Setup StatusBar Animation
+ f.Status.anim = CreateAnimationGroup(f.Status)
+ f.Status.anim.progress = f.Status.anim:CreateAnimation("Progress")
+ f.Status.anim.progress:SetEasing("Out")
+ f.Status.anim.progress:SetDuration(.3)
+
+ f.Status.text = f.Status:CreateFontString(nil, "OVERLAY")
+ f.Status.text:FontTemplate()
+ f.Status.text:SetPoint("CENTER")
+
+ f.Option1 = CreateFrame("Button", "PluginInstallOption1Button", f, "UIPanelButtonTemplate")
+ f.Option1:Size(160, 30)
+ f.Option1:Point("BOTTOM", 0, 45)
+ f.Option1:SetText("")
+ f.Option1:Hide()
+ S:HandleButton(f.Option1, true)
+
+ f.Option2 = CreateFrame("Button", "PluginInstallOption2Button", f, "UIPanelButtonTemplate")
+ f.Option2:Size(110, 30)
+ f.Option2:Point("BOTTOMLEFT", f, "BOTTOM", 4, 45)
+ f.Option2:SetText("")
+ f.Option2:Hide()
+ f.Option2:SetScript("OnShow", function() f.Option1:SetWidth(110) f.Option1:ClearAllPoints() f.Option1:Point("BOTTOMRIGHT", f, "BOTTOM", -4, 45) end)
+ f.Option2:SetScript("OnHide", function() f.Option1:SetWidth(160) f.Option1:ClearAllPoints() f.Option1:Point("BOTTOM", 0, 45) end)
+ S:HandleButton(f.Option2, true)
+
+ f.Option3 = CreateFrame("Button", "PluginInstallOption3Button", f, "UIPanelButtonTemplate")
+ f.Option3:Size(100, 30)
+ f.Option3:Point("LEFT", f.Option2, "RIGHT", 4, 0)
+ f.Option3:SetText("")
+ f.Option3:Hide()
+ f.Option3:SetScript("OnShow", function() f.Option1:SetWidth(100) f.Option1:ClearAllPoints() f.Option1:Point("RIGHT", f.Option2, "LEFT", -4, 0) f.Option2:SetWidth(100) f.Option2:ClearAllPoints() f.Option2:Point("BOTTOM", f, "BOTTOM", 0, 45) end)
+ f.Option3:SetScript("OnHide", function() f.Option1:SetWidth(160) f.Option1:ClearAllPoints() f.Option1:Point("BOTTOM", 0, 45) f.Option2:SetWidth(110) f.Option2:ClearAllPoints() f.Option2:Point("BOTTOMLEFT", f, "BOTTOM", 4, 45) end)
+ S:HandleButton(f.Option3, true)
+
+ f.Option4 = CreateFrame("Button", "PluginInstallOption4Button", f, "UIPanelButtonTemplate")
+ f.Option4:Size(100, 30)
+ f.Option4:Point("LEFT", f.Option3, "RIGHT", 4, 0)
+ f.Option4:SetText("")
+ f.Option4:Hide()
+ f.Option4:SetScript("OnShow", function()
+ f.Option1:Width(100)
+ f.Option2:Width(100)
+
+ f.Option1:ClearAllPoints()
+ f.Option1:Point("RIGHT", f.Option2, "LEFT", -4, 0)
+ f.Option2:ClearAllPoints()
+ f.Option2:Point("BOTTOMRIGHT", f, "BOTTOM", -4, 45)
+ end)
+ f.Option4:SetScript("OnHide", function() f.Option1:SetWidth(160) f.Option1:ClearAllPoints() f.Option1:Point("BOTTOM", 0, 45) f.Option2:SetWidth(110) f.Option2:ClearAllPoints() f.Option2:Point("BOTTOMLEFT", f, "BOTTOM", 4, 45) end)
+ S:HandleButton(f.Option4, true)
+
+ f.SubTitle = f:CreateFontString(nil, "OVERLAY")
+ f.SubTitle:FontTemplate(nil, 15, nil)
+ f.SubTitle:Point("TOP", 0, -40)
+
+ f.Desc1 = f:CreateFontString(nil, "OVERLAY")
+ f.Desc1:FontTemplate()
+ f.Desc1:Point("TOPLEFT", 20, -75)
+ f.Desc1:Width(f:GetWidth() - 40)
+
+ f.Desc2 = f:CreateFontString(nil, "OVERLAY")
+ f.Desc2:FontTemplate()
+ f.Desc2:Point("TOP", f.Desc1, "BOTTOM", 0, -20)
+ f.Desc2:Width(f:GetWidth() - 40)
+
+ f.Desc3 = f:CreateFontString(nil, "OVERLAY")
+ f.Desc3:FontTemplate()
+ f.Desc3:Point("TOP", f.Desc2, "BOTTOM", 0, -20)
+ f.Desc3:Width(f:GetWidth() - 40)
+
+ f.Desc4 = f:CreateFontString(nil, "OVERLAY")
+ f.Desc4:FontTemplate()
+ f.Desc4:Point("TOP", f.Desc3, "BOTTOM", 0, -20)
+ f.Desc4:Width(f:GetWidth() - 40)
+
+ local close = CreateFrame("Button", "PluginInstallCloseButton", f, "UIPanelCloseButton")
+ close:SetPoint("TOPRIGHT", f, "TOPRIGHT")
+ close:SetScript("OnClick", function() f:Hide() end)
+ S:HandleCloseButton(close)
+
+ f.pending = CreateFrame("Frame", "PluginInstallPendingButton", f)
+ f.pending:Size(20, 20)
+ f.pending:SetPoint("TOPLEFT", f, "TOPLEFT", 8, -8)
+ f.pending.tex = f.pending:CreateTexture(nil, "OVERLAY")
+ f.pending.tex:Point("TOPLEFT", f.pending, "TOPLEFT", 2, -2)
+ f.pending.tex:Point("BOTTOMRIGHT", f.pending, "BOTTOMRIGHT", -2, 2)
+ f.pending.tex:SetTexture([[Interface\OptionsFrame\UI-OptionsFrame-NewFeatureIcon]])
+ f.pending:CreateBackdrop("Transparent")
+ f.pending:SetScript("OnEnter", function(self)
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT", E.PixelMode and -7 or -9)
+ GameTooltip:AddLine(L["List of installations in queue:"], 1, 1, 1)
+ GameTooltip:AddLine(" ")
+ for i = 1, #PI.Installs do
+ GameTooltip:AddDoubleLine(format("%d. %s", i, (PI.Installs[i].Name or UNKNOWN)), i == 1 and format("|cff00FF00%s|r", L["In Progress"]) or format("|cffFF0000%s|r", L["Pending"]))
+ end
+ GameTooltip:Show()
+ end)
+ f.pending:SetScript("OnLeave", function()
+ GameTooltip:Hide()
+ end)
+
+ f.tutorialImage = f:CreateTexture("PluginInstallTutorialImage", "OVERLAY")
+ f.tutorialImage:Size(256, 128)
+ f.tutorialImage:Point("BOTTOM", 0, 70)
+
+ f.side = CreateFrame("Frame", "PluginInstallTitleFrame", f)
+ f.side:SetTemplate("Transparent")
+ f.side:SetPoint("TOPLEFT", f, "TOPRIGHT", E.PixelMode and 1 or 3, 0)
+ f.side:SetPoint("BOTTOMLEFT", f, "BOTTOMRIGHT", E.PixelMode and 1 or 3, 0)
+ f.side:Width(140)
+ f.side.text = f.side:CreateFontString(nil, "OVERLAY")
+ f.side.text:SetPoint("TOP", f.side, "TOP", 0, -4)
+ f.side.text:FontTemplate(E.media.normFont, 18, "OUTLINE")
+ f.side.text:SetText(L["Steps"])
+ f.side.Lines = {} --Table to keep shown lines
+ f.side:Hide()
+ for i = 1, 18 do
+ local button = CreateFrame("Button", nil, f)
+ if i == 1 then
+ button:SetPoint("TOP", f.side.text, "BOTTOM", 0, -6)
+ else
+ button:SetPoint("TOP", f.side.Lines[i - 1], "BOTTOM")
+ end
+ button:SetSize(130, BUTTON_HEIGHT)
+ button.text = button:CreateFontString(nil, "OVERLAY")
+ button.text:SetPoint("TOPLEFT", button, "TOPLEFT", 2, -2)
+ button.text:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -2, 2)
+ button.text:FontTemplate(E.media.normFont, 14, "OUTLINE")
+ button:SetScript("OnClick", function() if i <= f.MaxPage then SetPage(i, f.CurrentPage) end end)
+ button.text:SetText("")
+ f.side.Lines[i] = button
+ button:Hide()
+ end
+
+ f:Hide()
+
+ f:SetScript("OnHide", function() PI:CloseInstall() end)
+end
+
+function PI:Queue(addon)
+ local addonIsQueued = false
+ for _, v in pairs(self.Installs) do
+ if v.Name == addon.Name then
+ addonIsQueued = true
+ end
+ end
+
+ if not addonIsQueued then
+ tinsert(self.Installs, #(self.Installs)+1, addon)
+ self:RunInstall()
+ end
+end
+
+function PI:CloseInstall()
+ tremove(self.Installs, 1)
+ f.side:Hide()
+ for i = 1, #f.side.Lines do
+ f.side.Lines[i].text:SetText("")
+ f.side.Lines[i]:Hide()
+ end
+ if #self.Installs > 0 then
+ E:Delay(1, PI.RunInstall, PI)
+ end
+end
+
+function PI:RunInstall()
+ if not E.private.install_complete then return end
+ if self.Installs[1] and not PluginInstallFrame:IsShown() and not (ElvUIInstallFrame and ElvUIInstallFrame:IsShown()) then
+ f.StepTitles = nil
+ f.StepTitlesColor = nil
+ f.StepTitlesColorSelected = nil
+ local db = self.Installs[1]
+ f.CurrentPage = 0
+ f.MaxPage = #(db.Pages)
+
+ f.Title:SetText(db.Title or L["ElvUI Plugin Installation"])
+ f.Status:SetMinMaxValues(0, f.MaxPage)
+ f.Status.text:SetText(f.CurrentPage.." / "..f.MaxPage)
+ f.tutorialImage:SetTexture(db.tutorialImage or E.Media.Textures.Logo)
+
+ f.Pages = db.Pages
+
+ PluginInstallFrame:Show()
+ f:SetPoint("CENTER")
+ if db.StepTitles and #db.StepTitles == f.MaxPage then
+ f:SetPoint("CENTER", E.UIParent, "CENTER", -((db.StepTitleWidth or 140)/2), 0)
+ f.side:SetWidth(db.StepTitleWidth or 140)
+ f.side:Show()
+
+ for i = 1, #f.side.Lines do
+ if db.StepTitles[i] then
+ f.side.Lines[i]:SetWidth(db.StepTitleButtonWidth or 130)
+ f.side.Lines[i].text:SetJustifyH(db.StepTitleTextJustification or "CENTER")
+ f.side.Lines[i]:Show()
+ end
+ end
+
+ f.StepTitles = db.StepTitles
+ f.StepTitlesColor = db.StepTitlesColor
+ f.StepTitlesColorSelected = db.StepTitlesColorSelected
+ end
+ NextPage()
+ end
+ if #(self.Installs) > 1 then
+ f.pending:Show()
+ E:Flash(f.pending, 0.53, true)
+ else
+ f.pending:Hide()
+ E:StopFlash(f.pending)
+ end
+end
+
+function PI:Initialize()
+ PI.Initialized = true
+ PI:CreateStepComplete()
+ PI:CreateFrame()
+end
+
+local function InitializeCallback()
+ PI:Initialize()
+end
+
+E:RegisterModule(PI:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Core/Smoothie.lua b/ElvUI/Core/Smoothie.lua
new file mode 100644
index 0000000..0cfc061
--- /dev/null
+++ b/ElvUI/Core/Smoothie.lua
@@ -0,0 +1,142 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+-- Credit: ls- (lightspark)
+local abs, next = abs, next
+local tonumber, assert = tonumber, assert
+local activeObjects = {}
+local handledObjects = {}
+local TARGET_FPS = 60
+local AMOUNT = 0.33
+
+local function lerp(startValue, endValue, amount)
+ return (1 - amount) * startValue + amount * endValue
+end
+
+local function clamp(v, min, max)
+ min = min or 0
+ max = max or 1
+
+ if v > max then
+ return max
+ elseif v < min then
+ return min
+ end
+
+ return v
+end
+
+local function isCloseEnough(new, target, range)
+ if range > 0 then
+ return abs((new - target) / range) <= 0.001
+ end
+
+ return true
+end
+
+local frame = CreateFrame("Frame")
+local function onUpdate(_, elapsed)
+ for object, target in next, activeObjects do
+ local new = lerp(object._value, target, clamp(AMOUNT * elapsed * TARGET_FPS))
+ if isCloseEnough(new, target, object._max - object._min) then
+ new = target
+ activeObjects[object] = nil
+ end
+
+ object:SetValue_(new)
+ object._value = new
+ end
+end
+
+local function bar_SetSmoothedValue(self, value)
+ value = tonumber(value)
+
+ assert(value, "bar_SetSmoothedValue requires (value) to be a number.")
+
+ self._value = self:GetValue()
+ activeObjects[self] = clamp(value, self._min, self._max)
+end
+
+local function bar_SetSmoothedMinMaxValues(self, min, max)
+ min, max = tonumber(min), tonumber(max)
+
+ assert(min and max, "bar_SetSmoothedMinMaxValues requires (min and max) to be a number.")
+
+ self:SetMinMaxValues_(min, max)
+
+ if self._max and self._max ~= max then
+ local ratio = 1
+ if max ~= 0 and self._max and self._max ~= 0 then
+ ratio = max / (self._max or max)
+ end
+
+ local target = activeObjects[self]
+ if target then
+ activeObjects[self] = target * ratio
+ end
+
+ local cur = self._value
+ if cur then
+ self:SetValue_(cur * ratio)
+ self._value = cur * ratio
+ end
+ end
+
+ self._min = min
+ self._max = max
+end
+
+local function SmoothBar(bar)
+ bar._min, bar._max = bar:GetMinMaxValues()
+ bar._value = bar:GetValue()
+
+ if not bar.SetValue_ then
+ bar.SetValue_ = bar.SetValue
+ bar.SetValue = bar_SetSmoothedValue
+ end
+ if not bar.SetMinMaxValues_ then
+ bar.SetMinMaxValues_ = bar.SetMinMaxValues
+ bar.SetMinMaxValues = bar_SetSmoothedMinMaxValues
+ end
+
+ if not frame:GetScript("OnUpdate") then
+ frame:SetScript("OnUpdate", onUpdate)
+ end
+
+ handledObjects[bar] = true
+end
+
+local function DesmoothBar(bar)
+ if activeObjects[bar] then
+ bar:SetValue_(activeObjects[bar])
+ activeObjects[bar] = nil
+ end
+
+ if handledObjects[bar] then
+ handledObjects[bar] = nil
+ end
+
+ if bar.SetValue_ then
+ bar.SetValue = bar.SetValue_
+ bar.SetValue_ = nil
+ end
+ if bar.SetMinMaxValues_ then
+ bar.SetMinMaxValues = bar.SetMinMaxValues_
+ bar.SetMinMaxValues_ = nil
+ end
+
+ if not next(handledObjects) then
+ frame:SetScript("OnUpdate", nil)
+ end
+end
+
+function E:SetSmoothingAmount(amount)
+ AMOUNT = clamp(amount, 0.2, 0.8)
+end
+
+function E:SetSmoothing(bar, enable)
+ if enable then
+ SmoothBar(bar)
+ else
+ DesmoothBar(bar)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Core/StaticPopups.lua b/ElvUI/Core/StaticPopups.lua
new file mode 100644
index 0000000..0749628
--- /dev/null
+++ b/ElvUI/Core/StaticPopups.lua
@@ -0,0 +1,1142 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local AB = E:GetModule("ActionBars")
+local UF = E:GetModule("UnitFrames")
+local Misc = E:GetModule("Misc")
+local Bags = E:GetModule("Bags")
+local Skins = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local pairs, ipairs, type, unpack, assert = pairs, ipairs, type, unpack, assert
+local tremove, tContains, tinsert, wipe = tremove, tContains, tinsert, wipe
+local strlower, format = strlower, format
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local IsAddOnLoaded = IsAddOnLoaded
+local UnitIsDeadOrGhost, InCinematic = UnitIsDeadOrGhost, InCinematic
+local GetBindingFromClick, RunBinding = GetBindingFromClick, RunBinding
+local PurchaseSlot, GetBankSlotCost = PurchaseSlot, GetBankSlotCost
+local MoneyFrame_Update = MoneyFrame_Update
+local SetCVar, DisableAddOn = SetCVar, DisableAddOn
+local ReloadUI, PlaySound, StopMusic = ReloadUI, PlaySound, StopMusic
+local StaticPopup_Resize = StaticPopup_Resize
+local AutoCompleteEditBox_OnEnterPressed = AutoCompleteEditBox_OnEnterPressed
+local AutoCompleteEditBox_OnTextChanged = AutoCompleteEditBox_OnTextChanged
+local ChatEdit_FocusActiveWindow = ChatEdit_FocusActiveWindow
+local STATICPOPUP_TEXTURE_ALERT = STATICPOPUP_TEXTURE_ALERT
+local STATICPOPUP_TEXTURE_ALERTGEAR = STATICPOPUP_TEXTURE_ALERTGEAR
+local YES, NO, OKAY, CANCEL, ACCEPT, DECLINE = YES, NO, OKAY, CANCEL, ACCEPT, DECLINE
+
+E.PopupDialogs = {}
+E.StaticPopup_DisplayedFrames = {}
+
+E.PopupDialogs.ELVUI_UPDATED_WHILE_RUNNING = {
+ text = L["ElvUI was updated while the game is still running. Please relaunch the game, as this is required for the files to be properly updated."],
+ button1 = "|cffff0000"..QUIT,
+ button2 = CANCEL,
+ OnAccept = function()
+ Quit()
+ end,
+ OnShow = function(self, data)
+ self.button2:Disable()
+ end,
+ whileDead = 1,
+}
+
+E.PopupDialogs.ELVUI_UPDATE_AVAILABLE = {
+ text = L["ElvUI is five or more revisions out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"],
+ hasEditBox = 1,
+ OnShow = function(self)
+ self.editBox:SetAutoFocus(false)
+ self.editBox.width = self.editBox:GetWidth()
+ self.editBox:Width(220)
+ self.editBox:SetText("https://github.com/BanditTech/ElvUI-Ascension")
+ self.editBox:HighlightText()
+ ChatEdit_FocusActiveWindow()
+ end,
+ OnHide = function(self)
+ self.editBox:Width(self.editBox.width or 50)
+ self.editBox.width = nil
+ end,
+ hideOnEscape = 1,
+ button1 = OKAY,
+ OnAccept = E.noop,
+ EditBoxOnEnterPressed = function(self)
+ ChatEdit_FocusActiveWindow()
+ self:GetParent():Hide()
+ end,
+ EditBoxOnEscapePressed = function(self)
+ ChatEdit_FocusActiveWindow()
+ self:GetParent():Hide()
+ end,
+ EditBoxOnTextChanged = function(self)
+ if self:GetText() ~= "https://github.com/BanditTech/ElvUI-Ascension" then
+ self:SetText("https://github.com/BanditTech/ElvUI-Ascension")
+ end
+ self:HighlightText()
+ self:ClearFocus()
+ ChatEdit_FocusActiveWindow()
+ end,
+ OnEditFocusGained = function(self)
+ self:HighlightText()
+ end,
+ showAlert = 1
+}
+
+E.PopupDialogs.ELVUI_EDITBOX = {
+ text = E.title,
+ button1 = OKAY,
+ hasEditBox = 1,
+ OnShow = function(self, data)
+ self.editBox:SetAutoFocus(false)
+ self.editBox.width = self.editBox:GetWidth()
+ self.editBox:Width(280)
+ self.editBox:AddHistoryLine("text")
+ self.editBox.temptxt = data
+ self.editBox:SetText(data)
+ self.editBox:HighlightText()
+ self.editBox:SetJustifyH("CENTER")
+ end,
+ OnHide = function(self)
+ self.editBox:Width(self.editBox.width or 50)
+ self.editBox.width = nil
+ self.temptxt = nil
+ end,
+ EditBoxOnEnterPressed = function(self)
+ self:GetParent():Hide()
+ end,
+ EditBoxOnEscapePressed = function(self)
+ self:GetParent():Hide()
+ end,
+ EditBoxOnTextChanged = function(self)
+ if self:GetText() ~= self.temptxt then
+ self:SetText(self.temptxt)
+ end
+ self:HighlightText()
+ self:ClearFocus()
+ end,
+ OnAccept = E.noop,
+ whileDead = 1,
+ preferredIndex = 3,
+ hideOnEscape = 1,
+}
+
+E.PopupDialogs.CLIENT_UPDATE_REQUEST = {
+ text = L["Detected that your ElvUI OptionsUI addon is out of date. This may be a result of your Tukui Client being out of date. Please visit our download page and update your Tukui Client, then reinstall ElvUI. Not having your ElvUI OptionsUI addon up to date will result in missing options."],
+ button1 = OKAY,
+ OnAccept = E.noop,
+ showAlert = 1
+}
+
+E.PopupDialogs.CONFIRM_LOSE_BINDING_CHANGES = {
+ text = CONFIRM_LOSE_BINDING_CHANGES,
+ button1 = OKAY,
+ button2 = CANCEL,
+ OnAccept = function()
+ AB:ChangeBindingProfile()
+ AB.bindingsChanged = nil
+ end,
+ OnCancel = function()
+ local isChecked = ElvUIBindPopupWindowCheckButton:GetChecked()
+ ElvUIBindPopupWindowCheckButton:SetChecked(not isChecked)
+ end,
+ whileDead = 1,
+ showAlert = 1
+}
+
+E.PopupDialogs.TUKUI_ELVUI_INCOMPATIBLE = {
+ text = L["Oh lord, you have got ElvUI and Tukui both enabled at the same time. Select an addon to disable."],
+ OnAccept = function() DisableAddOn("ElvUI") ReloadUI() end,
+ OnCancel = function() DisableAddOn("Tukui") ReloadUI() end,
+ button1 = "ElvUI",
+ button2 = "Tukui",
+ whileDead = 1,
+ hideOnEscape = false
+}
+
+E.PopupDialogs.DISABLE_INCOMPATIBLE_ADDON = {
+ text = L["Do you swear not to post in technical support about something not working without first disabling the addon/module combination first?"],
+ OnAccept = function() E.global.ignoreIncompatible = true end,
+ OnCancel = function() E:StaticPopup_Hide("DISABLE_INCOMPATIBLE_ADDON") E:StaticPopup_Show("INCOMPATIBLE_ADDON", E.PopupDialogs.INCOMPATIBLE_ADDON.addon, E.PopupDialogs.INCOMPATIBLE_ADDON.module) end,
+ button1 = L["I Swear"],
+ button2 = DECLINE,
+ whileDead = 1,
+ hideOnEscape = false
+}
+
+E.PopupDialogs.INCOMPATIBLE_ADDON = {
+ text = L["INCOMPATIBLE_ADDON"],
+ OnAccept = function() DisableAddOn(E.PopupDialogs.INCOMPATIBLE_ADDON.addon) ReloadUI() end,
+ OnCancel = function() E.private[strlower(E.PopupDialogs.INCOMPATIBLE_ADDON.module)].enable = false ReloadUI() end,
+ button3 = L["Disable Warning"],
+ OnAlt = function ()
+ E:StaticPopup_Hide("INCOMPATIBLE_ADDON")
+ E:StaticPopup_Show("DISABLE_INCOMPATIBLE_ADDON")
+ end,
+ whileDead = 1,
+ hideOnEscape = false,
+ noCancelOnReuse = true
+}
+
+E.PopupDialogs.UISCALE_CHANGE = {
+ text = L["The UI Scale has been changed, if you would like to preview the change press the preview button. It is recommended that you reload your User Interface for the best appearance."],
+ OnAccept = function() ReloadUI() end,
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ button3 = L["Preview Changes"],
+ OnAlt = function() E:PixelScaleChanged("UISCALE_CHANGE") end,
+ whileDead = 1,
+ hideOnEscape = false,
+ noCancelOnReuse = true
+}
+
+E.PopupDialogs.CONFIG_RL = {
+ text = L["One or more of the changes you have made require a ReloadUI."],
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = ReloadUI,
+ whileDead = 1,
+ hideOnEscape = false
+}
+
+E.PopupDialogs.GLOBAL_RL = {
+ text = L["One or more of the changes you have made will effect all characters using this addon. You will have to reload the user interface to see the changes you have made."],
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = ReloadUI,
+ whileDead = 1,
+ hideOnEscape = false
+}
+
+E.PopupDialogs.PRIVATE_RL = {
+ text = L["A setting you have changed will change an option for this character only. This setting that you have changed will be uneffected by changing user profiles. Changing this setting requires that you reload your User Interface."],
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = ReloadUI,
+ whileDead = 1,
+ hideOnEscape = false
+}
+
+E.PopupDialogs.RESET_UF_UNIT = {
+ text = L["Accepting this will reset the UnitFrame settings for %s. Are you sure?"],
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = function(self)
+ if self.data and self.data.unit then
+ UF:ResetUnitSettings(self.data.unit)
+ if self.data.mover then
+ E:ResetMovers(self.data.mover)
+ end
+
+ if self.data.unit == "raidpet" then
+ UF:CreateAndUpdateHeaderGroup(self.data.unit, nil, nil, true)
+ end
+
+ if IsAddOnLoaded("ElvUI_OptionsUI") then
+ local ACD = E.Libs.AceConfigDialog
+ if ACD and ACD.OpenFrames and ACD.OpenFrames.ElvUI then
+ ACD:SelectGroup("ElvUI", "unitframe", self.data.unit)
+ end
+ end
+ else
+ E:Print(L["Error resetting UnitFrame."])
+ end
+ end,
+ whileDead = 1,
+ hideOnEscape = false,
+}
+
+E.PopupDialogs.RESET_UF_AF = {
+ text = L["Accepting this will reset your Filter Priority lists for all auras on UnitFrames. Are you sure?"],
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = function()
+ for unitName, content in pairs(E.db.unitframe.units) do
+ if content.buffs then
+ content.buffs.priority = P.unitframe.units[unitName].buffs.priority
+ end
+ if content.debuffs then
+ content.debuffs.priority = P.unitframe.units[unitName].debuffs.priority
+ end
+ if content.aurabar then
+ content.aurabar.priority = P.unitframe.units[unitName].aurabar.priority
+ end
+ end
+ end,
+ whileDead = 1,
+ hideOnEscape = false,
+}
+
+E.PopupDialogs.RESET_NP_AF = {
+ text = L["Accepting this will reset your Filter Priority lists for all auras on NamePlates. Are you sure?"],
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = function()
+ for unitType, content in pairs(E.db.nameplates.units) do
+ if content.buffs and content.buffs.filters then
+ content.buffs.filters.priority = P.nameplates.units[unitType].buffs.filters.priority
+ end
+ if content.debuffs and content.debuffs.filters then
+ content.debuffs.filters.priority = P.nameplates.units[unitType].debuffs.filters.priority
+ end
+ end
+ end,
+ whileDead = 1,
+ hideOnEscape = false,
+}
+
+E.PopupDialogs.DELETE_GRAYS = {
+ text = format("|cffff0000%s|r", L["Delete gray items?"]),
+ button1 = YES,
+ button2 = NO,
+ OnAccept = function() Bags:VendorGrays(true) end,
+ OnShow = function(self)
+ MoneyFrame_Update(self.moneyFrame, E.PopupDialogs.DELETE_GRAYS.Money)
+ end,
+ timeout = 4,
+ whileDead = 1,
+ hideOnEscape = false,
+ hasMoneyFrame = 1
+}
+
+E.PopupDialogs.BUY_BANK_SLOT = {
+ text = CONFIRM_BUY_BANK_SLOT,
+ button1 = YES,
+ button2 = NO,
+ OnAccept = PurchaseSlot,
+ OnShow = function(self)
+ MoneyFrame_Update(self.moneyFrame, GetBankSlotCost())
+ end,
+ hasMoneyFrame = 1,
+ hideOnEscape = 1
+}
+
+E.PopupDialogs.CANNOT_BUY_BANK_SLOT = {
+ text = L["Can't buy anymore slots!"],
+ button1 = ACCEPT,
+ whileDead = 1
+}
+
+E.PopupDialogs.NO_BANK_BAGS = {
+ text = L["You must purchase a bank slot first!"],
+ button1 = ACCEPT,
+ whileDead = 1
+}
+
+E.PopupDialogs.RESETUI_CHECK = {
+ text = L["Are you sure you want to reset every mover back to it's default position?"],
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = function()
+ E:ResetAllUI()
+ end,
+ whileDead = 1
+}
+
+E.PopupDialogs.HARLEM_SHAKE = {
+ text = L["ElvUI needs to perform database optimizations please be patient."],
+ button1 = OKAY,
+ OnAccept = function()
+ if E.isMassiveShaking then
+ E:StopHarlemShake()
+ else
+ E:BeginHarlemShake()
+ return true
+ end
+ end,
+ whileDead = 1
+}
+
+E.PopupDialogs.HELLO_KITTY = {
+ text = L["ElvUI needs to perform database optimizations please be patient."],
+ button1 = OKAY,
+ OnAccept = function()
+ E:SetupHelloKitty()
+ end,
+ whileDead = 1
+}
+
+E.PopupDialogs.HELLO_KITTY_END = {
+ text = L["Do you enjoy the new ElvUI?"],
+ button1 = L["Yes, Keep Changes!"],
+ button2 = L["No, Revert Changes!"],
+ OnAccept = function()
+ E:Print(L["Type /hellokitty to revert to old settings."])
+ StopMusic()
+ SetCVar("Sound_EnableAllSound", E.oldEnableAllSound)
+ SetCVar("Sound_EnableMusic", E.oldEnableMusic)
+ end,
+ OnCancel = function()
+ E:RestoreHelloKitty()
+ StopMusic()
+ SetCVar("Sound_EnableAllSound", E.oldEnableAllSound)
+ SetCVar("Sound_EnableMusic", E.oldEnableMusic)
+ end,
+ whileDead = 1
+}
+
+E.PopupDialogs.DISBAND_RAID = {
+ text = L["Are you sure you want to disband the group?"],
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = function() Misc:DisbandRaidGroup() end,
+ whileDead = 1
+}
+
+E.PopupDialogs.CONFIRM_LOOT_DISTRIBUTION = {
+ text = CONFIRM_LOOT_DISTRIBUTION,
+ button1 = YES,
+ button2 = NO,
+ hideOnEscape = 1
+}
+
+E.PopupDialogs.RESET_PROFILE_PROMPT = {
+ text = L["Are you sure you want to reset all the settings on this profile?"],
+ button1 = YES,
+ button2 = NO,
+ hideOnEscape = 1,
+ OnAccept = function() E:ResetProfile() end,
+ whileDead = 1,
+}
+
+E.PopupDialogs.APPLY_FONT_WARNING = {
+ text = L["Are you sure you want to apply this font to all ElvUI elements?"],
+ OnAccept = function()
+ local font = E.db.general.font
+ local fontSize = E.db.general.fontSize
+
+ E.db.bags.itemLevelFont = font
+ E.db.bags.itemLevelFontSize = fontSize
+ E.db.bags.countFont = font
+ E.db.bags.countFontSize = fontSize
+ E.db.nameplates.font = font
+ --E.db.nameplates.fontSize = fontSize
+ E.db.actionbar.font = font
+ --E.db.actionbar.fontSize = fontSize
+ E.db.auras.font = font
+ E.db.auras.fontSize = fontSize
+ E.db.general.reminder.font = font
+ --E.db.general.reminder.fontSize = fontSize
+ E.db.chat.font = font
+ E.db.chat.fontSize = fontSize
+ E.db.chat.tabFont = font
+ E.db.chat.tapFontSize = fontSize
+ E.db.datatexts.font = font
+ E.db.datatexts.fontSize = fontSize
+ E.db.general.minimap.locationFont = font
+ E.db.tooltip.font = font
+ E.db.tooltip.fontSize = fontSize
+ E.db.tooltip.headerFontSize = fontSize
+ E.db.tooltip.textFontSize = fontSize
+ E.db.tooltip.smallTextFontSize = fontSize
+ E.db.tooltip.healthBar.font = font
+ --E.db.tooltip.healthbar.fontSize = fontSize
+ E.db.unitframe.font = font
+ --E.db.unitframe.fontSize = fontSize
+ E.db.unitframe.units.party.rdebuffs.font = font
+ E.db.unitframe.units.raid.rdebuffs.font = font
+ E.db.unitframe.units.raid40.rdebuffs.font = font
+
+ E:UpdateAll(true)
+ end,
+ button1 = YES,
+ button2 = CANCEL,
+ whileDead = 1,
+ hideOnEscape = false
+}
+
+E.PopupDialogs.MODULE_COPY_CONFIRM = {
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ whileDead = 1,
+ hideOnEscape = false
+}
+
+E.PopupDialogs.SCRIPT_PROFILE = {
+ text = L["You are using CPU Profiling. This causes decreased performance. Do you want to disable it or continue?"],
+ button1 = L["Disable"],
+ button2 = L["Continue"],
+ OnAccept = function()
+ SetCVar("scriptProfile", 0)
+ ReloadUI()
+ end,
+ showAlert = 1,
+ whileDead = 1,
+ hideOnEscape = false
+}
+
+E.PopupDialogs.ELVUI_CONFIG_FOUND = {
+ text = L["You still have ElvUI_Config installed. ElvUI_Config has been renamed to ElvUI_OptionsUI, please remove it."],
+ button1 = ACCEPT,
+ whileDead = 1,
+ hideOnEscape = false
+}
+
+local MAX_STATIC_POPUPS = 4
+function E:StaticPopup_OnShow()
+ PlaySound("igMainMenuOpen")
+
+ local dialog = E.PopupDialogs[self.which]
+ local OnShow = dialog.OnShow
+
+ if OnShow then
+ OnShow(self, self.data)
+ end
+ if dialog.hasMoneyInputFrame then
+ _G[self:GetName().."MoneyInputFrameGold"]:SetFocus()
+ end
+ if dialog.enterClicksFirstButton then
+ self:SetScript("OnKeyDown", E.StaticPopup_OnKeyDown)
+ end
+
+ -- boost static popups over ace gui
+ if IsAddOnLoaded("ElvUI_OptionsUI") then
+ local ACD = E.Libs.AceConfigDialog
+ if ACD and ACD.OpenFrames and ACD.OpenFrames.ElvUI then
+ self.frameStrataIncreased = true
+ self:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ local popupFrameLevel = self:GetFrameLevel()
+ if popupFrameLevel < 100 then
+ self:SetFrameLevel(popupFrameLevel+100)
+ end
+ end
+ end
+end
+
+function E:StaticPopup_EscapePressed()
+ local closed = nil
+ for _, frame in ipairs(E.StaticPopup_DisplayedFrames) do
+ if frame:IsShown() and frame.hideOnEscape then
+ local standardDialog = E.PopupDialogs[frame.which]
+ if standardDialog then
+ local OnCancel = standardDialog.OnCancel
+ local noCancelOnEscape = standardDialog.noCancelOnEscape
+ if OnCancel and not noCancelOnEscape then
+ OnCancel(frame, frame.data, "clicked")
+ end
+ frame:Hide()
+ else
+ E:StaticPopupSpecial_Hide(frame)
+ end
+ closed = 1
+ end
+ end
+ return closed
+end
+
+function E:StaticPopupSpecial_Hide(frame)
+ frame:Hide()
+ E:StaticPopup_CollapseTable()
+end
+
+function E:StaticPopup_CollapseTable()
+ local displayedFrames = E.StaticPopup_DisplayedFrames
+ local index = #displayedFrames
+ while (index >= 1) and (not displayedFrames[index]:IsShown()) do
+ tremove(displayedFrames, index)
+ index = index - 1
+ end
+end
+
+function E:StaticPopup_SetUpPosition(dialog)
+ if not tContains(E.StaticPopup_DisplayedFrames, dialog) then
+ local lastFrame = E.StaticPopup_DisplayedFrames[#E.StaticPopup_DisplayedFrames]
+ if lastFrame then
+ dialog:Point("TOP", lastFrame, "BOTTOM", 0, -4)
+ else
+ dialog:Point("TOP", E.UIParent, "TOP", 0, -100)
+ end
+ tinsert(E.StaticPopup_DisplayedFrames, dialog)
+ end
+end
+
+function E:StaticPopupSpecial_Show(frame)
+ if frame.exclusive then
+ E:StaticPopup_HideExclusive()
+ end
+ E:StaticPopup_SetUpPosition(frame)
+ frame:Show()
+end
+
+function E:StaticPopupSpecial_Hide(frame)
+ frame:Hide()
+ E:StaticPopup_CollapseTable()
+end
+
+--Used to figure out if we can resize a frame
+function E:StaticPopup_IsLastDisplayedFrame(frame)
+ for i = #E.StaticPopup_DisplayedFrames, 1, -1 do
+ local popup = E.StaticPopup_DisplayedFrames[i]
+ if popup:IsShown() then
+ return frame == popup
+ end
+ end
+ return false
+end
+
+function E:StaticPopup_OnKeyDown(key)
+ if GetBindingFromClick(key) == "TOGGLEGAMEMENU" then
+ return E:StaticPopup_EscapePressed()
+ elseif GetBindingFromClick(key) == "SCREENSHOT" then
+ RunBinding("SCREENSHOT")
+ return
+ end
+
+ local dialog = E.PopupDialogs[self.which]
+ if dialog then
+ if key == "ENTER" and dialog.enterClicksFirstButton then
+ local frameName = self:GetName()
+ local button
+ local i = 1
+ while true do
+ button = _G[frameName.."Button"..i]
+ if button then
+ if button:IsShown() then
+ E:StaticPopup_OnClick(self, i)
+ return
+ end
+ i = i + 1
+ else
+ break
+ end
+ end
+ end
+ end
+end
+
+function E:StaticPopup_OnHide()
+ PlaySound("igMainMenuClose")
+
+ E:StaticPopup_CollapseTable()
+
+ local dialog = E.PopupDialogs[self.which]
+ local OnHide = dialog.OnHide
+ if OnHide then
+ OnHide(self, self.data)
+ end
+ self.extraFrame:Hide()
+ if dialog.enterClicksFirstButton then
+ self:SetScript("OnKeyDown", nil)
+ end
+
+ -- static popup was boosted over ace gui, set it back to normal
+ if self.frameStrataIncreased then
+ self.frameStrataIncreased = nil
+ self:SetFrameStrata("DIALOG")
+
+ local popupFrameLevel = self:GetFrameLevel()
+ if popupFrameLevel > 100 then
+ self:SetFrameLevel(popupFrameLevel-100)
+ end
+ end
+end
+
+function E:StaticPopup_OnUpdate(elapsed)
+ if self.timeleft and self.timeleft > 0 then
+ local which = self.which
+ local timeleft = self.timeleft - elapsed
+ if timeleft <= 0 then
+ if not E.PopupDialogs[which].timeoutInformationalOnly then
+ self.timeleft = 0
+ local OnCancel = E.PopupDialogs[which].OnCancel
+ if OnCancel then
+ OnCancel(self, self.data, "timeout")
+ end
+ self:Hide()
+ end
+ return
+ end
+ self.timeleft = timeleft
+ end
+
+ if self.startDelay then
+ local which = self.which
+ local timeleft = self.startDelay - elapsed
+ if timeleft <= 0 then
+ self.startDelay = nil
+ local text = _G[self:GetName().."Text"]
+ text:SetFormattedText(E.PopupDialogs[which].text, text.text_arg1, text.text_arg2)
+ local button1 = _G[self:GetName().."Button1"]
+ button1:Enable()
+ StaticPopup_Resize(self, which)
+ return
+ end
+ self.startDelay = timeleft
+ end
+
+ local onUpdate = E.PopupDialogs[self.which].OnUpdate
+ if onUpdate then
+ onUpdate(self, elapsed)
+ end
+end
+
+function E:StaticPopup_OnClick(index)
+ if not self:IsShown() then return end
+
+ local which = self.which
+ local info = E.PopupDialogs[which]
+ if not info then
+ return nil
+ end
+ local hide = true
+ if index == 1 then
+ local OnAccept = info.OnAccept
+ if OnAccept then
+ hide = not OnAccept(self, self.data, self.data2)
+ end
+ elseif index == 3 then
+ local OnAlt = info.OnAlt
+ if OnAlt then
+ OnAlt(self, self.data, "clicked")
+ end
+ else
+ local OnCancel = info.OnCancel
+ if OnCancel then
+ hide = not OnCancel(self, self.data, "clicked")
+ end
+ end
+
+ if hide and (which == self.which) and (index ~= 3 or not info.noCloseOnAlt) then
+ self:Hide()
+ end
+end
+
+function E:StaticPopup_EditBoxOnEnterPressed()
+ local EditBoxOnEnterPressed, which, dialog
+ local parent = self:GetParent()
+ if parent.which then
+ which = parent.which
+ dialog = parent
+ elseif parent:GetParent().which then
+ -- This is needed if this is a money input frame since it's nested deeper than a normal edit box
+ which = parent:GetParent().which
+ dialog = parent:GetParent()
+ end
+ if not self.autoCompleteParams or not AutoCompleteEditBox_OnEnterPressed(self) then
+ EditBoxOnEnterPressed = E.PopupDialogs[which].EditBoxOnEnterPressed
+ if EditBoxOnEnterPressed then
+ EditBoxOnEnterPressed(self, dialog.data)
+ end
+ end
+end
+
+function E:StaticPopup_EditBoxOnEscapePressed()
+ local EditBoxOnEscapePressed = E.PopupDialogs[self:GetParent().which].EditBoxOnEscapePressed
+ if EditBoxOnEscapePressed then
+ EditBoxOnEscapePressed(self, self:GetParent().data)
+ end
+end
+
+function E:StaticPopup_EditBoxOnTextChanged(userInput)
+ if not self.autoCompleteParams or not AutoCompleteEditBox_OnTextChanged(self, userInput) then
+ local EditBoxOnTextChanged = E.PopupDialogs[self:GetParent().which].EditBoxOnTextChanged
+ if EditBoxOnTextChanged then
+ EditBoxOnTextChanged(self, self:GetParent().data)
+ end
+ end
+end
+
+function E:StaticPopup_FindVisible(which, data)
+ local info = E.PopupDialogs[which]
+ if not info then
+ return nil
+ end
+ for index = 1, MAX_STATIC_POPUPS do
+ local frame = _G["ElvUI_StaticPopup"..index]
+ if frame and frame:IsShown() and (frame.which == which) and (not info.multiple or (frame.data == data)) then
+ return frame
+ end
+ end
+ return nil
+end
+
+function E:StaticPopup_Resize(dialog, which)
+ local info = E.PopupDialogs[which]
+ if not info then
+ return nil
+ end
+
+ local name = dialog:GetName()
+ local text = _G[name.."Text"]
+ local editBox = _G[name.."EditBox"]
+ local button1 = _G[name.."Button1"]
+
+ local maxHeightSoFar, maxWidthSoFar = (dialog.maxHeightSoFar or 0), (dialog.maxWidthSoFar or 0)
+ local width = 320
+
+ if dialog.numButtons == 3 then
+ width = 440
+ elseif info.showAlert or info.showAlertGear or info.closeButton then
+ width = 420
+ elseif info.editBoxWidth and info.editBoxWidth > 260 then
+ width = width + (info.editBoxWidth - 260)
+ end
+
+ if width > maxWidthSoFar then
+ dialog:Width(width)
+ dialog.maxWidthSoFar = width
+ end
+
+ local height = 32 + text:GetHeight() + 8 + button1:GetHeight()
+ if info.hasEditBox then
+ height = height + 8 + editBox:GetHeight()
+ elseif info.hasMoneyFrame then
+ height = height + 16
+ elseif info.hasMoneyInputFrame then
+ height = height + 22
+ end
+ if info.hasItemFrame then
+ height = height + 64
+ end
+
+ if height > maxHeightSoFar then
+ dialog:Height(height)
+ dialog.maxHeightSoFar = height
+ end
+end
+
+function E:StaticPopup_OnEvent()
+ self.maxHeightSoFar = 0
+ E:StaticPopup_Resize(self, self.which)
+end
+
+local tempButtonLocs = {} --So we don't make a new table each time.
+function E:StaticPopup_Show(which, text_arg1, text_arg2, data)
+ local info = E.PopupDialogs[which]
+ if not info then
+ return nil
+ end
+
+ if not info.whileDead and UnitIsDeadOrGhost("player") then
+ if info.OnCancel then
+ info.OnCancel()
+ end
+ return nil
+ end
+
+ if not info.interruptCinematic and InCinematic() then
+ if info.OnCancel then
+ info.OnCancel()
+ end
+ return nil
+ end
+
+ if info.cancels then
+ for index = 1, MAX_STATIC_POPUPS do
+ local frame = _G["ElvUI_StaticPopup"..index]
+ if frame:IsShown() and (frame.which == info.cancels) then
+ frame:Hide()
+ local OnCancel = E.PopupDialogs[frame.which].OnCancel
+ if OnCancel then
+ OnCancel(frame, frame.data, "override")
+ end
+ end
+ end
+ end
+
+ -- Pick a free dialog to use, find an open dialog of the requested type
+ local dialog = E:StaticPopup_FindVisible(which, data)
+ if dialog then
+ if not info.noCancelOnReuse then
+ local OnCancel = info.OnCancel
+ if OnCancel then
+ OnCancel(dialog, dialog.data, "override")
+ end
+ end
+ dialog:Hide()
+ end
+ if not dialog then
+ -- Find a free dialog
+ local index = 1
+ if info.preferredIndex then
+ index = info.preferredIndex
+ end
+ for i = index, MAX_STATIC_POPUPS do
+ local frame = _G["ElvUI_StaticPopup"..i]
+ if frame and not frame:IsShown() then
+ dialog = frame
+ break
+ end
+ end
+
+ --If dialog not found and there's a preferredIndex then try to find an available frame before the preferredIndex
+ if not dialog and info.preferredIndex then
+ for i = 1, info.preferredIndex do
+ local frame = _G["ElvUI_StaticPopup"..i]
+ if frame and not frame:IsShown() then
+ dialog = frame
+ break
+ end
+ end
+ end
+ end
+ if not dialog then
+ if info.OnCancel then
+ info.OnCancel()
+ end
+ return nil
+ end
+
+ dialog.maxHeightSoFar, dialog.maxWidthSoFar = 0, 0
+ -- Set the text of the dialog
+ local name = dialog:GetName()
+ local text = _G[name.."Text"]
+ text:SetFormattedText(info.text, text_arg1, text_arg2)
+
+ if info.closeButton then
+ local closeButton = _G[name.."CloseButton"]
+ if info.closeButtonIsHide then
+ closeButton:SetNormalTexture("Interface\\Buttons\\UI-Panel-HideButton-Up")
+ closeButton:SetPushedTexture("Interface\\Buttons\\UI-Panel-HideButton-Down")
+ else
+ closeButton:SetNormalTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Up")
+ closeButton:SetPushedTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Down")
+ end
+ closeButton:Show()
+ else
+ _G[name.."CloseButton"]:Hide()
+ end
+
+ -- Set the editbox of the dialog
+ local editBox = _G[name.."EditBox"]
+ if info.hasEditBox then
+ editBox:Show()
+
+ if info.maxLetters then
+ editBox:SetMaxLetters(info.maxLetters)
+ editBox:SetCountInvisibleLetters(info.countInvisibleLetters)
+ end
+ if info.maxBytes then
+ editBox:SetMaxBytes(info.maxBytes)
+ end
+ editBox:SetText("")
+ if info.editBoxWidth then
+ editBox:Width(info.editBoxWidth)
+ else
+ editBox:Width(130)
+ end
+ else
+ editBox:Hide()
+ end
+
+ -- Show or hide money frame
+ if info.hasMoneyFrame then
+ _G[name.."MoneyFrame"]:Show()
+ _G[name.."MoneyInputFrame"]:Hide()
+ elseif info.hasMoneyInputFrame then
+ local moneyInputFrame = _G[name.."MoneyInputFrame"]
+ moneyInputFrame:Show()
+ _G[name.."MoneyFrame"]:Hide()
+ -- Set OnEnterPress for money input frames
+ if info.EditBoxOnEnterPressed then
+ moneyInputFrame.gold:SetScript("OnEnterPressed", E.StaticPopup_EditBoxOnEnterPressed)
+ moneyInputFrame.silver:SetScript("OnEnterPressed", E.StaticPopup_EditBoxOnEnterPressed)
+ moneyInputFrame.copper:SetScript("OnEnterPressed", E.StaticPopup_EditBoxOnEnterPressed)
+ else
+ moneyInputFrame.gold:SetScript("OnEnterPressed", nil)
+ moneyInputFrame.silver:SetScript("OnEnterPressed", nil)
+ moneyInputFrame.copper:SetScript("OnEnterPressed", nil)
+ end
+ else
+ _G[name.."MoneyFrame"]:Hide()
+ _G[name.."MoneyInputFrame"]:Hide()
+ end
+
+ -- Show or hide item button
+ if info.hasItemFrame then
+ _G[name.."ItemFrame"]:Show()
+ if data and type(data) == "table" then
+ _G[name.."ItemFrame"].link = data.link
+ _G[name.."ItemFrameIconTexture"]:SetTexture(data.texture)
+ local nameText = _G[name.."ItemFrameText"]
+ nameText:SetTextColor(unpack(data.color or {1, 1, 1, 1}))
+ nameText:SetText(data.name)
+ if data.count and data.count > 1 then
+ _G[name.."ItemFrameCount"]:SetText(data.count)
+ _G[name.."ItemFrameCount"]:Show()
+ else
+ _G[name.."ItemFrameCount"]:Hide()
+ end
+ end
+ else
+ _G[name.."ItemFrame"]:Hide()
+ end
+
+ -- Set the miscellaneous variables for the dialog
+ dialog.which = which
+ dialog.timeleft = info.timeout
+ dialog.hideOnEscape = info.hideOnEscape
+ dialog.exclusive = info.exclusive
+ dialog.enterClicksFirstButton = info.enterClicksFirstButton
+ -- Clear out data
+ dialog.data = data
+
+ -- Set the buttons of the dialog
+ local button1 = _G[name.."Button1"]
+ local button2 = _G[name.."Button2"]
+ local button3 = _G[name.."Button3"]
+
+ do --If there is any recursion in this block, we may get errors (tempButtonLocs is static). If you have to recurse, we'll have to create a new table each time.
+ assert(#tempButtonLocs == 0) --If this fails, we're recursing. (See the table.wipe at the end of the block)
+
+ tinsert(tempButtonLocs, button1)
+ tinsert(tempButtonLocs, button2)
+ tinsert(tempButtonLocs, button3)
+
+ for i = #tempButtonLocs, 1, -1 do
+ --Do this stuff before we move it. (This is why we go back-to-front)
+ tempButtonLocs[i]:SetText(info["button"..i])
+ tempButtonLocs[i]:Hide()
+ tempButtonLocs[i]:ClearAllPoints()
+ --Now we possibly remove it.
+ if not (info["button"..i] and ( not info["DisplayButton"..i] or info["DisplayButton"..i](dialog))) then
+ tremove(tempButtonLocs, i)
+ end
+ end
+
+ local numButtons = #tempButtonLocs
+ --Save off the number of buttons.
+ dialog.numButtons = numButtons
+
+ if numButtons == 3 then
+ tempButtonLocs[1]:Point("BOTTOMRIGHT", dialog, "BOTTOM", -72, 16)
+ elseif numButtons == 2 then
+ tempButtonLocs[1]:Point("BOTTOMRIGHT", dialog, "BOTTOM", -6, 16)
+ elseif numButtons == 1 then
+ tempButtonLocs[1]:Point("BOTTOM", dialog, "BOTTOM", 0, 16)
+ end
+
+ for i = 1, numButtons do
+ if i > 1 then
+ tempButtonLocs[i]:Point("LEFT", tempButtonLocs[i - 1], "RIGHT", 13, 0)
+ end
+
+ local width = tempButtonLocs[i]:GetTextWidth()
+ if width > 110 then
+ tempButtonLocs[i]:Width(width + 20)
+ else
+ tempButtonLocs[i]:Width(120)
+ end
+ tempButtonLocs[i]:Enable()
+ tempButtonLocs[i]:Show()
+ end
+
+ wipe(tempButtonLocs)
+ end
+
+ -- Show or hide the alert icon
+ local alertIcon = _G[name.."AlertIcon"]
+ if info.showAlert then
+ alertIcon:SetTexture(STATICPOPUP_TEXTURE_ALERT)
+ if button3:IsShown() then
+ alertIcon:Point("LEFT", 24, 10)
+ else
+ alertIcon:Point("LEFT", 24, 0)
+ end
+ alertIcon:Show()
+ elseif info.showAlertGear then
+ alertIcon:SetTexture(STATICPOPUP_TEXTURE_ALERTGEAR)
+ if button3:IsShown() then
+ alertIcon:Point("LEFT", 24, 0)
+ else
+ alertIcon:Point("LEFT", 24, 0)
+ end
+ alertIcon:Show()
+ else
+ alertIcon:SetTexture()
+ alertIcon:Hide()
+ end
+
+ if info.StartDelay then
+ dialog.startDelay = info.StartDelay()
+ button1:Disable()
+ else
+ dialog.startDelay = nil
+ button1:Enable()
+ end
+
+ editBox.autoCompleteParams = info.autoCompleteParams
+ editBox.autoCompleteRegex = info.autoCompleteRegex
+ editBox.autoCompleteFormatRegex = info.autoCompleteFormatRegex
+
+ editBox.addHighlightedText = true
+
+ -- Finally size and show the dialog
+ E:StaticPopup_SetUpPosition(dialog)
+ dialog:Show()
+
+ E:StaticPopup_Resize(dialog, which)
+
+ if info.sound then
+ PlaySound(info.sound)
+ end
+
+ return dialog
+end
+
+function E:StaticPopup_Hide(which, data)
+ for index = 1, MAX_STATIC_POPUPS do
+ local dialog = _G["ElvUI_StaticPopup"..index]
+ if (dialog.which == which) and (not data or (data == dialog.data)) then
+ dialog:Hide()
+ end
+ end
+end
+
+function E:Contruct_StaticPopups()
+ E.StaticPopupFrames = {}
+
+ for index = 1, MAX_STATIC_POPUPS do
+ E.StaticPopupFrames[index] = CreateFrame("Frame", "ElvUI_StaticPopup"..index, E.UIParent, "StaticPopupTemplate")
+ E.StaticPopupFrames[index]:SetID(index)
+
+ --Fix Scripts
+ E.StaticPopupFrames[index]:SetScript("OnShow", E.StaticPopup_OnShow)
+ E.StaticPopupFrames[index]:SetScript("OnHide", E.StaticPopup_OnHide)
+ E.StaticPopupFrames[index]:SetScript("OnUpdate", E.StaticPopup_OnUpdate)
+ E.StaticPopupFrames[index]:SetScript("OnEvent", E.StaticPopup_OnEvent)
+
+ local name = E.StaticPopupFrames[index]:GetName()
+ for i = 1, 3 do
+ _G[name.."Button"..i]:SetScript("OnClick", function(button)
+ E.StaticPopup_OnClick(button:GetParent(), button:GetID())
+ end)
+ end
+
+ _G[name.."EditBox"]:SetScript("OnEnterPressed", E.StaticPopup_EditBoxOnEnterPressed)
+ _G[name.."EditBox"]:SetScript("OnEscapePressed", E.StaticPopup_EditBoxOnEscapePressed)
+ _G[name.."EditBox"]:SetScript("OnTextChanged", E.StaticPopup_EditBoxOnTextChanged)
+
+ --Skin
+ E.StaticPopupFrames[index]:SetTemplate("Transparent")
+
+ for i = 1, 3 do
+ Skins:HandleButton(_G[name.."Button"..i])
+ end
+
+ Skins:HandleEditBox(_G[name.."EditBox"])
+ for k = 1, _G[name.."EditBox"]:GetNumRegions() do
+ local region = select(k, _G[name.."EditBox"]:GetRegions())
+ if region and region:IsObjectType("Texture") then
+ if region:GetTexture() == "Interface\\ChatFrame\\UI-ChatInputBorder-Left" or region:GetTexture() == "Interface\\ChatFrame\\UI-ChatInputBorder-Right" then
+ region:Kill()
+ end
+ end
+ end
+ Skins:HandleEditBox(_G[name.."MoneyInputFrameGold"])
+ Skins:HandleEditBox(_G[name.."MoneyInputFrameSilver"])
+ Skins:HandleEditBox(_G[name.."MoneyInputFrameCopper"])
+ _G[name.."EditBox"].backdrop:Point("TOPLEFT", -2, -4)
+ _G[name.."EditBox"].backdrop:Point("BOTTOMRIGHT", 2, 4)
+ _G[name.."ItemFrameNameFrame"]:Kill()
+ _G[name.."ItemFrame"]:GetNormalTexture():Kill()
+ _G[name.."ItemFrame"]:SetTemplate("Default")
+ _G[name.."ItemFrame"]:StyleButton()
+ _G[name.."ItemFrameIconTexture"]:SetTexCoord(unpack(E.TexCoords))
+ _G[name.."ItemFrameIconTexture"]:SetInside()
+ end
+
+ E:SecureHook("StaticPopup_SetUpPosition")
+ E:SecureHook("StaticPopup_CollapseTable")
+end
\ No newline at end of file
diff --git a/ElvUI/Core/StatusReport.lua b/ElvUI/Core/StatusReport.lua
new file mode 100644
index 0000000..d04a5af
--- /dev/null
+++ b/ElvUI/Core/StatusReport.lua
@@ -0,0 +1,208 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local Skins = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetAddOnInfo = GetAddOnInfo
+local GetCurrentResolution = GetCurrentResolution
+local GetCVar = GetCVar
+local GetLocale = GetLocale
+local GetNumAddOns = GetNumAddOns
+local GetRealZoneText = GetRealZoneText
+local GetScreenResolutions = GetScreenResolutions
+
+local function AreOtherAddOnsEnabled()
+ local name, loadable, reason, _
+ for i = 1, GetNumAddOns() do
+ name, _, _, loadable, reason = GetAddOnInfo(i)
+ if (name ~= "ElvUI" and name ~= "ElvUI_OptionsUI") and (loadable or (not loadable and reason == "DEMAND_LOADED")) then --Loaded or load on demand
+ return "Yes"
+ end
+ end
+
+ return "No"
+end
+
+local function GetDisplayMode()
+ local window, maximize = GetCVar("gxWindow"), GetCVar("gxMaximize")
+ local displayMode
+
+ if window == "1" then
+ if maximize == "1" then
+ displayMode = "Windowed (Fullscreen)"
+ else
+ displayMode = "Windowed"
+ end
+ else
+ displayMode = "Fullscreen"
+ end
+
+ return displayMode
+end
+
+local function GetResolution()
+ return (({GetScreenResolutions()})[GetCurrentResolution()] or GetCVar("gxWindowedResolution"))
+end
+
+function E:CreateStatusFrame()
+ local function CreateSection(width, height, parent, anchor1, anchorTo, anchor2, yOffset)
+ local section = CreateFrame("Frame", nil, parent)
+ section:Size(width, height)
+ section:Point(anchor1, anchorTo, anchor2, 0, yOffset)
+
+ section.Header = CreateFrame("Frame", nil, section)
+ section.Header:Size(300, 30)
+ section.Header:Point("TOP", section)
+
+ section.Header.Text = section.Header:CreateFontString(nil, "ARTWORK", "NumberFont_Outline_Large")
+ section.Header.Text:Point("TOP")
+ section.Header.Text:Point("BOTTOM")
+ section.Header.Text:SetJustifyH("CENTER")
+ section.Header.Text:SetJustifyV("MIDDLE")
+ local font, fontHeight, flags = section.Header.Text:GetFont()
+ section.Header.Text:SetFont(font, fontHeight*1.3, flags)
+
+ section.Header.LeftDivider = section.Header:CreateTexture(nil, "ARTWORK")
+ section.Header.LeftDivider:Height(8)
+ section.Header.LeftDivider:Point("LEFT", section.Header, "LEFT", 5, 0)
+ section.Header.LeftDivider:Point("RIGHT", section.Header.Text, "LEFT", -5, 0)
+ section.Header.LeftDivider:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
+ section.Header.LeftDivider:SetTexCoord(0.81, 0.94, 0.5, 1)
+
+ section.Header.RightDivider = section.Header:CreateTexture(nil, "ARTWORK")
+ section.Header.RightDivider:Height(8)
+ section.Header.RightDivider:Point("RIGHT", section.Header, "RIGHT", -5, 0)
+ section.Header.RightDivider:Point("LEFT", section.Header.Text, "RIGHT", 5, 0)
+ section.Header.RightDivider:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
+ section.Header.RightDivider:SetTexCoord(0.81, 0.94, 0.5, 1)
+
+ return section
+ end
+
+ local function CreateContentLines(num, parent, anchorTo)
+ local content = CreateFrame("Frame", nil, parent)
+ content:Size(240, (num * 20) + ((num - 1) * 5)) --20 height and 5 spacing
+ content:Point("TOP", anchorTo, "BOTTOM", 0, -5)
+ for i = 1, num do
+ local line = CreateFrame("Frame", nil, content)
+ line:Size(240, 20)
+ line.Text = line:CreateFontString(nil, "ARTWORK", "NumberFont_Outline_Large")
+ line.Text:SetAllPoints()
+ line.Text:SetJustifyH("LEFT")
+ line.Text:SetJustifyV("MIDDLE")
+ content["Line"..i] = line
+
+ if i == 1 then
+ content["Line"..i]:Point("TOP", content, "TOP")
+ else
+ content["Line"..i]:Point("TOP", content["Line"..(i - 1)], "BOTTOM", 0, -5)
+ end
+ end
+
+ return content
+ end
+
+ --Main frame
+ local StatusFrame = CreateFrame("Frame", "ElvUIStatusReport", E.UIParent)
+ StatusFrame:Size(300, 640)
+ StatusFrame:Point("CENTER", E.UIParent, "CENTER")
+ StatusFrame:SetFrameStrata("HIGH")
+ StatusFrame:CreateBackdrop("Transparent", nil, true)
+ StatusFrame:Hide()
+ StatusFrame:CreateCloseButton()
+ StatusFrame:SetClampedToScreen(true)
+ StatusFrame:SetMovable(true)
+ StatusFrame:EnableMouse(true)
+ StatusFrame:RegisterForDrag("LeftButton", "RightButton")
+ StatusFrame:SetScript("OnDragStart", function(self)
+ self:StartMoving()
+ end)
+ StatusFrame:SetScript("OnDragStop", function(self)
+ self:StopMovingOrSizing()
+ end)
+
+ --Title logo
+ StatusFrame.TitleLogoFrame = CreateFrame("Frame", nil, StatusFrame)
+ StatusFrame.TitleLogoFrame:Size(128, 64)
+ StatusFrame.TitleLogoFrame:Point("CENTER", StatusFrame, "TOP", 0, 0)
+ StatusFrame.TitleLogoFrame.Texture = StatusFrame.TitleLogoFrame:CreateTexture(nil, "ARTWORK")
+ StatusFrame.TitleLogoFrame.Texture:SetTexture(E.Media.Textures.Logo)
+ StatusFrame.TitleLogoFrame.Texture:SetAllPoints()
+
+ --Sections
+ StatusFrame.Section1 = CreateSection(300, 150, StatusFrame, "TOP", StatusFrame, "TOP", -30)
+ StatusFrame.Section2 = CreateSection(300, 175, StatusFrame, "TOP", StatusFrame.Section1, "BOTTOM", 0)
+ StatusFrame.Section3 = CreateSection(300, 220, StatusFrame, "TOP", StatusFrame.Section2, "BOTTOM", 0)
+ StatusFrame.Section4 = CreateSection(300, 60, StatusFrame, "TOP", StatusFrame.Section3, "BOTTOM", 0)
+
+ --Section headers
+ StatusFrame.Section1.Header.Text:SetText("|cfffe7b2cAddOn Info|r")
+ StatusFrame.Section2.Header.Text:SetText("|cfffe7b2cWoW Info|r")
+ StatusFrame.Section3.Header.Text:SetText("|cfffe7b2cCharacter Info|r")
+ StatusFrame.Section4.Header.Text:SetText("|cfffe7b2cExport To|r")
+
+ --Section content
+ StatusFrame.Section1.Content = CreateContentLines(4, StatusFrame.Section1, StatusFrame.Section1.Header)
+ StatusFrame.Section2.Content = CreateContentLines(5, StatusFrame.Section2, StatusFrame.Section2.Header)
+ StatusFrame.Section3.Content = CreateContentLines(5, StatusFrame.Section3, StatusFrame.Section3.Header)
+ StatusFrame.Section4.Content = CreateFrame("Frame", nil, StatusFrame.Section4)
+ StatusFrame.Section4.Content:Size(240, 25)
+ StatusFrame.Section4.Content:Point("TOP", StatusFrame.Section4.Header, "BOTTOM", 0, 0)
+
+ --Content lines
+ StatusFrame.Section1.Content.Line1.Text:SetFormattedText("Version of ElvUI: |cff4beb2c%s|r", E.version)
+ StatusFrame.Section1.Content.Line2.Text:SetFormattedText("Other AddOns Enabled: |cff4beb2c%s|r", AreOtherAddOnsEnabled())
+ StatusFrame.Section1.Content.Line3.Text:SetFormattedText("Recommended Scale: |cff4beb2c%s|r", E:PixelBestSize())
+ StatusFrame.Section1.Content.Line4.Text:SetFormattedText("UI Scale Is: |cff4beb2c%s|r", E.global.general.UIScale)
+
+ StatusFrame.Section2.Content.Line1.Text:SetFormattedText("Version of WoW: |cff4beb2c%s (build %s)|r", E.wowpatch, E.wowbuild)
+ StatusFrame.Section2.Content.Line2.Text:SetFormattedText("Client Language: |cff4beb2c%s|r", GetLocale())
+ StatusFrame.Section2.Content.Line3.Text:SetFormattedText("Display Mode: |cff4beb2c%s|r", GetDisplayMode())
+ StatusFrame.Section2.Content.Line4.Text:SetFormattedText("Resolution: |cff4beb2c%s|r", GetResolution())
+ StatusFrame.Section2.Content.Line5.Text:SetFormattedText("Using Mac Client: |cff4beb2c%s|r", (E.isMacClient == true and "Yes" or "No"))
+
+ StatusFrame.Section3.Content.Line1.Text:SetFormattedText("Faction: |cff4beb2c%s|r", E.myfaction)
+ StatusFrame.Section3.Content.Line2.Text:SetFormattedText("Race: |cff4beb2c%s|r", E.myrace)
+ StatusFrame.Section3.Content.Line3.Text:SetFormattedText("Level: |cff4beb2c%s|r", E.mylevel)
+ StatusFrame.Section3.Content.Line4.Text:SetFormattedText("Zone: |cff4beb2c%s|r", GetRealZoneText())
+ StatusFrame.Section3.Content.Line5.Text:SetFormattedText("Realm: |cff4beb2c%s|r", E.myrealm)
+
+ --Export buttons
+ StatusFrame.Section4.Content.Button1 = CreateFrame("Button", nil, StatusFrame.Section4.Content, "UIPanelButtonTemplate")
+ StatusFrame.Section4.Content.Button1:Size(100, 25)
+ StatusFrame.Section4.Content.Button1:Point("LEFT", StatusFrame.Section4.Content, "LEFT")
+ StatusFrame.Section4.Content.Button1:SetText("Forum")
+ StatusFrame.Section4.Content.Button1:SetButtonState("DISABLED")
+ Skins:HandleButton(StatusFrame.Section4.Content.Button1, true)
+
+ StatusFrame.Section4.Content.Button2 = CreateFrame("Button", nil, StatusFrame.Section4.Content, "UIPanelButtonTemplate")
+ StatusFrame.Section4.Content.Button2:Size(100, 25)
+ StatusFrame.Section4.Content.Button2:Point("RIGHT", StatusFrame.Section4.Content, "RIGHT")
+ StatusFrame.Section4.Content.Button2:SetText("Ticket")
+ StatusFrame.Section4.Content.Button2:SetButtonState("DISABLED")
+ Skins:HandleButton(StatusFrame.Section4.Content.Button2, true)
+
+ E.StatusFrame = StatusFrame
+end
+
+local function UpdateDynamicValues()
+ E.StatusFrame.Section2.Content.Line3.Text:SetFormattedText("Display Mode: |cff4beb2c%s|r", GetDisplayMode())
+ E.StatusFrame.Section2.Content.Line4.Text:SetFormattedText("Resolution: |cff4beb2c%s|r", GetResolution())
+ E.StatusFrame.Section3.Content.Line3.Text:SetFormattedText("Level: |cff4beb2c%s|r", E.mylevel)
+ E.StatusFrame.Section3.Content.Line4.Text:SetFormattedText("Zone: |cff4beb2c%s|r", GetRealZoneText())
+end
+
+function E:ShowStatusReport()
+ if not self.StatusFrame then
+ self:CreateStatusFrame()
+ end
+
+ if not self.StatusFrame:IsShown() then
+ UpdateDynamicValues()
+ self.StatusFrame:Raise() --Set framelevel above everything else
+ self.StatusFrame:Show()
+ else
+ self.StatusFrame:Hide()
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Core/Tags.lua b/ElvUI/Core/Tags.lua
new file mode 100644
index 0000000..845baa9
--- /dev/null
+++ b/ElvUI/Core/Tags.lua
@@ -0,0 +1,756 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local ElvUF = E.oUF
+
+local Translit = E.Libs.Translit
+local translitMark = "!"
+
+--Lua functions
+local select = select
+local tonumber = tonumber
+local find = string.find
+local floor = math.floor
+local format = string.format
+local gmatch = gmatch
+local gsub = gsub
+local match = string.match
+local utf8lower = string.utf8lower
+local utf8sub = string.utf8sub
+--WoW API / Variables
+local GetGuildInfo = GetGuildInfo
+local GetInstanceInfo = GetInstanceInfo
+local GetNumPartyMembers = GetNumPartyMembers
+local GetPVPTimer = GetPVPTimer
+local GetQuestGreenRange = GetQuestGreenRange
+local GetThreatStatusColor = GetThreatStatusColor
+local GetTime = GetTime
+local GetUnitSpeed = GetUnitSpeed
+local UnitClass = UnitClass
+local UnitClassification = UnitClassification
+local UnitDetailedThreatSituation = UnitDetailedThreatSituation
+local UnitExists = UnitExists
+local UnitGUID = UnitGUID
+local UnitHealth = UnitHealth
+local UnitHealthMax = UnitHealthMax
+local UnitIsAFK = UnitIsAFK
+local UnitIsConnected = UnitIsConnected
+local UnitIsDND = UnitIsDND
+local UnitIsDead = UnitIsDead
+local UnitIsDeadOrGhost = UnitIsDeadOrGhost
+local UnitIsGhost = UnitIsGhost
+local UnitIsPVP = UnitIsPVP
+local UnitIsPVPFreeForAll = UnitIsPVPFreeForAll
+local UnitIsPlayer = UnitIsPlayer
+local UnitIsUnit = UnitIsUnit
+local UnitLevel = UnitLevel
+local UnitName = UnitName
+local UnitPVPName = UnitPVPName
+local UnitPower = UnitPower
+local UnitPowerMax = UnitPowerMax
+local UnitPowerType = UnitPowerType
+local UnitReaction = UnitReaction
+local DEFAULT_AFK_MESSAGE = DEFAULT_AFK_MESSAGE
+local SPELL_POWER_MANA = SPELL_POWER_MANA
+local PVP = PVP
+
+------------------------------------------------------------------------
+-- Tags
+------------------------------------------------------------------------
+
+local function abbrev(name)
+ local letters, lastWord = "", match(name, ".+%s(.+)$")
+ if lastWord then
+ for word in gmatch(name, ".-%s") do
+ local firstLetter = utf8sub(gsub(word, "^[%s%p]*", ""), 1, 1)
+ if firstLetter ~= utf8lower(firstLetter) then
+ letters = format("%s%s. ", letters, firstLetter)
+ end
+ end
+ name = format("%s%s", letters, lastWord)
+ end
+ return name
+end
+
+ElvUF.Tags.Events["afk"] = "PLAYER_FLAGS_CHANGED"
+ElvUF.Tags.Methods["afk"] = function(unit)
+ local isAFK = UnitIsAFK(unit)
+ if isAFK then
+ return format("|cffFFFFFF[|r|cffFF0000%s|r|cFFFFFFFF]|r", DEFAULT_AFK_MESSAGE)
+ else
+ return nil
+ end
+end
+
+ElvUF.Tags.Events["healthcolor"] = "UNIT_HEALTH UNIT_CONNECTION PLAYER_FLAGS_CHANGED"
+ElvUF.Tags.Methods["healthcolor"] = function(unit)
+ if UnitIsDeadOrGhost(unit) or not UnitIsConnected(unit) then
+ return Hex(0.84, 0.75, 0.65)
+ else
+ local r, g, b = ElvUF:ColorGradient(UnitHealth(unit), UnitHealthMax(unit), 0.69, 0.31, 0.31, 0.65, 0.63, 0.35, 0.33, 0.59, 0.33)
+ return Hex(r, g, b)
+ end
+end
+
+ElvUF.Tags.Events["name:abbrev"] = "UNIT_NAME_UPDATE"
+ElvUF.Tags.Methods["name:abbrev"] = function(unit)
+ local name = UnitName(unit)
+
+ if name and find(name, "%s") then
+ name = abbrev(name)
+ end
+
+ return name ~= nil and name or ""
+end
+
+for textFormat in pairs(E.GetFormattedTextStyles) do
+ local tagTextFormat = strlower(gsub(textFormat, "_", "-"))
+ ElvUF.Tags.Events[format("health:%s", tagTextFormat)] = "UNIT_HEALTH UNIT_MAXHEALTH UNIT_CONNECTION PLAYER_FLAGS_CHANGED"
+ ElvUF.Tags.Methods[format("health:%s", tagTextFormat)] = function(unit)
+ local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
+ if status then
+ return status
+ else
+ return E:GetFormattedText(textFormat, UnitHealth(unit), UnitHealthMax(unit))
+ end
+ end
+
+ ElvUF.Tags.Events[format("health:%s-nostatus", tagTextFormat)] = "UNIT_HEALTH_FREQUENT UNIT_MAXHEALTH"
+ ElvUF.Tags.Methods[format("health:%s-nostatus", tagTextFormat)] = function(unit)
+ return E:GetFormattedText(textFormat, UnitHealth(unit), UnitHealthMax(unit))
+ end
+
+ ElvUF.Tags.Events[format("power:%s", tagTextFormat)] = "UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_MAXRUNIC_POWER UNIT_RUNIC_POWER"
+ ElvUF.Tags.Methods[format("power:%s", tagTextFormat)] = function(unit)
+ local pType = UnitPowerType(unit)
+ local min = UnitPower(unit, pType)
+
+ if min == 0 and tagTextFormat ~= "deficit" then
+ return ""
+ else
+ return E:GetFormattedText(textFormat, UnitPower(unit, pType), UnitPowerMax(unit, pType))
+ end
+ end
+
+ ElvUF.Tags.Events[format("mana:%s", tagTextFormat)] = "UNIT_MANA UNIT_MAXMANA"
+ ElvUF.Tags.Methods[format("mana:%s", tagTextFormat)] = function(unit)
+ local min = UnitPower(unit, SPELL_POWER_MANA)
+
+ if min == 0 and tagTextFormat ~= "deficit" then
+ return ""
+ else
+ return E:GetFormattedText(textFormat, UnitPower(unit, SPELL_POWER_MANA), UnitPowerMax(unit, SPELL_POWER_MANA))
+ end
+ end
+
+ ElvUF.Tags.Events[format("energy:%s", tagTextFormat)] = "UNIT_MAXENERGY UNIT_ENERGY_FREQUENT"
+ ElvUF.Tags.Methods[format("energy:%s", tagTextFormat)] = function(unit)
+ local min = UnitPower(unit, 3)
+
+ if min == 0 and tagTextFormat ~= "deficit" then
+ return ""
+ else
+ return E:GetFormattedText(textFormat, UnitPower(unit, 3), UnitPowerMax(unit, 3))
+ end
+ end
+
+ ElvUF.Tags.Events[format("rage:%s", tagTextFormat)] = "UNIT_MAXRAGE UNIT_RAGE_FREQUENT"
+ ElvUF.Tags.Methods[format("rage:%s", tagTextFormat)] = function(unit)
+ local min = UnitPower(unit, 1)
+
+ if min == 0 and tagTextFormat ~= "deficit" then
+ return ""
+ else
+ return E:GetFormattedText(textFormat, UnitPower(unit, 1), UnitPowerMax(unit, 1))
+ end
+ end
+end
+
+for textFormat, length in pairs({veryshort = 5, short = 10, medium = 15, long = 20}) do
+ ElvUF.Tags.Events[format("health:deficit-percent:name-%s", textFormat)] = "UNIT_HEALTH UNIT_MAXHEALTH UNIT_CONNECTION PLAYER_FLAGS_CHANGED"
+ ElvUF.Tags.Methods[format("health:deficit-percent:name-%s", textFormat)] = function(unit)
+ local cur, max = UnitHealth(unit), UnitHealthMax(unit)
+ local deficit = max - cur
+
+ if deficit > 0 and cur > 0 then
+ return _TAGS["health:percent-nostatus"](unit)
+ else
+ return _TAGS[format("name:%s", textFormat)](unit)
+ end
+ end
+
+ ElvUF.Tags.Events[format("name:abbrev:%s", textFormat)] = "UNIT_NAME_UPDATE"
+ ElvUF.Tags.Methods[format("name:abbrev:%s", textFormat)] = function(unit)
+ local name = UnitName(unit)
+
+ if name and find(name, "%s") then
+ name = abbrev(name)
+ end
+
+ return name ~= nil and E:ShortenString(name, length) or ""
+ end
+
+ ElvUF.Tags.Events[format("name:%s", textFormat)] = "UNIT_NAME_UPDATE"
+ ElvUF.Tags.Methods[format("name:%s", textFormat)] = function(unit)
+ local name = UnitName(unit)
+ return name ~= nil and E:ShortenString(name, length) or nil
+ end
+
+ ElvUF.Tags.Events[format("name:%s:status", textFormat)] = "UNIT_NAME_UPDATE UNIT_CONNECTION PLAYER_FLAGS_CHANGED UNIT_HEALTH_FREQUENT"
+ ElvUF.Tags.Methods[format("name:%s:status", textFormat)] = function(unit)
+ local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
+ local name = UnitName(unit)
+ if (status) then
+ return status
+ else
+ return name ~= nil and E:ShortenString(name, length) or nil
+ end
+ end
+
+ ElvUF.Tags.Events[format("name:%s:translit", textFormat)] = "UNIT_NAME_UPDATE"
+ ElvUF.Tags.Methods[format("name:%s:translit", textFormat)] = function(unit)
+ local name = Translit:Transliterate(UnitName(unit), translitMark)
+ return name ~= nil and E:ShortenString(name, length) or nil
+ end
+
+ ElvUF.Tags.Events[format("target:%s", textFormat)] = "UNIT_TARGET"
+ ElvUF.Tags.Methods[format("target:%s", textFormat)] = function(unit)
+ local targetName = UnitName(unit.."target")
+ return targetName ~= nil and E:ShortenString(targetName, length) or nil
+ end
+
+ ElvUF.Tags.Events[format("target:%s:translit", textFormat)] = "UNIT_TARGET"
+ ElvUF.Tags.Methods[format("target:%s:translit", textFormat)] = function(unit)
+ local targetName = Translit:Transliterate(UnitName(unit.."target"), translitMark)
+ return targetName ~= nil and E:ShortenString(targetName, length) or nil
+ end
+end
+
+ElvUF.Tags.Events["health:max"] = "UNIT_MAXHEALTH"
+ElvUF.Tags.Methods["health:max"] = function(unit)
+ local max = UnitHealthMax(unit)
+
+ return E:GetFormattedText("CURRENT", max, max)
+end
+
+ElvUF.Tags.Events["health:deficit-percent:name"] = "UNIT_HEALTH UNIT_MAXHEALTH"
+ElvUF.Tags.Methods["health:deficit-percent:name"] = function(unit)
+ local currentHealth = UnitHealth(unit)
+ local deficit = UnitHealthMax(unit) - currentHealth
+
+ if deficit > 0 and currentHealth > 0 then
+ return _TAGS["health:percent-nostatus"](unit)
+ else
+ return _TAGS.name(unit)
+ end
+end
+
+ElvUF.Tags.Events["power:max"] = "UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_MAXRUNIC_POWER"
+ElvUF.Tags.Methods["power:max"] = function(unit)
+ local pType = UnitPowerType(unit)
+ local max = UnitPowerMax(unit, pType)
+
+ return E:GetFormattedText("CURRENT", max, max)
+end
+
+ElvUF.Tags.Methods["manacolor"] = function()
+ local mana = PowerBarColor.MANA
+ local altR, altG, altB = mana.r, mana.g, mana.b
+ local color = ElvUF.colors.power.MANA
+ if color then
+ return Hex(color[1], color[2], color[3])
+ else
+ return Hex(altR, altG, altB)
+ end
+end
+
+ElvUF.Tags.Events["mana:max"] = "UNIT_MAXMANA"
+ElvUF.Tags.Methods["mana:max"] = function(unit)
+ local max = UnitPowerMax(unit, SPELL_POWER_MANA)
+
+ return E:GetFormattedText("CURRENT", max, max)
+end
+
+ElvUF.Tags.Events["difficultycolor"] = "UNIT_LEVEL PLAYER_LEVEL_UP"
+ElvUF.Tags.Methods["difficultycolor"] = function(unit)
+ local r, g, b
+ local level = UnitLevel(unit)
+ if level > 1 then
+ local DiffColor = UnitLevel(unit) - UnitLevel("player")
+ if DiffColor >= 5 then
+ r, g, b = 0.69, 0.31, 0.31
+ elseif DiffColor >= 3 then
+ r, g, b = 0.71, 0.43, 0.27
+ elseif DiffColor >= -2 then
+ r, g, b = 0.84, 0.75, 0.65
+ elseif -DiffColor <= GetQuestGreenRange() then
+ r, g, b = 0.33, 0.59, 0.33
+ else
+ r, g, b = 0.55, 0.57, 0.61
+ end
+ end
+
+ return Hex(r, g, b)
+end
+
+ElvUF.Tags.Events["namecolor"] = "UNIT_NAME_UPDATE UNIT_FACTION"
+ElvUF.Tags.Methods["namecolor"] = function(unit)
+ local unitReaction = UnitReaction(unit, "player")
+ local unitPlayer = UnitIsPlayer(unit)
+ if unitPlayer then
+ return Hex(E.media.herocolor.r, E.media.herocolor.g, E.media.herocolor.b)
+ elseif unitReaction then
+ local reaction = ElvUF.colors.reaction[unitReaction]
+ return Hex(reaction[1], reaction[2], reaction[3])
+ else
+ return "|cFFC2C2C2"
+ end
+end
+
+ElvUF.Tags.Events["smartlevel"] = "UNIT_LEVEL PLAYER_LEVEL_UP"
+ElvUF.Tags.Methods["smartlevel"] = function(unit)
+ local level = UnitLevel(unit)
+ if level == UnitLevel("player") then
+ return ""
+ elseif level > 0 then
+ return level
+ else
+ return "??"
+ end
+end
+
+ElvUF.Tags.Events["realm"] = "UNIT_NAME_UPDATE"
+ElvUF.Tags.Methods["realm"] = function(unit)
+ local _, realm = UnitName(unit)
+
+ if realm and realm ~= "" then
+ return realm
+ else
+ return nil
+ end
+end
+
+ElvUF.Tags.Events["realm:dash"] = "UNIT_NAME_UPDATE"
+ElvUF.Tags.Methods["realm:dash"] = function(unit)
+ local _, realm = UnitName(unit)
+
+ if realm and (realm ~= "" and realm ~= E.myrealm) then
+ realm = format("-%s", realm)
+ elseif realm == "" then
+ realm = nil
+ end
+
+ return realm
+end
+
+ElvUF.Tags.Events["realm:translit"] = "UNIT_NAME_UPDATE"
+ElvUF.Tags.Methods["realm:translit"] = function(unit)
+ local _, realm = Translit:Transliterate(UnitName(unit), translitMark)
+
+ if realm and realm ~= "" then
+ return realm
+ else
+ return nil
+ end
+end
+
+ElvUF.Tags.Events["realm:dash:translit"] = "UNIT_NAME_UPDATE"
+ElvUF.Tags.Methods["realm:dash:translit"] = function(unit)
+ local _, realm = Translit:Transliterate(UnitName(unit), translitMark)
+
+ if realm and (realm ~= "" and realm ~= E.myrealm) then
+ realm = format("-%s", realm)
+ elseif realm == "" then
+ realm = nil
+ end
+
+ return realm
+end
+
+ElvUF.Tags.Events["threat:percent"] = "UNIT_THREAT_SITUATION_UPDATE UNIT_THREAT_LIST_UPDATE"
+ElvUF.Tags.Methods["threat:percent"] = function(unit)
+ local _, _, percent = UnitDetailedThreatSituation("player", unit)
+ if percent and percent > 0 and (GetNumPartyMembers() or UnitExists("pet")) then
+ return format("%.0f%%", percent)
+ else
+ return nil
+ end
+end
+
+ElvUF.Tags.Events["threat:current"] = "UNIT_THREAT_SITUATION_UPDATE UNIT_THREAT_LIST_UPDATE"
+ElvUF.Tags.Methods["threat:current"] = function(unit)
+ local _, _, percent, _, threatvalue = UnitDetailedThreatSituation("player", unit)
+ if percent and percent > 0 and (GetNumPartyMembers() or UnitExists("pet")) then
+ return E:ShortValue(threatvalue)
+ else
+ return nil
+ end
+end
+
+ElvUF.Tags.Events["threatcolor"] = "UNIT_THREAT_SITUATION_UPDATE UNIT_THREAT_LIST_UPDATE"
+ElvUF.Tags.Methods["threatcolor"] = function(unit)
+ local _, status = UnitDetailedThreatSituation("player", unit)
+ if status and (GetNumPartyMembers() > 0 or UnitExists("pet")) then
+ return Hex(GetThreatStatusColor(status))
+ else
+ return nil
+ end
+end
+
+local unitStatus = {}
+ElvUF.Tags.OnUpdateThrottle["statustimer"] = 1
+ElvUF.Tags.Methods["statustimer"] = function(unit)
+ if not UnitIsPlayer(unit) then return end
+ local guid = UnitGUID(unit)
+ if UnitIsAFK(unit) then
+ if not unitStatus[guid] or unitStatus[guid] and unitStatus[guid][1] ~= "AFK" then
+ unitStatus[guid] = {"AFK", GetTime()}
+ end
+ elseif UnitIsDND(unit) then
+ if not unitStatus[guid] or unitStatus[guid] and unitStatus[guid][1] ~= "DND" then
+ unitStatus[guid] = {"DND", GetTime()}
+ end
+ elseif UnitIsDead(unit) or UnitIsGhost(unit) then
+ if not unitStatus[guid] or unitStatus[guid] and unitStatus[guid][1] ~= "Dead" then
+ unitStatus[guid] = {"Dead", GetTime()}
+ end
+ elseif not UnitIsConnected(unit) then
+ if not unitStatus[guid] or unitStatus[guid] and unitStatus[guid][1] ~= "Offline" then
+ unitStatus[guid] = {"Offline", GetTime()}
+ end
+ else
+ unitStatus[guid] = nil
+ end
+
+ if unitStatus[guid] ~= nil then
+ local status = unitStatus[guid][1]
+ local timer = GetTime() - unitStatus[guid][2]
+ local mins = floor(timer / 60)
+ local secs = floor(timer - (mins * 60))
+ return format("%s (%01.f:%02.f)", status, mins, secs)
+ else
+ return nil
+ end
+end
+
+ElvUF.Tags.OnUpdateThrottle["pvptimer"] = 1
+ElvUF.Tags.Methods["pvptimer"] = function(unit)
+ if UnitIsPVPFreeForAll(unit) or UnitIsPVP(unit) then
+ local timer = GetPVPTimer()
+
+ if timer ~= 301000 and timer ~= -1 then
+ local mins = floor((timer / 1000) / 60)
+ local secs = floor((timer / 1000) - (mins * 60))
+ return format("%s (%01.f:%02.f)", PVP, mins, secs)
+ else
+ return PVP
+ end
+ else
+ return nil
+ end
+end
+
+local baseSpeed = 7
+local speedText = SPEED
+
+ElvUF.Tags.OnUpdateThrottle["speed:percent"] = 0.1
+ElvUF.Tags.Methods["speed:percent"] = function(unit)
+ local currentSpeedInYards = GetUnitSpeed(unit)
+ local currentSpeedInPercent = (currentSpeedInYards / baseSpeed) * 100
+
+ return format("%s: %d%%", speedText, currentSpeedInPercent)
+end
+
+ElvUF.Tags.OnUpdateThrottle["speed:percent-moving"] = 0.1
+ElvUF.Tags.Methods["speed:percent-moving"] = function(unit)
+ local currentSpeedInYards = GetUnitSpeed(unit)
+ local currentSpeedInPercent = currentSpeedInYards > 0 and ((currentSpeedInYards / baseSpeed) * 100)
+
+ if currentSpeedInPercent then
+ currentSpeedInPercent = format("%s: %d%%", speedText, currentSpeedInPercent)
+ end
+
+ return currentSpeedInPercent or nil
+end
+
+ElvUF.Tags.OnUpdateThrottle["speed:percent-raw"] = 0.1
+ElvUF.Tags.Methods["speed:percent-raw"] = function(unit)
+ local currentSpeedInYards = GetUnitSpeed(unit)
+ local currentSpeedInPercent = (currentSpeedInYards / baseSpeed) * 100
+
+ return format("%d%%", currentSpeedInPercent)
+end
+
+ElvUF.Tags.OnUpdateThrottle["speed:percent-moving-raw"] = 0.1
+ElvUF.Tags.Methods["speed:percent-moving-raw"] = function(unit)
+ local currentSpeedInYards = GetUnitSpeed(unit)
+ local currentSpeedInPercent = currentSpeedInYards > 0 and ((currentSpeedInYards / baseSpeed) * 100)
+
+ if currentSpeedInPercent then
+ currentSpeedInPercent = format("%d%%", currentSpeedInPercent)
+ end
+
+ return currentSpeedInPercent or nil
+end
+
+ElvUF.Tags.OnUpdateThrottle["speed:yardspersec"] = 0.1
+ElvUF.Tags.Methods["speed:yardspersec"] = function(unit)
+ local currentSpeedInYards = GetUnitSpeed(unit)
+
+ return format("%s: %.1f", speedText, currentSpeedInYards)
+end
+
+ElvUF.Tags.OnUpdateThrottle["speed:yardspersec-moving"] = 0.1
+ElvUF.Tags.Methods["speed:yardspersec-moving"] = function(unit)
+ local currentSpeedInYards = GetUnitSpeed(unit)
+
+ return currentSpeedInYards > 0 and format("%s: %.1f", speedText, currentSpeedInYards) or nil
+end
+
+ElvUF.Tags.OnUpdateThrottle["speed:yardspersec-raw"] = 0.1
+ElvUF.Tags.Methods["speed:yardspersec-raw"] = function(unit)
+ local currentSpeedInYards = GetUnitSpeed(unit)
+ return format("%.1f", currentSpeedInYards)
+end
+
+ElvUF.Tags.OnUpdateThrottle["speed:yardspersec-moving-raw"] = 0.1
+ElvUF.Tags.Methods["speed:yardspersec-moving-raw"] = function(unit)
+ local currentSpeedInYards = GetUnitSpeed(unit)
+
+ return currentSpeedInYards > 0 and format("%.1f", currentSpeedInYards) or nil
+end
+
+ElvUF.Tags.Events["classificationcolor"] = "UNIT_CLASSIFICATION_CHANGED"
+ElvUF.Tags.Methods["classificationcolor"] = function(unit)
+ local c = UnitClassification(unit)
+ if c == "rare" or c == "elite" then
+ return Hex(1, 0.5, 0.25) -- Orange
+ elseif c == "rareelite" or c == "worldboss" then
+ return Hex(1, 0, 0) -- Red
+ end
+end
+
+ElvUF.Tags.SharedEvents.PLAYER_GUILD_UPDATE = true
+
+ElvUF.Tags.Events["guild"] = "UNIT_NAME_UPDATE PLAYER_GUILD_UPDATE"
+ElvUF.Tags.Methods["guild"] = function(unit)
+ if (UnitIsPlayer(unit)) then
+ return GetGuildInfo(unit) or nil
+ end
+end
+
+ElvUF.Tags.Events["guild:brackets"] = "PLAYER_GUILD_UPDATE"
+ElvUF.Tags.Methods["guild:brackets"] = function(unit)
+ local guildName = GetGuildInfo(unit)
+
+ return guildName and format("<%s>", guildName) or nil
+end
+
+ElvUF.Tags.Events["guild:translit"] = "UNIT_NAME_UPDATE PLAYER_GUILD_UPDATE"
+ElvUF.Tags.Methods["guild:translit"] = function(unit)
+ if UnitIsPlayer(unit) then
+ return Translit:Transliterate(GetGuildInfo(unit), translitMark) or nil
+ end
+end
+
+ElvUF.Tags.Events["guild:brackets:translit"] = "PLAYER_GUILD_UPDATE"
+ElvUF.Tags.Methods["guild:brackets:translit"] = function(unit)
+ local guildName = Translit:Transliterate(GetGuildInfo(unit), translitMark)
+
+ return guildName and format("<%s>", guildName) or nil
+end
+
+ElvUF.Tags.Events["target"] = "UNIT_TARGET"
+ElvUF.Tags.Methods["target"] = function(unit)
+ local targetName = UnitName(unit.."target")
+ return targetName or nil
+end
+
+ElvUF.Tags.Events["target:translit"] = "UNIT_TARGET"
+ElvUF.Tags.Methods["target:translit"] = function(unit)
+ local targetName = Translit:Transliterate(UnitName(unit.."target"), translitMark)
+ return targetName or nil
+end
+
+ElvUF.Tags.Events["guild:rank"] = "UNIT_NAME_UPDATE"
+ElvUF.Tags.Methods["guild:rank"] = function(unit)
+ if (UnitIsPlayer(unit)) then
+ return select(2, GetGuildInfo(unit)) or ""
+ end
+end
+
+ElvUF.Tags.Events["arena:number"] = "UNIT_NAME_UPDATE"
+ElvUF.Tags.Methods["arena:number"] = function(unit)
+ local _, instanceType = GetInstanceInfo()
+ if instanceType == "arena" then
+ for i = 1, 5 do
+ if UnitIsUnit(unit, "arena"..i) then
+ return i
+ end
+ end
+ end
+end
+
+ElvUF.Tags.Events["class"] = "UNIT_NAME_UPDATE"
+ElvUF.Tags.Methods["class"] = function(unit)
+ return UnitClass(unit)
+end
+
+ElvUF.Tags.Events["name:title"] = "UNIT_NAME_UPDATE"
+ElvUF.Tags.Methods["name:title"] = function(unit)
+ if UnitIsPlayer(unit) then
+ return UnitPVPName(unit)
+ end
+end
+E.TagInfo = {
+ --Colors
+ ["namecolor"] = {category = "Colors", description = "Colors names by player class or NPC reaction"},
+ ["powercolor"] = {category = "Colors", description = "Colors the power text based upon its type"},
+ ["energycolor"] = {category = "Colors", description = "Colors the energy text based upon its type"},
+ ["ragecolor"] = {category = "Colors", description = "Colors the rage text based upon its type"},
+ ["difficultycolor"] = {category = "Colors", description = "Colors the following tags by difficulty, red for impossible, orange for hard, green for easy"},
+ ["healthcolor"] = {category = "Colors", description = "Changes color of health text, depending on the unit's current health"},
+ ["threatcolor"] = {category = "Colors", description = "Changes color of health, depending on the unit's threat situation"},
+ ["classificationcolor"] = {category = "Colors", description = "Changes color of health, depending on the unit's classification"},
+ --Classification
+ ["classification"] = {category = "Classification", description = "Displays the unit's classification (e.g. 'ELITE' and 'RARE')"},
+ ["shortclassification"] = {category = "Classification", description = "Displays the unit's classification in short form (e.g. '+' for ELITE and 'R' for RARE)"},
+ ["rare"] = {category = "Classification", description = "Displays 'Rare' when the unit is a rare or rareelite"},
+ --Guild
+ ["guild"] = {category = "Guild", description = "Displays the guild name"},
+ ["guild:brackets"] = {category = "Guild", description = "Displays the guild name with < > brackets (e.g. )"},
+ ["guild:brackets:translit"] = {category = "Guild", description = "Displays the guild name with < > and transliteration (e.g. )"},
+ ["guild:rank"] = {category = "Guild", description = "Displays the guild rank"},
+ ["guild:translit"] = {category = "Guild", description = "Displays the guild name with transliteration for cyrillic letters"},
+ --Health
+ ["curhp"] = {category = "Health", description = "Displays the current HP without decimals"},
+ ["perhp"] = {category = "Health", description = "Displays percentage HP without decimals"},
+ ["maxhp"] = {category = "Health", description = "Displays max HP without decimals"},
+ ["deficit:name"] = {category = "Health", description = "Displays the health as a deficit and the name at full health"},
+ ["health:current"] = {category = "Health", description = "Displays the current health of the unit"},
+ ["health:current-max"] = {category = "Health", description = "Displays the current and maximum health of the unit, separated by a dash"},
+ ["health:current-max-nostatus"] = {category = "Health", description = "Displays the current and maximum health of the unit, separated by a dash, without status"},
+ ["health:current-max-percent"] = {category = "Health", description = "Displays the current and max hp of the unit, separated by a dash (% when not full hp)"},
+ ["health:current-max-percent-nostatus"] = {category = "Health", description = "Displays the current and max hp of the unit, separated by a dash (% when not full hp), without status"},
+ ["health:current-nostatus"] = {category = "Health", description = "Displays the current health of the unit, without status"},
+ ["health:current-percent"] = {category = "Health", description = "Displays the current hp of the unit (% when not full hp)"},
+ ["health:current-percent-nostatus"] = {category = "Health", description = "Displays the current hp of the unit (% when not full hp), without status"},
+ ["health:deficit"] = {category = "Health", description = "Displays the health of the unit as a deficit (Total Health - Current Health = -Deficit)"},
+ ["health:deficit-nostatus"] = {category = "Health", description = "Displays the health of the unit as a deficit, without status"},
+ ["health:deficit-percent:name"] = {category = "Health", description = "Displays the health deficit as a percentage and the full name of the unit"},
+ ["health:deficit-percent:name-long"] = {category = "Health", description = "Displays the health deficit as a percentage and the name of the unit (limited to 20 letters)"},
+ ["health:deficit-percent:name-medium"] = {category = "Health", description = "Displays the health deficit as a percentage and the name of the unit (limited to 15 letters)"},
+ ["health:deficit-percent:name-short"] = {category = "Health", description = "Displays the health deficit as a percentage and the name of the unit (limited to 10 letters)"},
+ ["health:deficit-percent:name-veryshort"] = {category = "Health", description = "Displays the health deficit as a percentage and the name of the unit (limited to 5 letters)"},
+ ["health:max"] = {category = "Health", description = "Displays the maximum health of the unit"},
+ ["health:percent"] = {category = "Health", description = "Displays the current health of the unit as a percentage"},
+ ["health:percent-nostatus"] = {category = "Health", description = "Displays the unit's current health as a percentage, without status"},
+ ["missinghp"] = {category = "Health", description = "Displays the missing health of the unit in whole numbers, when not at full health"},
+ --Level
+ ["smartlevel"] = {category = "Level", description = "Only display the unit's level if it is not the same as yours"},
+ ["level"] = {category = "Level", description = "Displays the level of the unit"},
+ --Mana
+ ["mana:current"] = {category = "Mana", description = "Displays the unit's current amount of mana (e.g. 97200)"},
+ ["mana:current-percent"] = {category = "Mana", description = "Displays the current amount of mana as a whole number and a percentage, separated by a dash"},
+ ["mana:current-max"] = {category = "Mana", description = "Displays the current mana and max mana, separated by a dash"},
+ ["mana:current-max-percent"] = {category = "Mana", description = "Displays the current mana and max mana, separated by a dash (% when not full power)"},
+ ["mana:percent"] = {category = "Mana", description = "Displays the mana of the unit as a percentage value"},
+ ["mana:max"] = {category = "Mana", description = "Displays the unit's maximum mana"},
+ ["mana:deficit"] = {category = "Mana", description = "Displays the mana deficit (Total Mana - Current Mana = -Deficit)"},
+ ["curmana"] = {category = "Mana", description = "Displays the current mana without decimals"},
+ ["maxmana"] = {category = "Mana", description = "Displays the max amount of mana the unit can have"},
+ --Names
+ ["name"] = {category = "Names", description = "Displays the full name of the unit without any letter limitation"},
+ ["name:veryshort"] = {category = "Names", description = "Displays the name of the unit (limited to 5 letters)"},
+ ["name:short"] = {category = "Names", description = "Displays the name of the unit (limited to 10 letters)"},
+ ["name:medium"] = {category = "Names", description = "Displays the name of the unit (limited to 15 letters)"},
+ ["name:long"] = {category = "Names", description = "Displays the name of the unit (limited to 20 letters)"},
+ ["name:veryshort:translit"] = {category = "Names", description = "Displays the name of the unit with transliteration for cyrillic letters (limited to 5 letters)"},
+ ["name:short:translit"] = {category = "Names", description = "Displays the name of the unit with transliteration for cyrillic letters (limited to 10 letters)"},
+ ["name:medium:translit"] = {category = "Names", description = "Displays the name of the unit with transliteration for cyrillic letters (limited to 15 letters)"},
+ ["name:long:translit"] = {category = "Names", description = "Displays the name of the unit with transliteration for cyrillic letters (limited to 20 letters)"},
+ ["name:abbrev"] = {category = "Names", description = "Displays the name of the unit with abbreviation (e.g. 'Shadowfury Witch Doctor' becomes 'S. W. Doctor')"},
+ ["name:abbrev:veryshort"] = {category = "Names", description = "Displays the name of the unit with abbreviation (limited to 5 letters)"},
+ ["name:abbrev:short"] = {category = "Names", description = "Displays the name of the unit with abbreviation (limited to 10 letters)"},
+ ["name:abbrev:medium"] = {category = "Names", description = "Displays the name of the unit with abbreviation (limited to 15 letters)"},
+ ["name:abbrev:long"] = {category = "Names", description = "Displays the name of the unit with abbreviation (limited to 20 letters)"},
+ ["name:veryshort:status"] = {category = "Names", description = "Replace the name of the unit with 'DEAD' or 'OFFLINE' if applicable (limited to 5 letters)"},
+ ["name:short:status"] = {category = "Names", description = "Replace the name of the unit with 'DEAD' or 'OFFLINE' if applicable (limited to 10 letters)"},
+ ["name:medium:status"] = {category = "Names", description = "Replace the name of the unit with 'DEAD' or 'OFFLINE' if applicable (limited to 15 letters)"},
+ ["name:long:status"] = {category = "Names", description = "Replace the name of the unit with 'DEAD' or 'OFFLINE' if applicable (limited to 20 letters)"},
+ ["name:title"] = {category = "Names", description = "Displays player name and title"},
+ --Party and Raid
+ ["group"] = {category = "Party and Raid", description = "Displays the group number the unit is in ('1' - '8')"},
+ ["leader"] = {category = "Party and Raid", description = "Displays 'L' if the unit is the group/raid leader"},
+ ["leaderlong"] = {category = "Party and Raid", description = "Displays 'Leader' if the unit is the group/raid leader"},
+ --Power
+ ["power:current"] = {category = "Power", description = "Displays the unit's current amount of power"},
+ ["power:current-percent"] = {category = "Power", description = "Displays the current power and power as a percentage, separated by a dash"},
+ ["power:current-max"] = {category = "Power", description = "Displays the current power and max power, separated by a dash"},
+ ["power:current-max-percent"] = {category = "Power", description = "Displays the current power and max power, separated by a dash (% when not full power)"},
+ ["power:percent"] = {category = "Power", description = "Displays the unit's power as a percentage"},
+ ["power:max"] = {category = "Power", description = "Displays the unit's maximum power"},
+ ["power:deficit"] = {category = "Power", description = "Displays the power as a deficit (Total Power - Current Power = -Deficit)"},
+ ["curpp"] = {category = "Power", description = "Displays the unit's current power without decimals"},
+ ["perpp"] = {category = "Power", description = "Displays the unit's percentage power without decimals "},
+ ["maxpp"] = {category = "Power", description = "Displays the max amount of power of the unit in whole numbers without decimals"},
+ ["missingpp"] = {category = "Power", description = "Displays the missing power of the unit in whole numbers when not at full power"},
+ --Energy
+ ["energy:current"] = {category = "Energy", description = "Displays the unit's current amount of energy"},
+ ["energy:current-percent"] = {category = "Energy", description = "Displays the current energy and energy as a percentage, separated by a dash"},
+ ["energy:current-max"] = {category = "Energy", description = "Displays the current energy and max energy, separated by a dash"},
+ ["energy:current-max-percent"] = {category = "Energy", description = "Displays the current energy and max energy, separated by a dash (% when not full energy)"},
+ ["energy:percent"] = {category = "Energy", description = "Displays the unit's energy as a percentage"},
+ ["energy:max"] = {category = "Energy", description = "Displays the unit's maximum energy"},
+ ["energy:deficit"] = {category = "Energy", description = "Displays the energy as a deficit (Total Energy - Current Energy = -Deficit)"},
+ --Rage
+ ["rage:current"] = {category = "Rage", description = "Displays the unit's current amount of rage"},
+ ["rage:current-percent"] = {category = "Rage", description = "Displays the current rage and rage as a percentage, separated by a dash"},
+ ["rage:current-max"] = {category = "Rage", description = "Displays the current rage and max rage, separated by a dash"},
+ ["rage:current-max-percent"] = {category = "Rage", description = "Displays the current rage and max rage, separated by a dash (% when not full rage)"},
+ ["rage:percent"] = {category = "Rage", description = "Displays the unit's rage as a percentage"},
+ ["rage:max"] = {category = "Rage", description = "Displays the unit's maximum rage"},
+ ["rage:deficit"] = {category = "Rage", description = "Displays the rage as a deficit (Total Rage - Current Rage = -Deficit)"},
+ --Realm
+ ["realm"] = {category = "Realm", description = "Displays the server name"},
+ ["realm:translit"] = {category = "Realm", description = "Displays the server name with transliteration for cyrillic letters"},
+ ["realm:dash"] = {category = "Realm", description = "Displays the server name with a dash in front (e.g. -Realm)"},
+ ["realm:dash:translit"] = {category = "Realm", description = "Displays the server name with transliteration for cyrillic letters and a dash in front"},
+ --Status
+ ["status"] = {category = "Status", description = "Displays zzz, dead, ghost, offline"},
+ ["statustimer"] = {category = "Status", description = "Displays a timer for how long a unit has had the status (e.g 'DEAD - 0:34')"},
+ ["afk"] = {category = "Status", description = "Displays if the Unit is afk"},
+ ["dead"] = {category = "Status", description = "Displays if the unit is dead"},
+ ["resting"] = {category = "Status", description = "Displays zzz if the unit is dead"},
+ ["pvp"] = {category = "Status", description = "Displays 'PvP' if the unit is pvp flagged"},
+ ["offline"] = {category = "Status", description = "Displays 'OFFLINE' if the unit is disconnected"},
+ --Target
+ ["target"] = {category = "Target", description = "Displays the current target of the unit"},
+ ["target:veryshort"] = {category = "Target", description = "Displays the current target of the unit (limited to 5 letters)"},
+ ["target:short"] = {category = "Target", description = "Displays the current target of the unit (limited to 10 letters)"},
+ ["target:medium"] = {category = "Target", description = "Displays the current target of the unit (limited to 15 letters)"},
+ ["target:long"] = {category = "Target", description = "Displays the current target of the unit (limited to 20 letters)"},
+ ["target:translit"] = {category = "Target", description = "Displays the current target of the unit with transliteration for cyrillic letters"},
+ ["target:veryshort:translit"] = {category = "Target", description = "Displays the current target of the unit with transliteration for cyrillic letters (limited to 5 letters)"},
+ ["target:short:translit"] = {category = "Target", description = "Displays the current target of the unit with transliteration for cyrillic letters (limited to 10 letters)"},
+ ["target:medium:translit"] = {category = "Target", description = "Displays the current target of the unit with transliteration for cyrillic letters (limited to 15 letters)"},
+ ["target:long:translit"] = {category = "Target", description = "Displays the current target of the unit with transliteration for cyrillic letters (limited to 20 letters)"},
+ --Threat
+ ["threat"] = {category = "Threat", description = "Displays the current threat"},
+ ["threat:percent"] = {category = "Threat", description = "Displays the current threat as a percent"},
+ ["threat:current"] = {category = "Threat", description = "Displays the current threat as a value"},
+ --Miscellaneous
+ ["smartclass"] = {category = "Miscellaneous", description = "Displays the player's class or creature's type"},
+ ["class"] = {category = "Miscellaneous", description = "Displays the class of the unit, if that unit is a player"},
+ ["difficulty"] = {category = "Miscellaneous", description = "Changes color of the next tag based on how difficult the unit is compared to the players level"},
+ ["faction"] = {category = "Miscellaneous", description = "Displays 'Aliance' or 'Horde'"},
+ ["plus"] = {category = "Miscellaneous", description = "Displays the character '+' if the unit is an elite or rare-elite"},
+ ["arena:number"] = {category = "Miscellaneous", description = "Displays the arena number 1-5"},
+}
+
+function E:AddTagInfo(tagName, category, description, order)
+ if order then order = tonumber(order) + 10 end
+
+ E.TagInfo[tagName] = E.TagInfo[tagName] or {}
+ E.TagInfo[tagName].category = category or "Miscellaneous"
+ E.TagInfo[tagName].description = description or ""
+ E.TagInfo[tagName].order = order or nil
+end
\ No newline at end of file
diff --git a/ElvUI/Core/Toolkit.lua b/ElvUI/Core/Toolkit.lua
new file mode 100644
index 0000000..edb862b
--- /dev/null
+++ b/ElvUI/Core/Toolkit.lua
@@ -0,0 +1,346 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local LSM = E.Libs.LSM
+
+--Lua functions
+local _G = _G
+local unpack, type, select, getmetatable, assert = unpack, type, select, getmetatable, assert
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+local backdropr, backdropg, backdropb, backdropa, borderr, borderg, borderb = 0, 0, 0, 1, 0, 0, 0
+local function GetTemplate(template, isUnitFrameElement)
+ backdropa = 1
+
+ if template == "ClassColor" then
+ local color = E.media.herocolor
+ borderr, borderg, borderb = color.r, color.g, color.b
+ backdropr, backdropg, backdropb = unpack(E.media.backdropcolor)
+ elseif template == "Transparent" then
+ borderr, borderg, borderb = unpack(isUnitFrameElement and E.media.unitframeBorderColor or E.media.bordercolor)
+ backdropr, backdropg, backdropb, backdropa = unpack(E.media.backdropfadecolor)
+ else
+ borderr, borderg, borderb = unpack(isUnitFrameElement and E.media.unitframeBorderColor or E.media.bordercolor)
+ backdropr, backdropg, backdropb = unpack(E.media.backdropcolor)
+ end
+end
+
+local function Size(frame, width, height)
+ assert(width)
+ frame:SetSize(E:Scale(width), E:Scale(height or width))
+end
+
+local function Width(frame, width)
+ assert(width)
+ frame:SetWidth(E:Scale(width))
+end
+
+local function Height(frame, height)
+ assert(height)
+ frame:SetHeight(E:Scale(height))
+end
+
+local function Point(obj, arg1, arg2, arg3, arg4, arg5)
+ if arg2 == nil then arg2 = obj:GetParent() end
+
+ if type(arg2) == "number" then arg2 = E:Scale(arg2) end
+ if type(arg3) == "number" then arg3 = E:Scale(arg3) end
+ if type(arg4) == "number" then arg4 = E:Scale(arg4) end
+ if type(arg5) == "number" then arg5 = E:Scale(arg5) end
+
+ obj:SetPoint(arg1, arg2, arg3, arg4, arg5)
+end
+
+local function SetOutside(obj, anchor, xOffset, yOffset, anchor2)
+ xOffset = xOffset or E.Border
+ yOffset = yOffset or E.Border
+ anchor = anchor or obj:GetParent()
+
+ assert(anchor)
+ if obj:GetPoint() then
+ obj:ClearAllPoints()
+ end
+
+ obj:Point("TOPLEFT", anchor, "TOPLEFT", -xOffset, yOffset)
+ obj:Point("BOTTOMRIGHT", anchor2 or anchor, "BOTTOMRIGHT", xOffset, -yOffset)
+end
+
+local function SetInside(obj, anchor, xOffset, yOffset, anchor2)
+ xOffset = xOffset or E.Border
+ yOffset = yOffset or E.Border
+ anchor = anchor or obj:GetParent()
+
+ assert(anchor)
+ if obj:GetPoint() then
+ obj:ClearAllPoints()
+ end
+
+ obj:Point("TOPLEFT", anchor, "TOPLEFT", xOffset, -yOffset)
+ obj:Point("BOTTOMRIGHT", anchor2 or anchor, "BOTTOMRIGHT", -xOffset, yOffset)
+end
+
+local function SetTemplate(frame, template, glossTex, ignoreUpdates, forcePixelMode, isUnitFrameElement)
+ GetTemplate(template, isUnitFrameElement)
+
+ frame.template = template or "Default"
+ if glossTex then frame.glossTex = glossTex end
+ if ignoreUpdates then frame.ignoreUpdates = ignoreUpdates end
+ if forcePixelMode then frame.forcePixelMode = forcePixelMode end
+ if isUnitFrameElement then frame.isUnitFrameElement = isUnitFrameElement end
+
+ local bgFile = glossTex and E.media.glossTex or E.media.blankTex
+
+ if template ~= "NoBackdrop" then
+ frame:SetBackdrop({
+ bgFile = bgFile,
+ edgeFile = E.media.blankTex,
+ tile = false, tileSize = 0, edgeSize = E.mult,
+ insets = {left = 0, right = 0, top = 0, bottom = 0}
+ })
+
+ frame:SetBackdropColor(backdropr, backdropg, backdropb, backdropa)
+
+ if not E.PixelMode and not frame.forcePixelMode then
+ if not frame.iborder then
+ local border = CreateFrame("Frame", nil, frame)
+ border:SetInside(frame, E.mult, E.mult)
+ border:SetBackdrop({
+ edgeFile = E.media.blankTex,
+ edgeSize = E.mult,
+ insets = {left = -E.mult, right = -E.mult, top = -E.mult, bottom = -E.mult}
+ })
+ border:SetBackdropBorderColor(0, 0, 0, 1)
+ frame.iborder = border
+ end
+
+ if not frame.oborder then
+ local border = CreateFrame("Frame", nil, frame)
+ border:SetOutside(frame, E.mult, E.mult)
+ border:SetFrameLevel(frame:GetFrameLevel() + 1)
+ border:SetBackdrop({
+ edgeFile = E.media.blankTex,
+ edgeSize = E.mult,
+ insets = {left = E.mult, right = E.mult, top = E.mult, bottom = E.mult}
+ })
+ border:SetBackdropBorderColor(0, 0, 0, 1)
+ frame.oborder = border
+ end
+ end
+ else
+ frame:SetBackdrop(nil)
+ end
+ frame:SetBackdropBorderColor(borderr, borderg, borderb)
+
+ if not frame.ignoreUpdates then
+ if frame.isUnitFrameElement then
+ E.unitFrameElements[frame] = true
+ else
+ E.frames[frame] = true
+ end
+ end
+end
+
+local function CreateBackdrop(frame, template, glossTex, ignoreUpdates, forcePixelMode, isUnitFrameElement)
+ if not template then template = "Default" end
+
+ local parent = (frame.IsObjectType and frame:IsObjectType("Texture") and frame:GetParent()) or frame
+ local backdrop = frame.backdrop or CreateFrame("Frame", nil, parent)
+ if not frame.backdrop then frame.backdrop = backdrop end
+
+ if frame.forcePixelMode or forcePixelMode then
+ backdrop:SetOutside(frame, E.mult, E.mult)
+ else
+ backdrop:SetOutside(frame)
+ end
+
+ backdrop:SetTemplate(template, glossTex, ignoreUpdates, forcePixelMode, isUnitFrameElement)
+
+ local frameLevel = parent.GetFrameLevel and parent:GetFrameLevel()
+ local frameLevelMinusOne = frameLevel and (frameLevel - 1)
+ if frameLevelMinusOne and (frameLevelMinusOne >= 0) then
+ backdrop:SetFrameLevel(frameLevelMinusOne)
+ else
+ backdrop:SetFrameLevel(0)
+ end
+end
+
+local function CreateShadow(frame, size)
+ if frame.shadow then return end
+
+ backdropr, backdropg, backdropb, borderr, borderg, borderb = 0, 0, 0, 0, 0, 0
+
+ local shadow = CreateFrame("Frame", nil, frame)
+ shadow:SetFrameLevel(1)
+ shadow:SetFrameStrata(frame:GetFrameStrata())
+ shadow:SetOutside(frame, size or 3, size or 3)
+ shadow:SetBackdrop({edgeFile = LSM:Fetch("border", "ElvUI GlowBorder"), edgeSize = E:Scale(size or 3)})
+ shadow:SetBackdropColor(backdropr, backdropg, backdropb, 0)
+ shadow:SetBackdropBorderColor(borderr, borderg, borderb, 0.9)
+ frame.shadow = shadow
+end
+
+local function Kill(object)
+ if object.UnregisterAllEvents then
+ object:UnregisterAllEvents()
+ object:SetParent(E.HiddenFrame)
+ else
+ object.Show = object.Hide
+ end
+
+ object:Hide()
+end
+
+local function StripTextures(object, kill, alpha)
+ if object:IsObjectType("Texture") then
+ if kill then
+ object:Kill()
+ elseif alpha then
+ object:SetAlpha(0)
+ else
+ object:SetTexture()
+ end
+ else
+ if object.GetNumRegions then
+ for i = 1, object:GetNumRegions() do
+ local region = select(i, object:GetRegions())
+ if region and region.IsObjectType and region:IsObjectType("Texture") then
+ if kill then
+ region:Kill()
+ elseif alpha then
+ region:SetAlpha(0)
+ else
+ region:SetTexture()
+ end
+ end
+ end
+ end
+ end
+end
+
+local function FontTemplate(fs, font, fontSize, fontStyle)
+ fs.font = font
+ fs.fontSize = fontSize
+ fs.fontStyle = fontStyle
+
+ font = font or LSM:Fetch("font", E.db.general.font)
+ fontSize = fontSize or E.db.general.fontSize
+ fontStyle = fontStyle or E.db.general.fontStyle
+
+ if fontStyle == "OUTLINE" and E.db.general.font == "Homespun" and (fontSize > 10 and not fs.fontSize) then
+ fontSize, fontStyle = 10, "MONOCHROMEOUTLINE"
+ end
+
+ fs:SetFont(font, fontSize, fontStyle)
+
+ if fontStyle == "NONE" then
+ local s = E.mult or 1
+ fs:SetShadowOffset(s, -s/2)
+ fs:SetShadowColor(0, 0, 0, 1)
+ else
+ fs:SetShadowOffset(0, 0)
+ fs:SetShadowColor(0, 0, 0, 0)
+ end
+
+ E.texts[fs] = true
+end
+
+local function StyleButton(button, noHover, noPushed, noChecked)
+ if button.SetHighlightTexture and not button.hover and not noHover then
+ local hover = button:CreateTexture()
+ hover:SetInside()
+ hover:SetTexture(1, 1, 1, 0.3)
+ button:SetHighlightTexture(hover)
+ button.hover = hover
+ end
+
+ if button.SetPushedTexture and not button.pushed and not noPushed then
+ local pushed = button:CreateTexture()
+ pushed:SetInside()
+ pushed:SetTexture(0.9, 0.8, 0.1, 0.3)
+ button:SetPushedTexture(pushed)
+ button.pushed = pushed
+ end
+
+ if button.SetCheckedTexture and not button.checked and not noChecked then
+ local checked = button:CreateTexture()
+ checked:SetInside()
+ checked:SetTexture(1, 1, 1, 0.3)
+ button:SetCheckedTexture(checked)
+ button.checked = checked
+ end
+
+ local name = button.GetName and button:GetName()
+ local cooldown = name and _G[name.."Cooldown"]
+ if cooldown then
+ cooldown:ClearAllPoints()
+ cooldown:SetInside()
+ end
+end
+
+local CreateCloseButton
+do
+ local CloseButtonOnClick = function(btn) btn:GetParent():Hide() end
+ local CloseButtonOnEnter = function(btn) if btn.Texture then btn.Texture:SetVertexColor(unpack(E.media.rgbvaluecolor)) end end
+ local CloseButtonOnLeave = function(btn) if btn.Texture then btn.Texture:SetVertexColor(1, 1, 1) end end
+ CreateCloseButton = function(frame, size, offset, texture, backdrop)
+ if frame.CloseButton then return end
+
+ local CloseButton = CreateFrame("Button", nil, frame)
+ CloseButton:Size(size or 16)
+ CloseButton:Point("TOPRIGHT", offset or -6, offset or -6)
+ if backdrop then CloseButton:CreateBackdrop(nil, true) end
+
+ CloseButton.Texture = CloseButton:CreateTexture(nil, "OVERLAY")
+ CloseButton.Texture:SetAllPoints()
+ CloseButton.Texture:SetTexture(texture or E.Media.Textures.Close)
+
+ CloseButton:SetScript("OnClick", CloseButtonOnClick)
+ CloseButton:SetScript("OnEnter", CloseButtonOnEnter)
+ CloseButton:SetScript("OnLeave", CloseButtonOnLeave)
+
+ frame.CloseButton = CloseButton
+ end
+end
+
+local function GetNamedChild(frame, childName, index)
+ local name = frame and frame.GetName and frame:GetName()
+ if not name or not childName then return nil end
+ return _G[name..childName..(index or "")]
+end
+
+local function addapi(object)
+ local mt = getmetatable(object).__index
+ if not object.Size then mt.Size = Size end
+ if not object.Point then mt.Point = Point end
+ if not object.SetOutside then mt.SetOutside = SetOutside end
+ if not object.SetInside then mt.SetInside = SetInside end
+ if not object.SetTemplate then mt.SetTemplate = SetTemplate end
+ if not object.CreateBackdrop then mt.CreateBackdrop = CreateBackdrop end
+ if not object.CreateShadow then mt.CreateShadow = CreateShadow end
+ if not object.Kill then mt.Kill = Kill end
+ if not object.Width then mt.Width = Width end
+ if not object.Height then mt.Height = Height end
+ if not object.FontTemplate then mt.FontTemplate = FontTemplate end
+ if not object.StripTextures then mt.StripTextures = StripTextures end
+ if not object.StyleButton then mt.StyleButton = StyleButton end
+ if not object.CreateCloseButton then mt.CreateCloseButton = CreateCloseButton end
+ if not object.GetNamedChild then mt.GetNamedChild = GetNamedChild end
+end
+
+local handled = {["Frame"] = true}
+local object = CreateFrame("Frame")
+addapi(object)
+addapi(object:CreateTexture())
+addapi(object:CreateFontString())
+
+object = EnumerateFrames()
+while object do
+ if not handled[object:GetObjectType()] then
+ addapi(object)
+ handled[object:GetObjectType()] = true
+ end
+
+ object = EnumerateFrames(object)
+end
+
+--Add API to `CreateFont` objects without actually creating one
+addapi(GameFontNormal)
\ No newline at end of file
diff --git a/ElvUI/Core/Tutorials.lua b/ElvUI/Core/Tutorials.lua
new file mode 100644
index 0000000..246613a
--- /dev/null
+++ b/ElvUI/Core/Tutorials.lua
@@ -0,0 +1,120 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local Skins = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local DISABLE = DISABLE
+local HIDE = HIDE
+
+E.TutorialList = {
+ L["For technical support visit us at https://github.com/ElvUI-WotLK."],
+ L["You can toggle the microbar by using your middle mouse button on the minimap you can also accomplish this by enabling the actual microbar located in the actionbar settings."],
+ L["A raid marker feature is available by pressing Escape -> Keybinds scroll to the bottom under ElvUI and setting a keybind for the raid marker."],
+ L["You can set your keybinds quickly by typing /kb."],
+ L["The focus unit can be set by typing /focus when you are targeting the unit you want to focus. It is recommended you make a macro to do this."],
+ L["ElvUI has a dual spec feature which allows you to load different profiles based on your current spec on the fly. You can enable this from the profiles tab."],
+ L["You can access copy chat and chat menu functions by mouse over the top right corner of chat panel and left/right click on the button that will appear."],
+ L["If you are experiencing issues with ElvUI try disabling all your addons except ElvUI, remember ElvUI is a full UI replacement addon, you cannot run two addons that do the same thing."],
+ L["If you accidently remove a chat frame you can always go the in-game configuration menu, press install, go to the chat portion and reset them."],
+ L["To setup which channels appear in which chat frame, right click the chat tab and go to settings."],
+ L["You can use the /resetui command to reset all of your movers. You can also use the command to reset a specific mover, /resetui .\nExample: /resetui Player Frame"],
+ L["To move abilities on the actionbars by default hold shift + drag. You can change the modifier key from the actionbar options menu."],
+ L["You can see someones average item level of their gear by holding shift and mousing over them. It should appear inside the tooltip."]
+}
+
+function E:SetNextTutorial()
+ self.db.currentTutorial = self.db.currentTutorial or 0
+ self.db.currentTutorial = self.db.currentTutorial + 1
+
+ if self.db.currentTutorial > #E.TutorialList then
+ self.db.currentTutorial = 1
+ end
+
+ ElvUITutorialWindow.desc:SetText(E.TutorialList[self.db.currentTutorial])
+end
+
+function E:SetPrevTutorial()
+ self.db.currentTutorial = self.db.currentTutorial or 0
+ self.db.currentTutorial = self.db.currentTutorial - 1
+
+ if self.db.currentTutorial <= 0 then
+ self.db.currentTutorial = #E.TutorialList
+ end
+
+ ElvUITutorialWindow.desc:SetText(E.TutorialList[self.db.currentTutorial])
+end
+
+function E:SpawnTutorialFrame()
+ local f = CreateFrame("Frame", "ElvUITutorialWindow", E.UIParent)
+ f:SetFrameStrata("DIALOG")
+ f:SetToplevel(true)
+ f:SetClampedToScreen(true)
+ f:Width(360)
+ f:Height(110)
+ f:SetTemplate("Transparent")
+ f:Hide()
+
+ local header = CreateFrame("Button", nil, f)
+ header:SetTemplate("Default", true)
+ header:Width(120)
+ header:Height(25)
+ header:Point("CENTER", f, "TOP")
+ header:SetFrameLevel(header:GetFrameLevel() + 2)
+
+ local title = header:CreateFontString("OVERLAY")
+ title:FontTemplate()
+ title:Point("CENTER", header, "CENTER")
+ title:SetText("ElvUI")
+
+ local desc = f:CreateFontString("ARTWORK")
+ desc:SetFontObject("GameFontHighlight")
+ desc:SetJustifyV("TOP")
+ desc:SetJustifyH("LEFT")
+ desc:Point("TOPLEFT", 18, -32)
+ desc:Point("BOTTOMRIGHT", -18, 30)
+ f.desc = desc
+
+ f.disableButton = CreateFrame("CheckButton", f:GetName().."DisableButton", f, "OptionsCheckButtonTemplate")
+ _G[f.disableButton:GetName().."Text"]:SetText(DISABLE)
+ f.disableButton:Point("BOTTOMLEFT")
+ Skins:HandleCheckBox(f.disableButton)
+ f.disableButton:SetScript("OnShow", function(self) self:SetChecked(E.db.hideTutorial) end)
+
+ f.disableButton:SetScript("OnClick", function(self) E.db.hideTutorial = self:GetChecked() end)
+
+ f.hideButton = CreateFrame("Button", f:GetName().."HideButton", f, "OptionsButtonTemplate")
+ f.hideButton:Point("BOTTOMRIGHT", -5, 5)
+ Skins:HandleButton(f.hideButton)
+ _G[f.hideButton:GetName().."Text"]:SetText(HIDE)
+ f.hideButton:SetScript("OnClick", function(self) E:StaticPopupSpecial_Hide(self:GetParent()) end)
+
+ f.nextButton = CreateFrame("Button", f:GetName().."NextButton", f, "OptionsButtonTemplate")
+ f.nextButton:Point("RIGHT", f.hideButton, "LEFT", -4, 0)
+ f.nextButton:Width(20)
+ Skins:HandleButton(f.nextButton)
+ _G[f.nextButton:GetName().."Text"]:SetText(">")
+ f.nextButton:SetScript("OnClick", function() E:SetNextTutorial() end)
+
+ f.prevButton = CreateFrame("Button", f:GetName().."PrevButton", f, "OptionsButtonTemplate")
+ f.prevButton:Point("RIGHT", f.nextButton, "LEFT", -4, 0)
+ f.prevButton:Width(20)
+ Skins:HandleButton(f.prevButton)
+ _G[f.prevButton:GetName().."Text"]:SetText("<")
+ f.prevButton:SetScript("OnClick", function() E:SetPrevTutorial() end)
+
+ return f
+end
+
+function E:Tutorials(forceShow)
+ if (not forceShow and self.db.hideTutorial) or (not forceShow and not self.private.install_complete) then return end
+ local f = ElvUITutorialWindow
+ if not f then
+ f = E:SpawnTutorialFrame()
+ end
+
+ E:StaticPopupSpecial_Show(f)
+
+ self:SetNextTutorial()
+end
\ No newline at end of file
diff --git a/ElvUI/Developer/Frame.lua b/ElvUI/Developer/Frame.lua
new file mode 100644
index 0000000..77dd71d
--- /dev/null
+++ b/ElvUI/Developer/Frame.lua
@@ -0,0 +1,280 @@
+--Lua functions
+local _G = _G
+local loadstring = loadstring
+local pcall = pcall
+local print = print
+local select = select
+local tostring = tostring
+local type = type
+local find, format, match = string.find, string.format, string.match
+local tconcat = table.concat
+--WoW API / Variables
+local FrameStackTooltip_Toggle = FrameStackTooltip_Toggle
+local GetMouseFocus = GetMouseFocus
+local tostringall = tostringall
+
+local WorldFrame = WorldFrame
+
+local DEFAULT_CHAT_FRAME = DEFAULT_CHAT_FRAME
+local oldAddMessage
+
+local function printNoTimestamp(...)
+ if oldAddMessage or DEFAULT_CHAT_FRAME.OldAddMessage then
+ if not oldAddMessage then
+ oldAddMessage = DEFAULT_CHAT_FRAME.OldAddMessage
+ end
+
+ if select("#", ...) > 1 then
+ oldAddMessage(DEFAULT_CHAT_FRAME, tconcat({tostringall(...)}, ", "))
+ else
+ oldAddMessage(DEFAULT_CHAT_FRAME, ...)
+ end
+ elseif CHAT_TIMESTAMP_FORMAT then
+ local tsformat = CHAT_TIMESTAMP_FORMAT
+ CHAT_TIMESTAMP_FORMAT = nil
+ print(...)
+ CHAT_TIMESTAMP_FORMAT = tsformat
+ else
+ print(...)
+ end
+end
+
+local function updateCopyChat()
+ if CopyChatFrame and CopyChatFrame:IsShown() then
+ CopyChatFrame:Hide()
+ ElvUI[1]:GetModule("Chat"):CopyChat(DEFAULT_CHAT_FRAME)
+ end
+end
+
+local function getObject(objName)
+ local obj
+
+ if objName == "" then
+ obj = GetMouseFocus()
+ else
+ obj = _G[objName]
+
+ if not obj then
+ local pass
+
+ if find(objName, "^[%.:]([A-z0-9_]+)") then
+ local _obj = GetMouseFocus()
+
+ if _obj and _obj ~= WorldFrame then
+ local res = match(objName, "^[%.:]([A-z0-9_]+)")
+
+ if res and _obj[res] and _obj:GetName() then
+ objName = format("%s%s", _obj:GetName(), objName)
+ end
+
+ pass = true
+ end
+ elseif find(objName, "[%.()%[%]'\"]") then
+ pass = true
+ end
+
+ if pass then
+ local success, ret = pcall(loadstring(format("return %s", objName)))
+ if success then
+ ret = ret == "string" and _G[ret] or ret
+
+ if type(ret) == "table" and ret.GetName then
+ obj = ret
+ end
+ end
+ end
+ end
+ end
+
+ if obj then
+ return obj ~= WorldFrame and obj or nil
+ else
+ printNoTimestamp(format("Object |cffFFD100%s|r not found!", objName))
+ end
+end
+
+local FrameStackHighlight = CreateFrame("Frame", "FrameStackHighlight")
+FrameStackHighlight:SetFrameStrata("TOOLTIP")
+FrameStackHighlight.t = FrameStackHighlight:CreateTexture(nil, "BORDER")
+FrameStackHighlight.t:SetAllPoints()
+FrameStackHighlight.t:SetTexture(0, 1, 0, 0.5)
+
+local FrameStackHitRectHighlight = CreateFrame("Frame", "FrameStackHitRectHighlight")
+FrameStackHitRectHighlight:SetFrameStrata("TOOLTIP")
+FrameStackHitRectHighlight.t = FrameStackHitRectHighlight:CreateTexture(nil, "ARTWORK")
+FrameStackHitRectHighlight.t:SetAllPoints()
+FrameStackHitRectHighlight.t:SetTexture(0, 0, 1, 0.5)
+FrameStackHitRectHighlight.t:SetBlendMode("ADD")
+
+hooksecurefunc("FrameStackTooltip_Toggle", function()
+ if not FrameStackTooltip:IsVisible() then
+ FrameStackHighlight:Hide()
+ FrameStackHitRectHighlight:Hide()
+ end
+end)
+
+local _timeSinceLast = 0
+FrameStackTooltip:HookScript("OnUpdate", function(_, elapsed)
+ _timeSinceLast = _timeSinceLast - elapsed
+ if _timeSinceLast <= 0 then
+ _timeSinceLast = FRAMESTACK_UPDATE_TIME
+ local highlightFrame = GetMouseFocus()
+
+ if highlightFrame and highlightFrame ~= WorldFrame then
+ FrameStackHighlight:ClearAllPoints()
+ FrameStackHighlight:SetPoint("BOTTOMLEFT", highlightFrame)
+ FrameStackHighlight:SetPoint("TOPRIGHT", highlightFrame)
+ FrameStackHighlight:Show()
+
+ local l, r, t, b = highlightFrame:GetHitRectInsets()
+ if l ~= 0 or r ~= 0 or t ~= 0 or b ~= 0 then
+ local scale = highlightFrame:GetEffectiveScale()
+ FrameStackHitRectHighlight:ClearAllPoints()
+ FrameStackHitRectHighlight:SetPoint("TOPLEFT", highlightFrame, l * scale, -t * scale)
+ FrameStackHitRectHighlight:SetPoint("BOTTOMRIGHT", highlightFrame, -r * scale, b * scale)
+ FrameStackHitRectHighlight:Show()
+ else
+ FrameStackHitRectHighlight:Hide()
+ end
+ else
+ FrameStackHighlight:Hide()
+ FrameStackHitRectHighlight:Hide()
+ end
+ end
+end)
+
+SLASH_FRAME1 = "/frame"
+SlashCmdList.FRAME = function(frame)
+ frame = getObject(frame)
+ if not frame then return end
+
+ local parent = frame:GetParent()
+ local parentName = parent and parent.GetName and parent:GetName()
+
+ printNoTimestamp("|cffCC0000----------------------------")
+
+ printNoTimestamp(format("Name: |cffFFD100%s|r; ObjectType: |cffFFD100%s|r", frame:GetName() or "nil", frame:GetObjectType()))
+ printNoTimestamp(format("Parent: |cffFFD100%s|r", parentName or (parent and tostring(parent)) or "nil"))
+
+ if frame.GetFrameStrata then
+ printNoTimestamp(format("Strata: |cffFFD100%s|r; FrameLevel: |cffFFD100%d|r", frame:GetFrameStrata(), frame:GetFrameLevel()))
+ else
+ printNoTimestamp(format("DrawLayer: |cffFFD100%s|r", frame:GetDrawLayer()))
+ end
+
+ if frame.GetScale then
+ printNoTimestamp(format("Width: |cffFFD100%.0f|r; Height: |cffFFD100%.0f|r; Scale: |cffFFD100%s|r", frame:GetWidth(), frame:GetHeight(), frame:GetScale()))
+ else
+ printNoTimestamp(format("Width: |cffFFD100%.0f|r; Height: |cffFFD100%.0f|r", frame:GetWidth(), frame:GetHeight()))
+ end
+
+ local point, relativeTo, relativePoint, x, y, relativeName
+ for i = 1, frame:GetNumPoints() do
+ point, relativeTo, relativePoint, x, y = frame:GetPoint(i)
+ relativeName = relativeTo and relativeTo.GetName and (relativeTo:GetName() or tostring(relativeTo)) or "nil"
+
+ if point == relativePoint and relativeTo == parent then
+ printNoTimestamp(format("Point %d: |cffFFD100\"%s\", %.0f, %.0f|r", i, point, x, y))
+ else
+ printNoTimestamp(format("Point %d: |cffFFD100\"%s\", %s, \"%s\", %.0f, %.0f|r", i, point, relativeName, relativePoint, x, y))
+ end
+ end
+
+ printNoTimestamp("|cffCC0000----------------------------")
+
+ updateCopyChat()
+end
+
+SLASH_FRAMELIST1 = "/framelist"
+SlashCmdList.FRAMELIST = function(showHidden)
+ if not FrameStackTooltip then
+ UIParentLoadAddOn("Blizzard_DebugTools")
+ end
+
+ local isPreviouslyShown = FrameStackTooltip:IsShown()
+ if not isPreviouslyShown then
+ if showHidden == "true" then
+ FrameStackTooltip_Toggle(true)
+ else
+ FrameStackTooltip_Toggle()
+ end
+ end
+
+ printNoTimestamp("|cffCC0000----------------------------|r")
+ for i = 2, FrameStackTooltip:NumLines() do
+ local text = _G["FrameStackTooltipTextLeft"..i]:GetText()
+ if text and text ~= "" then
+ printNoTimestamp(text)
+ end
+ end
+ printNoTimestamp("|cffCC0000----------------------------|r")
+
+ updateCopyChat()
+
+ if not isPreviouslyShown then
+ FrameStackTooltip_Toggle()
+ end
+end
+
+SLASH_TEXLIST1 = "/texlist"
+SlashCmdList.TEXLIST = function(frame)
+ frame = getObject(frame)
+ if not (frame and frame.GetNumRegions) then return end
+
+ for i = 1, frame:GetNumRegions() do
+ local region = select(i, frame:GetRegions())
+ if region.IsObjectType and region:IsObjectType("Texture") and region:GetTexture() then
+ printNoTimestamp(region:GetTexture(), region:GetName(), region:GetDrawLayer())
+ end
+ end
+
+ updateCopyChat()
+end
+
+SLASH_REGLIST1 = "/reglist"
+SlashCmdList.REGLIST = function(frame)
+ frame = getObject(frame)
+ if not (frame and frame.GetNumRegions) then return end
+
+ for i = 1, frame:GetNumRegions() do
+ local region = select(i, frame:GetRegions())
+ printNoTimestamp(i, region:GetObjectType(), region:GetName(), region:GetDrawLayer())
+ end
+
+ updateCopyChat()
+end
+
+SLASH_CHILDLIST1 = "/childlist"
+SlashCmdList.CHILDLIST = function(frame)
+ frame = getObject(frame)
+ if not (frame and frame.GetNumChildren) then return end
+
+ for i = 1, frame:GetNumChildren() do
+ local obj = select(i, frame:GetChildren())
+ printNoTimestamp(i, obj:GetObjectType(), obj:GetName(), obj:GetFrameStrata(), obj:GetFrameLevel())
+ end
+
+ updateCopyChat()
+end
+
+SLASH_GETPOINT1 = "/getpoint"
+SlashCmdList.GETPOINT = function(frame)
+ frame = getObject(frame)
+ if not frame then return end
+
+ local parent = frame:GetParent()
+ local point, relativeTo, relativePoint, x, y, relativeName
+
+ for i = 1, frame:GetNumPoints() do
+ point, relativeTo, relativePoint, x, y = frame:GetPoint(i)
+ relativeName = relativeTo and relativeTo.GetName and (relativeTo:GetName() or tostring(relativeTo)) or "nil"
+
+ if point == relativePoint and relativeTo == parent then
+ printNoTimestamp(format("\"%s\", %.0f, %.0f", point, x, y))
+ else
+ printNoTimestamp(format("\"%s\", %s, \"%s\", %.0f, %.0f", point, relativeName, relativePoint, x, y))
+ end
+ end
+
+ updateCopyChat()
+end
\ No newline at end of file
diff --git a/ElvUI/Developer/Load_Developer.xml b/ElvUI/Developer/Load_Developer.xml
new file mode 100644
index 0000000..9399215
--- /dev/null
+++ b/ElvUI/Developer/Load_Developer.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Developer/ReloadUI.lua b/ElvUI/Developer/ReloadUI.lua
new file mode 100644
index 0000000..9317bd9
--- /dev/null
+++ b/ElvUI/Developer/ReloadUI.lua
@@ -0,0 +1,8 @@
+--Lua functions
+--WoW API / Variables
+local SlashCmdList = SlashCmdList
+-- GLOBALS: SLASH_RELOADUI1, SLASH_RELOADUI2
+
+SLASH_RELOADUI1 = "/rl"
+SLASH_RELOADUI2 = "/reloadui"
+SlashCmdList.RELOADUI = ReloadUI
diff --git a/ElvUI/Developer/Table.lua b/ElvUI/Developer/Table.lua
new file mode 100644
index 0000000..f221fab
--- /dev/null
+++ b/ElvUI/Developer/Table.lua
@@ -0,0 +1,30 @@
+--Lua functions
+local pairs, type = pairs, type
+local setmetatable, getmetatable = setmetatable, getmetatable
+--WoW API / Variables
+
+local function table_copy(t, deep, seen)
+ if type(t) ~= "table" then return nil end
+
+ if not seen then
+ seen = {}
+ elseif seen[t] then
+ return seen[t]
+ end
+
+ local nt = {}
+ for k, v in pairs(t) do
+ if deep and type(v) == "table" then
+ nt[k] = table_copy(v, deep, seen)
+ else
+ nt[k] = v
+ end
+ end
+
+ setmetatable(nt, table_copy(getmetatable(t), deep, seen))
+ seen[t] = nt
+
+ return nt
+end
+
+table.copy = table_copy
\ No newline at end of file
diff --git a/ElvUI/Developer/Test.lua b/ElvUI/Developer/Test.lua
new file mode 100644
index 0000000..1b12ce3
--- /dev/null
+++ b/ElvUI/Developer/Test.lua
@@ -0,0 +1,5 @@
+--[[
+ Going to leave this as my bullshit lua file.
+
+ So I can test stuff.
+]]
diff --git a/ElvUI/ElvUI.toc b/ElvUI/ElvUI.toc
new file mode 100644
index 0000000..de7a1c6
--- /dev/null
+++ b/ElvUI/ElvUI.toc
@@ -0,0 +1,19 @@
+## Interface: 30300
+## Author: Elv, Bunny
+## Version: 6.10
+## Title: |cff1784d1E|r|cffe5e3e3lvUI|r
+## Notes: User Interface replacement AddOn for World of Warcraft.
+## SavedVariables: ElvDB, ElvPrivateDB
+## SavedVariablesPerCharacter: ElvCharacterDB
+## OptionalDeps: Blizzard_DebugTools, SharedMedia, Tukui, ButtonFacade
+## X-oUF: ElvUF
+
+Developer\Load_Developer.xml
+Libraries\Load_Libraries.xml
+Init.lua
+Locales\Load_Locales.xml
+Media\Load_Media.xml
+Settings\Load_Config.xml
+Core\Load_Core.xml
+Layout\Load_Layout.xml
+Modules\Load_Modules.xml
\ No newline at end of file
diff --git a/ElvUI/Init.lua b/ElvUI/Init.lua
new file mode 100644
index 0000000..cda6515
--- /dev/null
+++ b/ElvUI/Init.lua
@@ -0,0 +1,426 @@
+--[[
+~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 ERR_NOT_IN_COMBAT = ERR_NOT_IN_COMBAT
+local GameMenuButtonLogout = GameMenuButtonLogout
+local GameMenuFrame = GameMenuFrame
+
+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("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("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")
+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")
+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")
+
+do
+ local arg2, arg3 = "([%(%)%.%%%+%-%*%?%[%^%$])", "%%%1"
+ function AddOn:EscapeString(str)
+ return gsub(str, arg2, arg3)
+ 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 = CreateFrame("Button", "ElvUI_MenuButton", GameMenuFrame, "GameMenuButtonTemplate")
+ GameMenuButton:SetText(self.title)
+ GameMenuButton:SetScript("OnClick", function()
+ AddOn:ToggleOptionsUI()
+ HideUIPanel(GameMenuFrame)
+ end)
+ GameMenuFrame[AddOnName] = GameMenuButton
+
+ GameMenuButton:Size(GameMenuButtonLogout:GetWidth(), GameMenuButtonLogout:GetHeight())
+ GameMenuButtonRatings:HookScript("OnShow", function(self)
+ GameMenuFrame:SetHeight(GameMenuFrame:GetHeight() + self:GetHeight())
+ end)
+ GameMenuButtonRatings:HookScript("OnHide", function(self)
+ GameMenuFrame:SetHeight(GameMenuFrame:GetHeight() - self:GetHeight())
+ end)
+
+ GameMenuFrame:HookScript("OnShow", function()
+ if not GameMenuFrame.isElvUI then
+ GameMenuFrame:SetHeight(GameMenuFrame:GetHeight() + GameMenuButtonLogout:GetHeight() + 1)
+ GameMenuFrame.isElvUI = true
+ end
+ local _, relTo = GameMenuButtonLogout:GetPoint()
+ if relTo ~= GameMenuFrame[AddOnName] then
+ GameMenuFrame[AddOnName]:ClearAllPoints()
+ GameMenuFrame[AddOnName]:Point("TOPLEFT", relTo, "BOTTOMLEFT", 0, -1)
+ GameMenuButtonLogout:ClearAllPoints()
+ GameMenuButtonLogout:Point("TOPLEFT", GameMenuFrame[AddOnName], "BOTTOMLEFT", 0, -16)
+ end
+ 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.06" 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
\ No newline at end of file
diff --git a/ElvUI/Layout/Layout.lua b/ElvUI/Layout/Layout.lua
new file mode 100644
index 0000000..77d6d87
--- /dev/null
+++ b/ElvUI/Layout/Layout.lua
@@ -0,0 +1,521 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local LO = E:GetModule("Layout")
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local UIFrameFadeIn, UIFrameFadeOut = UIFrameFadeIn, UIFrameFadeOut
+
+local PANEL_HEIGHT = 22
+local SIDE_BUTTON_WIDTH = 16
+
+local function Panel_OnShow(self)
+ self:SetFrameLevel(0)
+ self:SetFrameStrata("BACKGROUND")
+end
+
+function LO:Initialize()
+ self.Initialized = true
+ self:CreateChatPanels()
+ self:CreateMinimapPanels()
+ self:SetDataPanelStyle()
+
+ self.BottomPanel = CreateFrame("Frame", "ElvUI_BottomPanel", E.UIParent)
+ self.BottomPanel:SetTemplate("Transparent")
+ self.BottomPanel:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", -1, -1)
+ self.BottomPanel:Point("BOTTOMRIGHT", E.UIParent, "BOTTOMRIGHT", 1, -1)
+ self.BottomPanel:Height(PANEL_HEIGHT)
+ self.BottomPanel:SetScript("OnShow", Panel_OnShow)
+ Panel_OnShow(self.BottomPanel)
+ self:BottomPanelVisibility()
+
+ self.TopPanel = CreateFrame("Frame", "ElvUI_TopPanel", E.UIParent)
+ self.TopPanel:SetTemplate("Transparent")
+ self.TopPanel:Point("TOPLEFT", E.UIParent, "TOPLEFT", -1, 1)
+ self.TopPanel:Point("TOPRIGHT", E.UIParent, "TOPRIGHT", 1, 1)
+ self.TopPanel:Height(PANEL_HEIGHT)
+ self.TopPanel:SetScript("OnShow", Panel_OnShow)
+ Panel_OnShow(self.TopPanel)
+ self:TopPanelVisibility()
+end
+
+function LO:BottomPanelVisibility()
+ if E.db.general.bottomPanel then
+ self.BottomPanel:Show()
+ else
+ self.BottomPanel:Hide()
+ end
+end
+
+function LO:TopPanelVisibility()
+ if E.db.general.topPanel then
+ self.TopPanel:Show()
+ else
+ self.TopPanel:Hide()
+ end
+end
+
+local function ChatPanelLeft_OnFade()
+ LeftChatPanel:Hide()
+end
+
+local function ChatPanelRight_OnFade()
+ RightChatPanel:Hide()
+end
+
+local function ChatButton_OnEnter(self)
+ if E.db[self.parent:GetName().."Faded"] then
+ self.parent:Show()
+ UIFrameFadeIn(self.parent, 0.2, self.parent:GetAlpha(), 1)
+ if E.db.chat.fadeChatToggles then
+ UIFrameFadeIn(self, 0.2, self:GetAlpha(), 1)
+ end
+ end
+
+ if self == LeftChatToggleButton then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT", 0, (E.PixelMode and 1 or 3))
+ GameTooltip:ClearLines()
+ GameTooltip:AddDoubleLine(L["Left Click:"], L["Toggle Chat Frame"], 1, 1, 1)
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT", 0, (E.PixelMode and 1 or 3))
+ GameTooltip:ClearLines()
+ GameTooltip:AddDoubleLine(L["Left Click:"], L["Toggle Chat Frame"], 1, 1, 1)
+ end
+
+ GameTooltip:Show()
+end
+
+local function ChatButton_OnLeave(self)
+ if E.db[self.parent:GetName().."Faded"] then
+ UIFrameFadeOut(self.parent, 0.2, self.parent:GetAlpha(), 0)
+ self.parent.fadeInfo.finishedFunc = self.parent.fadeFunc
+
+ if E.db.chat.fadeChatToggles then
+ UIFrameFadeOut(self, 0.2, self:GetAlpha(), 0)
+ end
+ end
+ GameTooltip:Hide()
+end
+
+local function ChatButton_OnClick(self)
+ GameTooltip:Hide()
+
+ local name = self.parent:GetName().."Faded"
+ if E.db[name] then
+ E.db[name] = nil
+ UIFrameFadeIn(self.parent, 0.2, self.parent:GetAlpha(), 1)
+ if E.db.chat.fadeChatToggles then
+ UIFrameFadeIn(self, 0.2, self:GetAlpha(), 1)
+ end
+ else
+ E.db[name] = true
+ UIFrameFadeOut(self.parent, 0.2, self.parent:GetAlpha(), 0)
+ self.parent.fadeInfo.finishedFunc = self.parent.fadeFunc
+ if E.db.chat.fadeChatToggles then
+ UIFrameFadeOut(self, 0.2, self:GetAlpha(), 0)
+ end
+ end
+end
+
+function HideLeftChat()
+ ChatButton_OnClick(LeftChatToggleButton)
+end
+
+function HideRightChat()
+ ChatButton_OnClick(RightChatToggleButton)
+end
+
+function HideBothChat()
+ ChatButton_OnClick(LeftChatToggleButton)
+ ChatButton_OnClick(RightChatToggleButton)
+end
+
+function LO:ToggleChatTabPanels(rightOverride, leftOverride)
+ if leftOverride or not E.db.chat.panelTabBackdrop then
+ LeftChatTab:Hide()
+ else
+ LeftChatTab:Show()
+ end
+
+ if rightOverride or not E.db.chat.panelTabBackdrop then
+ RightChatTab:Hide()
+ else
+ RightChatTab:Show()
+ end
+end
+
+function LO:SetChatTabStyle()
+ local tabStyle = E.db.chat.panelTabTransparency and "Transparent" or nil
+ local glossTex = not tabStyle and true or nil
+
+ LeftChatTab:SetTemplate(tabStyle, glossTex)
+ RightChatTab:SetTemplate(tabStyle, glossTex)
+end
+
+function LO:SetDataPanelStyle()
+ local miniStyle = E.db.datatexts.panelTransparency and "Transparent" or "Default"
+ local panelStyle = (not E.db.datatexts.panelBackdrop) and "NoBackdrop" or miniStyle
+
+ local panelGlossTex = (panelStyle and true) or nil
+ local miniGlossTex = (miniStyle and nil) or true
+
+ LeftChatDataPanel:SetTemplate(panelStyle, panelGlossTex)
+ LeftChatToggleButton:SetTemplate(panelStyle, panelGlossTex)
+ RightChatDataPanel:SetTemplate(panelStyle, panelGlossTex)
+ RightChatToggleButton:SetTemplate(panelStyle, panelGlossTex)
+
+ LeftMiniPanel:SetTemplate(miniStyle, miniGlossTex)
+ RightMiniPanel:SetTemplate(miniStyle, miniGlossTex)
+ ElvConfigToggle:SetTemplate(miniStyle, miniGlossTex)
+end
+
+function LO:RepositionChatDataPanels()
+ LeftChatDataPanel:ClearAllPoints()
+ RightChatDataPanel:ClearAllPoints()
+
+ local SPACING = E.Border*3 - E.Spacing
+ local SIDE_BUTTON_SPACING = (E.PixelMode and E.Border*4) or SPACING*2
+
+ --Left Chat Tab
+ LeftChatTab:Point("TOPLEFT", LeftChatPanel, "TOPLEFT", SPACING, -SPACING)
+ LeftChatTab:Point("TOPRIGHT", LeftChatPanel, "TOPRIGHT", -SPACING, -SPACING)
+ LeftChatTab:Point("BOTTOMRIGHT", LeftChatPanel, "TOPRIGHT", -SPACING, -(SPACING + PANEL_HEIGHT))
+ LeftChatTab:Point("BOTTOMLEFT", LeftChatPanel, "TOPLEFT", SPACING, -(SPACING + PANEL_HEIGHT))
+
+ --Left Chat Data Panel
+ LeftChatDataPanel:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMLEFT", SPACING + SIDE_BUTTON_WIDTH, SPACING)
+ LeftChatDataPanel:Point("BOTTOMRIGHT", LeftChatPanel, "BOTTOMRIGHT", -SPACING, SPACING)
+ LeftChatDataPanel:Point("TOPRIGHT", LeftChatPanel, "BOTTOMRIGHT", -SPACING, (SPACING + PANEL_HEIGHT))
+ LeftChatDataPanel:Point("TOPLEFT", LeftChatPanel, "BOTTOMLEFT", SIDE_BUTTON_SPACING + SIDE_BUTTON_WIDTH, (SPACING + PANEL_HEIGHT))
+
+ --Left Chat Toggle Button
+ LeftChatToggleButton:Point("TOPRIGHT", LeftChatDataPanel, "TOPLEFT", E.Border - E.Spacing*3, 0)
+ LeftChatToggleButton:Point("TOPLEFT", LeftChatDataPanel, "TOPLEFT", -E.Border - E.Spacing*3 - SIDE_BUTTON_WIDTH, 0)
+ LeftChatToggleButton:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMLEFT", SPACING, SPACING)
+ LeftChatToggleButton:Point("BOTTOMRIGHT", LeftChatPanel, "BOTTOMLEFT", SPACING + SIDE_BUTTON_WIDTH, SPACING)
+
+ --Right Chat Tab
+ RightChatTab:Point("TOPRIGHT", RightChatPanel, "TOPRIGHT", -SPACING, -SPACING)
+ RightChatTab:Point("TOPLEFT", RightChatPanel, "TOPLEFT", SPACING, -SPACING)
+ RightChatTab:Point("BOTTOMLEFT", RightChatPanel, "TOPLEFT", SPACING, -(SPACING + PANEL_HEIGHT))
+ RightChatTab:Point("BOTTOMRIGHT", RightChatPanel, "TOPRIGHT", -SPACING, -(SPACING + PANEL_HEIGHT))
+
+ --Right Chat Data Panel
+ RightChatDataPanel:Point("BOTTOMLEFT", RightChatPanel, "BOTTOMLEFT", SPACING, SPACING)
+ RightChatDataPanel:Point("BOTTOMRIGHT", RightChatPanel, "BOTTOMRIGHT", -SPACING-SIDE_BUTTON_WIDTH, SPACING)
+ RightChatDataPanel:Point("TOPRIGHT", RightChatPanel, "BOTTOMRIGHT", -(SIDE_BUTTON_SPACING + SIDE_BUTTON_WIDTH), SPACING + PANEL_HEIGHT)
+ RightChatDataPanel:Point("TOPLEFT", RightChatPanel, "BOTTOMLEFT", (SPACING), SPACING + PANEL_HEIGHT)
+
+ --Right Chat Toggle Button
+ RightChatToggleButton:Point("TOPLEFT", RightChatDataPanel, "TOPRIGHT", -E.Border + E.Spacing*3, 0)
+ RightChatToggleButton:Point("TOPRIGHT", RightChatDataPanel, "TOPRIGHT", E.Border + E.Spacing*3 + SIDE_BUTTON_WIDTH, 0)
+ RightChatToggleButton:Point("BOTTOMRIGHT", RightChatPanel, "BOTTOMRIGHT", -SPACING, SPACING)
+ RightChatToggleButton:Point("BOTTOMLEFT", RightChatPanel, "BOTTOMRIGHT", -SPACING - SIDE_BUTTON_WIDTH, SPACING)
+end
+
+function LO:ToggleChatPanels()
+ LeftChatDataPanel:ClearAllPoints()
+ RightChatDataPanel:ClearAllPoints()
+
+ local SPACING = E.Border*3 - E.Spacing
+ local SIDE_BUTTON_SPACING = (E.PixelMode and E.Border*4) or SPACING*2
+
+ if E.db.datatexts.leftChatPanel then
+ LeftChatDataPanel:Show()
+ LeftChatToggleButton:Show()
+ else
+ LeftChatDataPanel:Hide()
+ LeftChatToggleButton:Hide()
+ end
+
+ if E.db.datatexts.rightChatPanel then
+ RightChatDataPanel:Show()
+ RightChatToggleButton:Show()
+ else
+ RightChatDataPanel:Hide()
+ RightChatToggleButton:Hide()
+ end
+
+ local panelBackdrop = E.db.chat.panelBackdrop
+ if panelBackdrop == "SHOWBOTH" then
+ LeftChatPanel.backdrop:Show()
+ RightChatPanel.backdrop:Show()
+ LeftChatDataPanel:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMLEFT", SIDE_BUTTON_SPACING + SIDE_BUTTON_WIDTH, SPACING)
+ LeftChatDataPanel:Point("TOPRIGHT", LeftChatPanel, "BOTTOMRIGHT", -SPACING, (SPACING + PANEL_HEIGHT))
+ RightChatDataPanel:Point("BOTTOMLEFT", RightChatPanel, "BOTTOMLEFT", SPACING, SPACING)
+ RightChatDataPanel:Point("TOPRIGHT", RightChatPanel, "BOTTOMRIGHT", -(SIDE_BUTTON_SPACING + SIDE_BUTTON_WIDTH), SPACING + PANEL_HEIGHT)
+ LeftChatToggleButton:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMLEFT", SPACING, SPACING)
+ RightChatToggleButton:Point("BOTTOMRIGHT", RightChatPanel, "BOTTOMRIGHT", -SPACING, SPACING)
+ LO:ToggleChatTabPanels()
+ elseif panelBackdrop == "HIDEBOTH" then
+ LeftChatPanel.backdrop:Hide()
+ RightChatPanel.backdrop:Hide()
+ LeftChatDataPanel:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMLEFT", SIDE_BUTTON_WIDTH, 0)
+ LeftChatDataPanel:Point("TOPRIGHT", LeftChatPanel, "BOTTOMRIGHT", 0, PANEL_HEIGHT)
+ RightChatDataPanel:Point("BOTTOMLEFT", RightChatPanel, "BOTTOMLEFT")
+ RightChatDataPanel:Point("TOPRIGHT", RightChatPanel, "BOTTOMRIGHT", -SIDE_BUTTON_WIDTH, PANEL_HEIGHT)
+ LeftChatToggleButton:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMLEFT")
+ RightChatToggleButton:Point("BOTTOMRIGHT", RightChatPanel, "BOTTOMRIGHT")
+ LO:ToggleChatTabPanels(true, true)
+ elseif panelBackdrop == "LEFT" then
+ LeftChatPanel.backdrop:Show()
+ RightChatPanel.backdrop:Hide()
+ LeftChatDataPanel:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMLEFT", SIDE_BUTTON_SPACING + SIDE_BUTTON_WIDTH, SPACING)
+ LeftChatDataPanel:Point("TOPRIGHT", LeftChatPanel, "BOTTOMRIGHT", -SPACING, (SPACING + PANEL_HEIGHT))
+ RightChatDataPanel:Point("BOTTOMLEFT", RightChatPanel, "BOTTOMLEFT")
+ RightChatDataPanel:Point("TOPRIGHT", RightChatPanel, "BOTTOMRIGHT", -SIDE_BUTTON_WIDTH, PANEL_HEIGHT)
+ LeftChatToggleButton:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMLEFT", SPACING, SPACING)
+ RightChatToggleButton:Point("BOTTOMRIGHT", RightChatPanel, "BOTTOMRIGHT")
+ LO:ToggleChatTabPanels(true)
+ else
+ LeftChatPanel.backdrop:Hide()
+ RightChatPanel.backdrop:Show()
+ LeftChatDataPanel:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMLEFT", SIDE_BUTTON_WIDTH, 0)
+ LeftChatDataPanel:Point("TOPRIGHT", LeftChatPanel, "BOTTOMRIGHT", 0, PANEL_HEIGHT)
+ RightChatDataPanel:Point("BOTTOMLEFT", RightChatPanel, "BOTTOMLEFT", SPACING, SPACING)
+ RightChatDataPanel:Point("TOPRIGHT", RightChatPanel, "BOTTOMRIGHT", -(SIDE_BUTTON_SPACING + SIDE_BUTTON_WIDTH), SPACING + PANEL_HEIGHT)
+ LeftChatToggleButton:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMLEFT")
+ RightChatToggleButton:Point("BOTTOMRIGHT", RightChatPanel, "BOTTOMRIGHT", -SPACING, SPACING)
+ LO:ToggleChatTabPanels(nil, true)
+ end
+end
+
+function LO:CreateChatPanels()
+ local SPACING = E.Border*3 - E.Spacing
+ local SIDE_BUTTON_SPACING = (E.PixelMode and E.Border*4) or SPACING*2
+
+ --Left Chat
+ local lchat = CreateFrame("Frame", "LeftChatPanel", E.UIParent)
+ lchat:SetFrameStrata("BACKGROUND")
+ lchat:SetFrameLevel(100)
+ lchat:Size(E.db.chat.panelWidth, E.db.chat.panelHeight)
+ lchat:Point("BOTTOMLEFT", E.UIParent, 4, 4)
+ lchat:CreateBackdrop("Transparent")
+ lchat.backdrop.ignoreBackdropColors = true
+ lchat.backdrop:SetAllPoints()
+ E:CreateMover(lchat, "LeftChatMover", L["Left Chat"], nil, nil, nil, nil, nil, "chat,general")
+
+ --Background Texture
+ lchat.tex = lchat:CreateTexture(nil, "OVERLAY")
+ lchat.tex:SetInside()
+ lchat.tex:SetTexture(E.db.chat.panelBackdropNameLeft)
+ lchat.tex:SetAlpha(E.db.general.backdropfadecolor.a - 0.7 > 0 and E.db.general.backdropfadecolor.a - 0.7 or 0.5)
+
+ --Left Chat Tab
+ local lchattab = CreateFrame("Frame", "LeftChatTab", lchat)
+ lchattab:Point("TOPLEFT", lchat, "TOPLEFT", SPACING, -SPACING)
+ lchattab:Point("TOPRIGHT", lchat, "TOPRIGHT", -SPACING, -SPACING)
+ lchattab:Point("BOTTOMRIGHT", lchat, "TOPRIGHT", -SPACING, -(SPACING + PANEL_HEIGHT))
+ lchattab:Point("BOTTOMLEFT", lchat, "TOPLEFT", SPACING, -(SPACING + PANEL_HEIGHT))
+ lchattab:SetTemplate(E.db.chat.panelTabTransparency and "Transparent" or "Default", true)
+
+ --Left Chat Data Panel
+ local lchatdp = CreateFrame("Frame", "LeftChatDataPanel", lchat)
+ lchatdp:Point("BOTTOMLEFT", lchat, "BOTTOMLEFT", SPACING + SIDE_BUTTON_WIDTH, SPACING)
+ lchatdp:Point("BOTTOMRIGHT", lchat, "BOTTOMRIGHT", -SPACING, SPACING)
+ lchatdp:Point("TOPRIGHT", lchat, "BOTTOMRIGHT", -SPACING, (SPACING + PANEL_HEIGHT))
+ lchatdp:Point("TOPLEFT", lchat, "BOTTOMLEFT", SIDE_BUTTON_SPACING+SIDE_BUTTON_WIDTH, (SPACING + PANEL_HEIGHT))
+ lchatdp:SetTemplate(E.db.datatexts.panelTransparency and "Transparent" or "Default", true)
+
+ DT:RegisterPanel(lchatdp, 3, "ANCHOR_TOPLEFT", -17, 4)
+
+ --Left Chat Toggle Button
+ local lchattb = CreateFrame("Button", "LeftChatToggleButton", E.UIParent)
+ lchattb.parent = lchat
+ LeftChatPanel.fadeFunc = ChatPanelLeft_OnFade
+ lchattb:Point("TOPRIGHT", lchatdp, "TOPLEFT", E.Border - E.Spacing*3, 0)
+ lchattb:Point("TOPLEFT", lchatdp, "TOPLEFT", -E.Border - E.Spacing*3 - SIDE_BUTTON_WIDTH, 0)
+ lchattb:Point("BOTTOMLEFT", lchat, "BOTTOMLEFT", SPACING, SPACING)
+ lchattb:Point("BOTTOMRIGHT", lchat, "BOTTOMLEFT", SPACING+SIDE_BUTTON_WIDTH, SPACING)
+ lchattb:SetTemplate(E.db.datatexts.panelTransparency and "Transparent" or "Default", true)
+ lchattb:RegisterForClicks("AnyUp")
+ lchattb:SetScript("OnEnter", ChatButton_OnEnter)
+ lchattb:SetScript("OnLeave", ChatButton_OnLeave)
+ lchattb:SetScript("OnClick", ChatButton_OnClick)
+ lchattb.text = lchattb:CreateFontString(nil, "OVERLAY")
+ lchattb.text:FontTemplate()
+ lchattb.text:Point("CENTER")
+ lchattb.text:SetJustifyH("CENTER")
+ lchattb.text:SetText("<")
+
+ --Right Chat
+ local rchat = CreateFrame("Frame", "RightChatPanel", E.UIParent)
+ rchat:SetFrameStrata("BACKGROUND")
+ rchat:SetFrameLevel(100)
+ rchat:Size(E.db.chat.separateSizes and E.db.chat.panelWidthRight or E.db.chat.panelWidth, E.db.chat.separateSizes and E.db.chat.panelHeightRight or E.db.chat.panelHeight)
+ rchat:Point("BOTTOMRIGHT", E.UIParent, -4, 4)
+ rchat:CreateBackdrop("Transparent")
+ rchat.backdrop.ignoreBackdropColors = true
+ rchat.backdrop:SetAllPoints()
+ E:CreateMover(rchat, "RightChatMover", L["Right Chat"], nil, nil, nil, nil, nil, "chat,general")
+
+ --Background Texture
+ rchat.tex = rchat:CreateTexture(nil, "OVERLAY")
+ rchat.tex:SetInside()
+ rchat.tex:SetTexture(E.db.chat.panelBackdropNameRight)
+ rchat.tex:SetAlpha(E.db.general.backdropfadecolor.a - 0.7 > 0 and E.db.general.backdropfadecolor.a - 0.7 or 0.5)
+
+ --Right Chat Tab
+ local rchattab = CreateFrame("Frame", "RightChatTab", rchat)
+ rchattab:Point("TOPRIGHT", rchat, "TOPRIGHT", -SPACING, -SPACING)
+ rchattab:Point("TOPLEFT", rchat, "TOPLEFT", SPACING, -SPACING)
+ rchattab:Point("BOTTOMLEFT", rchat, "TOPLEFT", SPACING, -(SPACING + PANEL_HEIGHT))
+ rchattab:Point("BOTTOMRIGHT", rchat, "TOPRIGHT", -SPACING, -(SPACING + PANEL_HEIGHT))
+ rchattab:SetTemplate(E.db.chat.panelTabTransparency and "Transparent" or "Default", true)
+
+ --Right Chat Data Panel
+ local rchatdp = CreateFrame("Frame", "RightChatDataPanel", rchat)
+ rchatdp:Point("BOTTOMLEFT", rchat, "BOTTOMLEFT", SPACING, SPACING)
+ rchatdp:Point("BOTTOMRIGHT", rchat, "BOTTOMRIGHT", -SPACING-SIDE_BUTTON_WIDTH, SPACING)
+ rchatdp:Point("TOPRIGHT", rchat, "BOTTOMRIGHT", -(SIDE_BUTTON_SPACING + SIDE_BUTTON_WIDTH), SPACING + PANEL_HEIGHT)
+ rchatdp:Point("TOPLEFT", rchat, "BOTTOMLEFT", (SPACING), SPACING + PANEL_HEIGHT)
+ rchatdp:SetTemplate(E.db.datatexts.panelTransparency and "Transparent" or "Default", true)
+ DT:RegisterPanel(rchatdp, 3, "ANCHOR_TOPRIGHT", 17, 4)
+
+ --Right Chat Toggle Button
+ local rchattb = CreateFrame("Button", "RightChatToggleButton", E.UIParent)
+ rchattb.parent = rchat
+ rchat.fadeFunc = ChatPanelRight_OnFade
+ rchattb:Point("TOPLEFT", rchatdp, "TOPRIGHT", -E.Border + E.Spacing*3, 0)
+ rchattb:Point("TOPRIGHT", rchatdp, "TOPRIGHT", E.Border + E.Spacing*3 + SIDE_BUTTON_WIDTH, 0)
+ rchattb:Point("BOTTOMRIGHT", rchat, "BOTTOMRIGHT", -SPACING, SPACING)
+ rchattb:Point("BOTTOMLEFT", rchat, "BOTTOMRIGHT", -SPACING-SIDE_BUTTON_WIDTH, SPACING)
+ rchattb:SetTemplate(E.db.datatexts.panelTransparency and "Transparent" or "Default", true)
+ rchattb:RegisterForClicks("AnyUp")
+ rchattb:SetScript("OnEnter", ChatButton_OnEnter)
+ rchattb:SetScript("OnLeave", ChatButton_OnLeave)
+ rchattb:SetScript("OnClick", ChatButton_OnClick)
+ rchattb.text = rchattb:CreateFontString(nil, "OVERLAY")
+ rchattb.text:FontTemplate()
+ rchattb.text:Point("CENTER")
+ rchattb.text:SetJustifyH("CENTER")
+ rchattb.text:SetText(">")
+
+ --Load Settings
+ local fadeToggle = E.db.chat.fadeChatToggles
+ if E.db.LeftChatPanelFaded then
+ if fadeToggle then
+ LeftChatToggleButton:SetAlpha(0)
+ end
+
+ lchat:Hide()
+ end
+
+ if E.db.RightChatPanelFaded then
+ if fadeToggle then
+ RightChatToggleButton:SetAlpha(0)
+ end
+
+ rchat:Hide()
+ end
+
+ self:ToggleChatPanels()
+end
+
+function LO:CreateMinimapPanels()
+ local lminipanel = CreateFrame("Frame", "LeftMiniPanel", Minimap)
+ lminipanel:Point("TOPLEFT", Minimap, "BOTTOMLEFT", -E.Border, -E.Spacing*3)
+ lminipanel:Point("BOTTOMRIGHT", Minimap, "BOTTOM", 0, -(E.Spacing*3 + PANEL_HEIGHT))
+ lminipanel:SetTemplate(E.db.datatexts.panelTransparency and "Transparent" or "Default", true)
+ DT:RegisterPanel(lminipanel, 1, "ANCHOR_BOTTOMLEFT", lminipanel:GetWidth() * 2, -4)
+
+ local rminipanel = CreateFrame("Frame", "RightMiniPanel", Minimap)
+ rminipanel:Point("TOPRIGHT", Minimap, "BOTTOMRIGHT", E.Border, -(E.Spacing*3))
+ rminipanel:Point("BOTTOMLEFT", lminipanel, "BOTTOMRIGHT", -E.Border + (E.Spacing*3), 0)
+ rminipanel:SetTemplate(E.db.datatexts.panelTransparency and "Transparent" or "Default", true)
+ DT:RegisterPanel(rminipanel, 1, "ANCHOR_BOTTOM", 0, -4)
+
+ if E.db.datatexts.minimapPanels then
+ LeftMiniPanel:Show()
+ RightMiniPanel:Show()
+ else
+ LeftMiniPanel:Hide()
+ RightMiniPanel:Hide()
+ end
+
+ local configtoggle = CreateFrame("Button", "ElvConfigToggle", Minimap)
+ if E.db.general.reminder.position == "LEFT" then
+ configtoggle:Point("TOPRIGHT", lminipanel, "TOPLEFT", (E.PixelMode and 1 or -1), 0)
+ configtoggle:Point("BOTTOMRIGHT", lminipanel, "BOTTOMLEFT", (E.PixelMode and 1 or -1), 0)
+ else
+ configtoggle:Point("TOPLEFT", rminipanel, "TOPRIGHT", (E.PixelMode and -1 or 1), 0)
+ configtoggle:Point("BOTTOMLEFT", rminipanel, "BOTTOMRIGHT", (E.PixelMode and -1 or 1), 0)
+ end
+ configtoggle:RegisterForClicks("AnyUp")
+ configtoggle:Width(E.RBRWidth)
+ configtoggle:SetTemplate(E.db.datatexts.panelTransparency and "Transparent" or "Default", true)
+ configtoggle.text = configtoggle:CreateFontString(nil, "OVERLAY")
+ configtoggle.text:FontTemplate(E.Libs.LSM:Fetch("font", E.db.datatexts.font), E.db.datatexts.fontSize, E.db.datatexts.fontOutline)
+ configtoggle.text:SetText("C")
+ configtoggle.text:SetPoint("CENTER")
+ configtoggle.text:SetJustifyH("CENTER")
+ configtoggle:SetScript("OnClick", function(_, btn)
+ if btn == "LeftButton" then
+ E:ToggleOptionsUI()
+ else
+ E:BGStats()
+ end
+ end)
+ configtoggle:SetScript("OnEnter", function(self)
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT", 0, -4)
+ GameTooltip:ClearLines()
+ GameTooltip:AddDoubleLine(L["Left Click:"], L["Toggle Configuration"], 1, 1, 1)
+
+ if E.db.datatexts.battleground then
+ GameTooltip:AddDoubleLine(L["Right Click:"], L["Show BG Texts"], 1, 1, 1)
+ end
+ GameTooltip:Show()
+ end)
+ configtoggle:SetScript("OnLeave", function()
+ GameTooltip:Hide()
+ end)
+
+ local f = CreateFrame("Frame", "BottomMiniPanel", Minimap)
+ f:SetPoint("BOTTOM", Minimap, "BOTTOM")
+ f:Width(120)
+ f:Height(20)
+ f:SetFrameLevel(Minimap:GetFrameLevel() + 5)
+ DT:RegisterPanel(f, 1, "ANCHOR_BOTTOM", 0, -10)
+
+ f = CreateFrame("Frame", "TopMiniPanel", Minimap)
+ f:SetPoint("TOP", Minimap, "TOP")
+ f:Width(120)
+ f:Height(20)
+ f:SetFrameLevel(Minimap:GetFrameLevel() + 5)
+ DT:RegisterPanel(f, 1, "ANCHOR_BOTTOM", 0, -10)
+
+ f = CreateFrame("Frame", "TopLeftMiniPanel", Minimap)
+ f:SetPoint("TOPLEFT", Minimap, "TOPLEFT")
+ f:Width(75)
+ f:Height(20)
+ f:SetFrameLevel(Minimap:GetFrameLevel() + 5)
+ DT:RegisterPanel(f, 1, "ANCHOR_BOTTOMLEFT", 0, -10)
+
+ f = CreateFrame("Frame", "TopRightMiniPanel", Minimap)
+ f:SetPoint("TOPRIGHT", Minimap, "TOPRIGHT")
+ f:Width(75)
+ f:Height(20)
+ f:SetFrameLevel(Minimap:GetFrameLevel() + 5)
+ DT:RegisterPanel(f, 1, "ANCHOR_BOTTOMRIGHT", 0, -10)
+
+ f = CreateFrame("Frame", "BottomLeftMiniPanel", Minimap)
+ f:SetPoint("BOTTOMLEFT", Minimap, "BOTTOMLEFT")
+ f:Width(75)
+ f:Height(20)
+ f:SetFrameLevel(Minimap:GetFrameLevel() + 5)
+ DT:RegisterPanel(f, 1, "ANCHOR_BOTTOMLEFT", 0, -10)
+
+ f = CreateFrame("Frame", "BottomRightMiniPanel", Minimap)
+ f:SetPoint("BOTTOMRIGHT", Minimap, "BOTTOMRIGHT")
+ f:Width(75)
+ f:Height(20)
+ f:SetFrameLevel(Minimap:GetFrameLevel() + 5)
+ DT:RegisterPanel(f, 1, "ANCHOR_BOTTOMRIGHT", 0, -10)
+end
+
+local function InitializeCallback()
+ LO:Initialize()
+end
+
+E:RegisterModule(LO:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Layout/Load_Layout.xml b/ElvUI/Layout/Load_Layout.xml
new file mode 100644
index 0000000..5b02b2e
--- /dev/null
+++ b/ElvUI/Layout/Load_Layout.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/Ace3/AceAddon-3.0/AceAddon-3.0.lua b/ElvUI/Libraries/Ace3/AceAddon-3.0/AceAddon-3.0.lua
new file mode 100644
index 0000000..3dbaa1c
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceAddon-3.0/AceAddon-3.0.lua
@@ -0,0 +1,674 @@
+--- **AceAddon-3.0** provides a template for creating addon objects.
+-- It'll provide you with a set of callback functions that allow you to simplify the loading
+-- process of your addon.\\
+-- Callbacks provided are:\\
+-- * **OnInitialize**, which is called directly after the addon is fully loaded.
+-- * **OnEnable** which gets called during the PLAYER_LOGIN event, when most of the data provided by the game is already present.
+-- * **OnDisable**, which is only called when your addon is manually being disabled.
+-- @usage
+-- -- A small (but complete) addon, that doesn't do anything,
+-- -- but shows usage of the callbacks.
+-- local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
+--
+-- function MyAddon:OnInitialize()
+-- -- do init tasks here, like loading the Saved Variables,
+-- -- or setting up slash commands.
+-- end
+--
+-- function MyAddon:OnEnable()
+-- -- Do more initialization here, that really enables the use of your addon.
+-- -- Register Events, Hook functions, Create Frames, Get information from
+-- -- the game that wasn't available in OnInitialize
+-- end
+--
+-- function MyAddon:OnDisable()
+-- -- Unhook, Unregister Events, Hide frames that you created.
+-- -- You would probably only use an OnDisable if you want to
+-- -- build a "standby" mode, or be able to toggle modules on/off.
+-- end
+-- @class file
+-- @name AceAddon-3.0.lua
+-- @release $Id$
+
+local MAJOR, MINOR = "AceAddon-3.0", 12
+local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceAddon then return end -- No Upgrade needed.
+
+AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame
+AceAddon.addons = AceAddon.addons or {} -- addons in general
+AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon.
+AceAddon.initializequeue = AceAddon.initializequeue or {} -- addons that are new and not initialized
+AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized and waiting to be enabled
+AceAddon.embeds = AceAddon.embeds or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end }) -- contains a list of libraries embedded in an addon
+
+-- Lua APIs
+local tinsert, tconcat, tremove = table.insert, table.concat, table.remove
+local fmt, tostring = string.format, tostring
+local select, pairs, next, type, unpack = select, pairs, next, type, unpack
+local loadstring, assert, error = loadstring, assert, error
+local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: LibStub, IsLoggedIn, geterrorhandler
+
+--[[
+ xpcall safecall implementation
+]]
+local xpcall = xpcall
+
+local function errorhandler(err)
+ return geterrorhandler()(err)
+end
+
+local function CreateDispatcher(argCount)
+ local code = [[
+ local xpcall, eh = ...
+ local method, ARGS
+ local function call() return method(ARGS) end
+
+ local function dispatch(func, ...)
+ method = func
+ if not method then return end
+ ARGS = ...
+ return xpcall(call, eh)
+ end
+
+ return dispatch
+ ]]
+
+ local ARGS = {}
+ for i = 1, argCount do ARGS[i] = "arg"..i end
+ code = code:gsub("ARGS", tconcat(ARGS, ", "))
+ return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
+end
+
+local Dispatchers = setmetatable({}, {__index=function(self, argCount)
+ local dispatcher = CreateDispatcher(argCount)
+ rawset(self, argCount, dispatcher)
+ return dispatcher
+end})
+Dispatchers[0] = function(func)
+ return xpcall(func, errorhandler)
+end
+
+local function safecall(func, ...)
+ -- we check to see if the func is passed is actually a function here and don't error when it isn't
+ -- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
+ -- present execution should continue without hinderance
+ if type(func) == "function" then
+ return Dispatchers[select('#', ...)](func, ...)
+ end
+end
+
+-- local functions that will be implemented further down
+local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype
+
+-- used in the addon metatable
+local function addontostring( self ) return self.name end
+
+-- Check if the addon is queued for initialization
+local function queuedForInitialization(addon)
+ for i = 1, #AceAddon.initializequeue do
+ if AceAddon.initializequeue[i] == addon then
+ return true
+ end
+ end
+ return false
+end
+
+--- Create a new AceAddon-3.0 addon.
+-- Any libraries you specified will be embeded, and the addon will be scheduled for
+-- its OnInitialize and OnEnable callbacks.
+-- The final addon object, with all libraries embeded, will be returned.
+-- @paramsig [object ,]name[, lib, ...]
+-- @param object Table to use as a base for the addon (optional)
+-- @param name Name of the addon object to create
+-- @param lib List of libraries to embed into the addon
+-- @usage
+-- -- Create a simple addon object
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceEvent-3.0")
+--
+-- -- Create a Addon object based on the table of a frame
+-- local MyFrame = CreateFrame("Frame")
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon(MyFrame, "MyAddon", "AceEvent-3.0")
+function AceAddon:NewAddon(objectorname, ...)
+ local object,name
+ local i=1
+ if type(objectorname)=="table" then
+ object=objectorname
+ name=...
+ i=2
+ else
+ name=objectorname
+ end
+ if type(name)~="string" then
+ error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2)
+ end
+ if self.addons[name] then
+ error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2)
+ end
+
+ object = object or {}
+ object.name = name
+
+ local addonmeta = {}
+ local oldmeta = getmetatable(object)
+ if oldmeta then
+ for k, v in pairs(oldmeta) do addonmeta[k] = v end
+ end
+ addonmeta.__tostring = addontostring
+
+ setmetatable( object, addonmeta )
+ self.addons[name] = object
+ object.modules = {}
+ object.orderedModules = {}
+ object.defaultModuleLibraries = {}
+ Embed( object ) -- embed NewModule, GetModule methods
+ self:EmbedLibraries(object, select(i,...))
+
+ -- add to queue of addons to be initialized upon ADDON_LOADED
+ tinsert(self.initializequeue, object)
+ return object
+end
+
+
+--- Get the addon object by its name from the internal AceAddon registry.
+-- Throws an error if the addon object cannot be found (except if silent is set).
+-- @param name unique name of the addon object
+-- @param silent if true, the addon is optional, silently return nil if its not found
+-- @usage
+-- -- Get the Addon
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+function AceAddon:GetAddon(name, silent)
+ if not silent and not self.addons[name] then
+ error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2)
+ end
+ return self.addons[name]
+end
+
+-- - Embed a list of libraries into the specified addon.
+-- This function will try to embed all of the listed libraries into the addon
+-- and error if a single one fails.
+--
+-- **Note:** This function is for internal use by :NewAddon/:NewModule
+-- @paramsig addon, [lib, ...]
+-- @param addon addon object to embed the libs in
+-- @param lib List of libraries to embed into the addon
+function AceAddon:EmbedLibraries(addon, ...)
+ for i=1,select("#", ... ) do
+ local libname = select(i, ...)
+ self:EmbedLibrary(addon, libname, false, 4)
+ end
+end
+
+-- - Embed a library into the addon object.
+-- This function will check if the specified library is registered with LibStub
+-- and if it has a :Embed function to call. It'll error if any of those conditions
+-- fails.
+--
+-- **Note:** This function is for internal use by :EmbedLibraries
+-- @paramsig addon, libname[, silent[, offset]]
+-- @param addon addon object to embed the library in
+-- @param libname name of the library to embed
+-- @param silent marks an embed to fail silently if the library doesn't exist (optional)
+-- @param offset will push the error messages back to said offset, defaults to 2 (optional)
+function AceAddon:EmbedLibrary(addon, libname, silent, offset)
+ local lib = LibStub:GetLibrary(libname, true)
+ if not lib and not silent then
+ error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2)
+ elseif lib and type(lib.Embed) == "function" then
+ lib:Embed(addon)
+ tinsert(self.embeds[addon], libname)
+ return true
+ elseif lib then
+ error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2)
+ end
+end
+
+--- Return the specified module from an addon object.
+-- Throws an error if the addon object cannot be found (except if silent is set)
+-- @name //addon//:GetModule
+-- @paramsig name[, silent]
+-- @param name unique name of the module
+-- @param silent if true, the module is optional, silently return nil if its not found (optional)
+-- @usage
+-- -- Get the Addon
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- -- Get the Module
+-- MyModule = MyAddon:GetModule("MyModule")
+function GetModule(self, name, silent)
+ if not self.modules[name] and not silent then
+ error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2)
+ end
+ return self.modules[name]
+end
+
+local function IsModuleTrue(self) return true end
+
+--- Create a new module for the addon.
+-- The new module can have its own embeded libraries and/or use a module prototype to be mixed into the module.\\
+-- A module has the same functionality as a real addon, it can have modules of its own, and has the same API as
+-- an addon object.
+-- @name //addon//:NewModule
+-- @paramsig name[, prototype|lib[, lib, ...]]
+-- @param name unique name of the module
+-- @param prototype object to derive this module from, methods and values from this table will be mixed into the module (optional)
+-- @param lib List of libraries to embed into the addon
+-- @usage
+-- -- Create a module with some embeded libraries
+-- MyModule = MyAddon:NewModule("MyModule", "AceEvent-3.0", "AceHook-3.0")
+--
+-- -- Create a module with a prototype
+-- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
+-- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0")
+function NewModule(self, name, prototype, ...)
+ if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end
+ if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end
+
+ if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end
+
+ -- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well.
+ -- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is.
+ local module = AceAddon:NewAddon(fmt("%s_%s", self.name or tostring(self), name))
+
+ module.IsModule = IsModuleTrue
+ module:SetEnabledState(self.defaultModuleState)
+ module.moduleName = name
+
+ if type(prototype) == "string" then
+ AceAddon:EmbedLibraries(module, prototype, ...)
+ else
+ AceAddon:EmbedLibraries(module, ...)
+ end
+ AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries))
+
+ if not prototype or type(prototype) == "string" then
+ prototype = self.defaultModulePrototype or nil
+ end
+
+ if type(prototype) == "table" then
+ local mt = getmetatable(module)
+ mt.__index = prototype
+ setmetatable(module, mt) -- More of a Base class type feel.
+ end
+
+ safecall(self.OnModuleCreated, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy.
+ self.modules[name] = module
+ tinsert(self.orderedModules, module)
+
+ return module
+end
+
+--- Returns the real name of the addon or module, without any prefix.
+-- @name //addon//:GetName
+-- @paramsig
+-- @usage
+-- print(MyAddon:GetName())
+-- -- prints "MyAddon"
+function GetName(self)
+ return self.moduleName or self.name
+end
+
+--- Enables the Addon, if possible, return true or false depending on success.
+-- This internally calls AceAddon:EnableAddon(), thus dispatching a OnEnable callback
+-- and enabling all modules of the addon (unless explicitly disabled).\\
+-- :Enable() also sets the internal `enableState` variable to true
+-- @name //addon//:Enable
+-- @paramsig
+-- @usage
+-- -- Enable MyModule
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyModule = MyAddon:GetModule("MyModule")
+-- MyModule:Enable()
+function Enable(self)
+ self:SetEnabledState(true)
+
+ -- nevcairiel 2013-04-27: don't enable an addon/module if its queued for init still
+ -- it'll be enabled after the init process
+ if not queuedForInitialization(self) then
+ return AceAddon:EnableAddon(self)
+ end
+end
+
+--- Disables the Addon, if possible, return true or false depending on success.
+-- This internally calls AceAddon:DisableAddon(), thus dispatching a OnDisable callback
+-- and disabling all modules of the addon.\\
+-- :Disable() also sets the internal `enableState` variable to false
+-- @name //addon//:Disable
+-- @paramsig
+-- @usage
+-- -- Disable MyAddon
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyAddon:Disable()
+function Disable(self)
+ self:SetEnabledState(false)
+ return AceAddon:DisableAddon(self)
+end
+
+--- Enables the Module, if possible, return true or false depending on success.
+-- Short-hand function that retrieves the module via `:GetModule` and calls `:Enable` on the module object.
+-- @name //addon//:EnableModule
+-- @paramsig name
+-- @usage
+-- -- Enable MyModule using :GetModule
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyModule = MyAddon:GetModule("MyModule")
+-- MyModule:Enable()
+--
+-- -- Enable MyModule using the short-hand
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyAddon:EnableModule("MyModule")
+function EnableModule(self, name)
+ local module = self:GetModule( name )
+ return module:Enable()
+end
+
+--- Disables the Module, if possible, return true or false depending on success.
+-- Short-hand function that retrieves the module via `:GetModule` and calls `:Disable` on the module object.
+-- @name //addon//:DisableModule
+-- @paramsig name
+-- @usage
+-- -- Disable MyModule using :GetModule
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyModule = MyAddon:GetModule("MyModule")
+-- MyModule:Disable()
+--
+-- -- Disable MyModule using the short-hand
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyAddon:DisableModule("MyModule")
+function DisableModule(self, name)
+ local module = self:GetModule( name )
+ return module:Disable()
+end
+
+--- Set the default libraries to be mixed into all modules created by this object.
+-- Note that you can only change the default module libraries before any module is created.
+-- @name //addon//:SetDefaultModuleLibraries
+-- @paramsig lib[, lib, ...]
+-- @param lib List of libraries to embed into the addon
+-- @usage
+-- -- Create the addon object
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
+-- -- Configure default libraries for modules (all modules need AceEvent-3.0)
+-- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0")
+-- -- Create a module
+-- MyModule = MyAddon:NewModule("MyModule")
+function SetDefaultModuleLibraries(self, ...)
+ if next(self.modules) then
+ error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2)
+ end
+ self.defaultModuleLibraries = {...}
+end
+
+--- Set the default state in which new modules are being created.
+-- Note that you can only change the default state before any module is created.
+-- @name //addon//:SetDefaultModuleState
+-- @paramsig state
+-- @param state Default state for new modules, true for enabled, false for disabled
+-- @usage
+-- -- Create the addon object
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
+-- -- Set the default state to "disabled"
+-- MyAddon:SetDefaultModuleState(false)
+-- -- Create a module and explicilty enable it
+-- MyModule = MyAddon:NewModule("MyModule")
+-- MyModule:Enable()
+function SetDefaultModuleState(self, state)
+ if next(self.modules) then
+ error("Usage: SetDefaultModuleState(state): cannot change the module defaults after a module has been registered.", 2)
+ end
+ self.defaultModuleState = state
+end
+
+--- Set the default prototype to use for new modules on creation.
+-- Note that you can only change the default prototype before any module is created.
+-- @name //addon//:SetDefaultModulePrototype
+-- @paramsig prototype
+-- @param prototype Default prototype for the new modules (table)
+-- @usage
+-- -- Define a prototype
+-- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
+-- -- Set the default prototype
+-- MyAddon:SetDefaultModulePrototype(prototype)
+-- -- Create a module and explicitly Enable it
+-- MyModule = MyAddon:NewModule("MyModule")
+-- MyModule:Enable()
+-- -- should print "OnEnable called!" now
+-- @see NewModule
+function SetDefaultModulePrototype(self, prototype)
+ if next(self.modules) then
+ error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2)
+ end
+ if type(prototype) ~= "table" then
+ error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2)
+ end
+ self.defaultModulePrototype = prototype
+end
+
+--- Set the state of an addon or module
+-- This should only be called before any enabling actually happend, e.g. in/before OnInitialize.
+-- @name //addon//:SetEnabledState
+-- @paramsig state
+-- @param state the state of an addon or module (enabled=true, disabled=false)
+function SetEnabledState(self, state)
+ self.enabledState = state
+end
+
+
+--- Return an iterator of all modules associated to the addon.
+-- @name //addon//:IterateModules
+-- @paramsig
+-- @usage
+-- -- Enable all modules
+-- for name, module in MyAddon:IterateModules() do
+-- module:Enable()
+-- end
+local function IterateModules(self) return pairs(self.modules) end
+
+-- Returns an iterator of all embeds in the addon
+-- @name //addon//:IterateEmbeds
+-- @paramsig
+local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) end
+
+--- Query the enabledState of an addon.
+-- @name //addon//:IsEnabled
+-- @paramsig
+-- @usage
+-- if MyAddon:IsEnabled() then
+-- MyAddon:Disable()
+-- end
+local function IsEnabled(self) return self.enabledState end
+local mixins = {
+ NewModule = NewModule,
+ GetModule = GetModule,
+ Enable = Enable,
+ Disable = Disable,
+ EnableModule = EnableModule,
+ DisableModule = DisableModule,
+ IsEnabled = IsEnabled,
+ SetDefaultModuleLibraries = SetDefaultModuleLibraries,
+ SetDefaultModuleState = SetDefaultModuleState,
+ SetDefaultModulePrototype = SetDefaultModulePrototype,
+ SetEnabledState = SetEnabledState,
+ IterateModules = IterateModules,
+ IterateEmbeds = IterateEmbeds,
+ GetName = GetName,
+}
+local function IsModule(self) return false end
+local pmixins = {
+ defaultModuleState = true,
+ enabledState = true,
+ IsModule = IsModule,
+}
+-- Embed( target )
+-- target (object) - target object to embed aceaddon in
+--
+-- this is a local function specifically since it's meant to be only called internally
+function Embed(target, skipPMixins)
+ for k, v in pairs(mixins) do
+ target[k] = v
+ end
+ if not skipPMixins then
+ for k, v in pairs(pmixins) do
+ target[k] = target[k] or v
+ end
+ end
+end
+
+
+-- - Initialize the addon after creation.
+-- This function is only used internally during the ADDON_LOADED event
+-- It will call the **OnInitialize** function on the addon object (if present),
+-- and the **OnEmbedInitialize** function on all embeded libraries.
+--
+-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
+-- @param addon addon object to intialize
+function AceAddon:InitializeAddon(addon)
+ safecall(addon.OnInitialize, addon)
+
+ local embeds = self.embeds[addon]
+ for i = 1, #embeds do
+ local lib = LibStub:GetLibrary(embeds[i], true)
+ if lib then safecall(lib.OnEmbedInitialize, lib, addon) end
+ end
+
+ -- we don't call InitializeAddon on modules specifically, this is handled
+ -- from the event handler and only done _once_
+end
+
+-- - Enable the addon after creation.
+-- Note: This function is only used internally during the PLAYER_LOGIN event, or during ADDON_LOADED,
+-- if IsLoggedIn() already returns true at that point, e.g. for LoD Addons.
+-- It will call the **OnEnable** function on the addon object (if present),
+-- and the **OnEmbedEnable** function on all embeded libraries.\\
+-- This function does not toggle the enable state of the addon itself, and will return early if the addon is disabled.
+--
+-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
+-- Use :Enable on the addon itself instead.
+-- @param addon addon object to enable
+function AceAddon:EnableAddon(addon)
+ if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
+ if self.statuses[addon.name] or not addon.enabledState then return false end
+
+ -- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable.
+ self.statuses[addon.name] = true
+
+ safecall(addon.OnEnable, addon)
+
+ -- make sure we're still enabled before continueing
+ if self.statuses[addon.name] then
+ local embeds = self.embeds[addon]
+ for i = 1, #embeds do
+ local lib = LibStub:GetLibrary(embeds[i], true)
+ if lib then safecall(lib.OnEmbedEnable, lib, addon) end
+ end
+
+ -- enable possible modules.
+ local modules = addon.orderedModules
+ for i = 1, #modules do
+ self:EnableAddon(modules[i])
+ end
+ end
+ return self.statuses[addon.name] -- return true if we're disabled
+end
+
+-- - Disable the addon
+-- Note: This function is only used internally.
+-- It will call the **OnDisable** function on the addon object (if present),
+-- and the **OnEmbedDisable** function on all embeded libraries.\\
+-- This function does not toggle the enable state of the addon itself, and will return early if the addon is still enabled.
+--
+-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
+-- Use :Disable on the addon itself instead.
+-- @param addon addon object to enable
+function AceAddon:DisableAddon(addon)
+ if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
+ if not self.statuses[addon.name] then return false end
+
+ -- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable.
+ self.statuses[addon.name] = false
+
+ safecall( addon.OnDisable, addon )
+
+ -- make sure we're still disabling...
+ if not self.statuses[addon.name] then
+ local embeds = self.embeds[addon]
+ for i = 1, #embeds do
+ local lib = LibStub:GetLibrary(embeds[i], true)
+ if lib then safecall(lib.OnEmbedDisable, lib, addon) end
+ end
+ -- disable possible modules.
+ local modules = addon.orderedModules
+ for i = 1, #modules do
+ self:DisableAddon(modules[i])
+ end
+ end
+
+ return not self.statuses[addon.name] -- return true if we're disabled
+end
+
+--- Get an iterator over all registered addons.
+-- @usage
+-- -- Print a list of all installed AceAddon's
+-- for name, addon in AceAddon:IterateAddons() do
+-- print("Addon: " .. name)
+-- end
+function AceAddon:IterateAddons() return pairs(self.addons) end
+
+--- Get an iterator over the internal status registry.
+-- @usage
+-- -- Print a list of all enabled addons
+-- for name, status in AceAddon:IterateAddonStatus() do
+-- if status then
+-- print("EnabledAddon: " .. name)
+-- end
+-- end
+function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
+
+-- Following Iterators are deprecated, and their addon specific versions should be used
+-- e.g. addon:IterateEmbeds() instead of :IterateEmbedsOnAddon(addon)
+function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
+function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
+
+-- Event Handling
+local function onEvent(this, event, arg1)
+ -- 2011-08-17 nevcairiel - ignore the load event of Blizzard_DebugTools, so a potential startup error isn't swallowed up
+ if (event == "ADDON_LOADED" and arg1 ~= "Blizzard_DebugTools") or event == "PLAYER_LOGIN" then
+ -- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration
+ while(#AceAddon.initializequeue > 0) do
+ local addon = tremove(AceAddon.initializequeue, 1)
+ -- this might be an issue with recursion - TODO: validate
+ if event == "ADDON_LOADED" then addon.baseName = arg1 end
+ AceAddon:InitializeAddon(addon)
+ tinsert(AceAddon.enablequeue, addon)
+ end
+
+ if IsLoggedIn() then
+ while(#AceAddon.enablequeue > 0) do
+ local addon = tremove(AceAddon.enablequeue, 1)
+ AceAddon:EnableAddon(addon)
+ end
+ end
+ end
+end
+
+AceAddon.frame:RegisterEvent("ADDON_LOADED")
+AceAddon.frame:RegisterEvent("PLAYER_LOGIN")
+AceAddon.frame:SetScript("OnEvent", onEvent)
+
+-- upgrade embeded
+for name, addon in pairs(AceAddon.addons) do
+ Embed(addon, true)
+end
+
+-- 2010-10-27 nevcairiel - add new "orderedModules" table
+if oldminor and oldminor < 10 then
+ for name, addon in pairs(AceAddon.addons) do
+ addon.orderedModules = {}
+ for module_name, module in pairs(addon.modules) do
+ tinsert(addon.orderedModules, module)
+ end
+ end
+end
diff --git a/ElvUI/Libraries/Ace3/AceAddon-3.0/AceAddon-3.0.xml b/ElvUI/Libraries/Ace3/AceAddon-3.0/AceAddon-3.0.xml
new file mode 100644
index 0000000..e6ad639
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceAddon-3.0/AceAddon-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/Ace3/AceComm-3.0/AceComm-3.0.lua b/ElvUI/Libraries/Ace3/AceComm-3.0/AceComm-3.0.lua
new file mode 100644
index 0000000..00e713b
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceComm-3.0/AceComm-3.0.lua
@@ -0,0 +1,308 @@
+--- **AceComm-3.0** allows you to send messages of unlimited length over the addon comm channels.
+-- It'll automatically split the messages into multiple parts and rebuild them on the receiving end.\\
+-- **ChatThrottleLib** is of course being used to avoid being disconnected by the server.
+--
+-- **AceComm-3.0** can be embeded into your addon, either explicitly by calling AceComm:Embed(MyAddon) or by
+-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
+-- and can be accessed directly, without having to explicitly call AceComm itself.\\
+-- It is recommended to embed AceComm, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceComm.
+-- @class file
+-- @name AceComm-3.0
+-- @release $Id$
+
+--[[ AceComm-3.0
+
+TODO: Time out old data rotting around from dead senders? Not a HUGE deal since the number of possible sender names is somewhat limited.
+
+]]
+
+local CallbackHandler = LibStub("CallbackHandler-1.0")
+local CTL = assert(ChatThrottleLib, "AceComm-3.0 requires ChatThrottleLib")
+
+local MAJOR, MINOR = "AceComm-3.0", 12
+local AceComm,oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceComm then return end
+
+-- Lua APIs
+local type, next, pairs, tostring = type, next, pairs, tostring
+local strsub, strfind = string.sub, string.find
+local tinsert, tconcat = table.insert, table.concat
+local error, assert = error, assert
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: LibStub, DEFAULT_CHAT_FRAME, geterrorhandler
+
+AceComm.embeds = AceComm.embeds or {}
+
+-- for my sanity and yours, let's give the message type bytes some names
+local MSG_MULTI_FIRST = "\001"
+local MSG_MULTI_NEXT = "\002"
+local MSG_MULTI_LAST = "\003"
+
+AceComm.multipart_origprefixes = AceComm.multipart_origprefixes or {} -- e.g. "Prefix\001"="Prefix", "Prefix\002"="Prefix"
+AceComm.multipart_reassemblers = AceComm.multipart_reassemblers or {} -- e.g. "Prefix\001"="OnReceiveMultipartFirst"
+
+-- the multipart message spool: indexed by a combination of sender+distribution+
+AceComm.multipart_spool = AceComm.multipart_spool or {}
+
+--- Register for Addon Traffic on a specified prefix
+-- @param prefix A printable character (\032-\255) classification of the message (typically AddonName or AddonNameEvent)
+-- @param method Callback to call on message reception: Function reference, or method name (string) to call on self. Defaults to "OnCommReceived"
+function AceComm:RegisterComm(prefix, method)
+ if method == nil then
+ method = "OnCommReceived"
+ end
+
+ return AceComm._RegisterComm(self, prefix, method) -- created by CallbackHandler
+end
+
+local warnedPrefix=false
+
+--- Send a message over the Addon Channel
+-- @param prefix A printable character (\032-\255) classification of the message (typically AddonName or AddonNameEvent)
+-- @param text Data to send, nils (\000) not allowed. Any length.
+-- @param distribution Addon channel, e.g. "RAID", "GUILD", etc; see SendAddonMessage API
+-- @param target Destination for some distributions; see SendAddonMessage API
+-- @param prio OPTIONAL: ChatThrottleLib priority, "BULK", "NORMAL" or "ALERT". Defaults to "NORMAL".
+-- @param callbackFn OPTIONAL: callback function to be called as each chunk is sent. receives 3 args: the user supplied arg (see next), the number of bytes sent so far, and the number of bytes total to send.
+-- @param callbackArg: OPTIONAL: first arg to the callback function. nil will be passed if not specified.
+function AceComm:SendCommMessage(prefix, text, distribution, target, prio, callbackFn, callbackArg)
+ prio = prio or "NORMAL" -- pasta's reference implementation had different prio for singlepart and multipart, but that's a very bad idea since that can easily lead to out-of-sequence delivery!
+ if not( type(prefix)=="string" and
+ type(text)=="string" and
+ type(distribution)=="string" and
+ (target==nil or type(target)=="string" or type(target)=="number") and
+ (prio=="BULK" or prio=="NORMAL" or prio=="ALERT")
+ ) then
+ error('Usage: SendCommMessage(addon, "prefix", "text", "distribution"[, "target"[, "prio"[, callbackFn, callbackarg]]])', 2)
+ end
+
+ if strfind(prefix, "[\001-\009]") then
+ if strfind(prefix, "[\001-\003]") then
+ error("SendCommMessage: Characters \\001--\\003 in prefix are reserved for AceComm metadata", 2)
+ elseif not warnedPrefix then
+ -- I have some ideas about future extensions that require more control characters /mikk, 20090808
+ geterrorhandler()("SendCommMessage: Heads-up developers: Characters \\004--\\009 in prefix are reserved for AceComm future extension")
+ warnedPrefix = true
+ end
+ end
+
+
+ local textlen = #text
+ local maxtextlen = 254 - #prefix -- 254 is the max length of prefix + text that can be sent in one message
+ local queueName = prefix..distribution..(target or "")
+
+ local ctlCallback = nil
+ if callbackFn then
+ ctlCallback = function(sent)
+ return callbackFn(callbackArg, sent, textlen)
+ end
+ end
+
+ if textlen <= maxtextlen then
+ -- fits all in one message
+ CTL:SendAddonMessage(prio, prefix, text, distribution, target, queueName, ctlCallback, textlen)
+ else
+ maxtextlen = maxtextlen - 1 -- 1 extra byte for part indicator in prefix
+
+ -- first part
+ local chunk = strsub(text, 1, maxtextlen)
+ CTL:SendAddonMessage(prio, prefix..MSG_MULTI_FIRST, chunk, distribution, target, queueName, ctlCallback, maxtextlen)
+
+ -- continuation
+ local pos = 1+maxtextlen
+ local prefix2 = prefix..MSG_MULTI_NEXT
+
+ while pos+maxtextlen <= textlen do
+ chunk = strsub(text, pos, pos+maxtextlen-1)
+ CTL:SendAddonMessage(prio, prefix2, chunk, distribution, target, queueName, ctlCallback, pos+maxtextlen-1)
+ pos = pos + maxtextlen
+ end
+
+ -- final part
+ chunk = strsub(text, pos)
+ CTL:SendAddonMessage(prio, prefix..MSG_MULTI_LAST, chunk, distribution, target, queueName, ctlCallback, textlen)
+ end
+end
+
+
+----------------------------------------
+-- Message receiving
+----------------------------------------
+
+do
+ local compost = setmetatable({}, {__mode = "k"})
+ local function new()
+ local t = next(compost)
+ if t then
+ compost[t]=nil
+ for i=#t,3,-1 do -- faster than pairs loop. don't even nil out 1/2 since they'll be overwritten
+ t[i]=nil
+ end
+ return t
+ end
+
+ return {}
+ end
+
+ local function lostdatawarning(prefix,sender,where)
+ DEFAULT_CHAT_FRAME:AddMessage(MAJOR..": Warning: lost network data regarding '"..tostring(prefix).."' from '"..tostring(sender).."' (in "..where..")")
+ end
+
+ function AceComm:OnReceiveMultipartFirst(prefix, message, distribution, sender)
+ local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender
+ local spool = AceComm.multipart_spool
+
+ --[[
+ if spool[key] then
+ lostdatawarning(prefix,sender,"First")
+ -- continue and overwrite
+ end
+ --]]
+
+ spool[key] = message -- plain string for now
+ end
+
+ function AceComm:OnReceiveMultipartNext(prefix, message, distribution, sender)
+ local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender
+ local spool = AceComm.multipart_spool
+ local olddata = spool[key]
+
+ if not olddata then
+ --lostdatawarning(prefix,sender,"Next")
+ return
+ end
+
+ if type(olddata)~="table" then
+ -- ... but what we have is not a table. So make it one. (Pull a composted one if available)
+ local t = new()
+ t[1] = olddata -- add old data as first string
+ t[2] = message -- and new message as second string
+ spool[key] = t -- and put the table in the spool instead of the old string
+ else
+ tinsert(olddata, message)
+ end
+ end
+
+ function AceComm:OnReceiveMultipartLast(prefix, message, distribution, sender)
+ local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender
+ local spool = AceComm.multipart_spool
+ local olddata = spool[key]
+
+ if not olddata then
+ --lostdatawarning(prefix,sender,"End")
+ return
+ end
+
+ spool[key] = nil
+
+ if type(olddata) == "table" then
+ -- if we've received a "next", the spooled data will be a table for rapid & garbage-free tconcat
+ tinsert(olddata, message)
+ AceComm.callbacks:Fire(prefix, tconcat(olddata, ""), distribution, sender)
+ compost[olddata] = true
+ else
+ -- if we've only received a "first", the spooled data will still only be a string
+ AceComm.callbacks:Fire(prefix, olddata..message, distribution, sender)
+ end
+ end
+end
+
+
+
+
+
+
+----------------------------------------
+-- Embed CallbackHandler
+----------------------------------------
+
+if not AceComm.callbacks then
+ -- ensure that 'prefix to watch' table is consistent with registered
+ -- callbacks
+ AceComm.__prefixes = {}
+
+ AceComm.callbacks = CallbackHandler:New(AceComm,
+ "_RegisterComm",
+ "UnregisterComm",
+ "UnregisterAllComm")
+end
+
+function AceComm.callbacks:OnUsed(target, prefix)
+ AceComm.multipart_origprefixes[prefix..MSG_MULTI_FIRST] = prefix
+ AceComm.multipart_reassemblers[prefix..MSG_MULTI_FIRST] = "OnReceiveMultipartFirst"
+
+ AceComm.multipart_origprefixes[prefix..MSG_MULTI_NEXT] = prefix
+ AceComm.multipart_reassemblers[prefix..MSG_MULTI_NEXT] = "OnReceiveMultipartNext"
+
+ AceComm.multipart_origprefixes[prefix..MSG_MULTI_LAST] = prefix
+ AceComm.multipart_reassemblers[prefix..MSG_MULTI_LAST] = "OnReceiveMultipartLast"
+end
+
+function AceComm.callbacks:OnUnused(target, prefix)
+ AceComm.multipart_origprefixes[prefix..MSG_MULTI_FIRST] = nil
+ AceComm.multipart_reassemblers[prefix..MSG_MULTI_FIRST] = nil
+
+ AceComm.multipart_origprefixes[prefix..MSG_MULTI_NEXT] = nil
+ AceComm.multipart_reassemblers[prefix..MSG_MULTI_NEXT] = nil
+
+ AceComm.multipart_origprefixes[prefix..MSG_MULTI_LAST] = nil
+ AceComm.multipart_reassemblers[prefix..MSG_MULTI_LAST] = nil
+end
+
+local function OnEvent(this, event, ...)
+ if event == "CHAT_MSG_ADDON" then
+ local prefix,message,distribution,sender = ...
+ local reassemblername = AceComm.multipart_reassemblers[prefix]
+ if reassemblername then
+ -- multipart: reassemble
+ local aceCommReassemblerFunc = AceComm[reassemblername]
+ local origprefix = AceComm.multipart_origprefixes[prefix]
+ aceCommReassemblerFunc(AceComm, origprefix, message, distribution, sender)
+ else
+ -- single part: fire it off immediately and let CallbackHandler decide if it's registered or not
+ AceComm.callbacks:Fire(prefix, message, distribution, sender)
+ end
+ else
+ assert(false, "Received "..tostring(event).." event?!")
+ end
+end
+
+AceComm.frame = AceComm.frame or CreateFrame("Frame", "AceComm30Frame")
+AceComm.frame:SetScript("OnEvent", OnEvent)
+AceComm.frame:UnregisterAllEvents()
+AceComm.frame:RegisterEvent("CHAT_MSG_ADDON")
+
+
+----------------------------------------
+-- Base library stuff
+----------------------------------------
+
+local mixins = {
+ "RegisterComm",
+ "UnregisterComm",
+ "UnregisterAllComm",
+ "SendCommMessage",
+}
+
+-- Embeds AceComm-3.0 into the target object making the functions from the mixins list available on target:..
+-- @param target target object to embed AceComm-3.0 in
+function AceComm:Embed(target)
+ for k, v in pairs(mixins) do
+ target[v] = self[v]
+ end
+ self.embeds[target] = true
+ return target
+end
+
+function AceComm:OnEmbedDisable(target)
+ target:UnregisterAllComm()
+end
+
+-- Update embeds
+for target, v in pairs(AceComm.embeds) do
+ AceComm:Embed(target)
+end
diff --git a/ElvUI/Libraries/Ace3/AceComm-3.0/AceComm-3.0.xml b/ElvUI/Libraries/Ace3/AceComm-3.0/AceComm-3.0.xml
new file mode 100644
index 0000000..09e8d87
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceComm-3.0/AceComm-3.0.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/Ace3/AceComm-3.0/ChatThrottleLib.lua b/ElvUI/Libraries/Ace3/AceComm-3.0/ChatThrottleLib.lua
new file mode 100644
index 0000000..d502802
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceComm-3.0/ChatThrottleLib.lua
@@ -0,0 +1,517 @@
+--
+-- ChatThrottleLib by Mikk
+--
+-- Manages AddOn chat output to keep player from getting kicked off.
+--
+-- ChatThrottleLib:SendChatMessage/:SendAddonMessage functions that accept
+-- a Priority ("BULK", "NORMAL", "ALERT") as well as prefix for SendChatMessage.
+--
+-- Priorities get an equal share of available bandwidth when fully loaded.
+-- Communication channels are separated on extension+chattype+destination and
+-- get round-robinned. (Destination only matters for whispers and channels,
+-- obviously)
+--
+-- Will install hooks for SendChatMessage and SendAddonMessage to measure
+-- bandwidth bypassing the library and use less bandwidth itself.
+--
+--
+-- Fully embeddable library. Just copy this file into your addon directory,
+-- add it to the .toc, and it's done.
+--
+-- Can run as a standalone addon also, but, really, just embed it! :-)
+--
+-- LICENSE: ChatThrottleLib is released into the Public Domain
+--
+
+local CTL_VERSION = 24
+
+local _G = _G
+
+if _G.ChatThrottleLib then
+ if _G.ChatThrottleLib.version >= CTL_VERSION then
+ -- There's already a newer (or same) version loaded. Buh-bye.
+ return
+ elseif not _G.ChatThrottleLib.securelyHooked then
+ print("ChatThrottleLib: Warning: There's an ANCIENT ChatThrottleLib.lua (pre-wow 2.0, =v16) in it!")
+ -- ATTEMPT to unhook; this'll behave badly if someone else has hooked...
+ -- ... and if someone has securehooked, they can kiss that goodbye too... >.<
+ _G.SendChatMessage = _G.ChatThrottleLib.ORIG_SendChatMessage
+ if _G.ChatThrottleLib.ORIG_SendAddonMessage then
+ _G.SendAddonMessage = _G.ChatThrottleLib.ORIG_SendAddonMessage
+ end
+ end
+ _G.ChatThrottleLib.ORIG_SendChatMessage = nil
+ _G.ChatThrottleLib.ORIG_SendAddonMessage = nil
+end
+
+if not _G.ChatThrottleLib then
+ _G.ChatThrottleLib = {}
+end
+
+ChatThrottleLib = _G.ChatThrottleLib -- in case some addon does "local ChatThrottleLib" above us and we're copypasted (AceComm-2, sigh)
+local ChatThrottleLib = _G.ChatThrottleLib
+
+ChatThrottleLib.version = CTL_VERSION
+
+
+
+------------------ TWEAKABLES -----------------
+
+ChatThrottleLib.MAX_CPS = 800 -- 2000 seems to be safe if NOTHING ELSE is happening. let's call it 800.
+ChatThrottleLib.MSG_OVERHEAD = 40 -- Guesstimate overhead for sending a message; source+dest+chattype+protocolstuff
+
+ChatThrottleLib.BURST = 4000 -- WoW's server buffer seems to be about 32KB. 8KB should be safe, but seen disconnects on _some_ servers. Using 4KB now.
+
+ChatThrottleLib.MIN_FPS = 20 -- Reduce output CPS to half (and don't burst) if FPS drops below this value
+
+
+local setmetatable = setmetatable
+local table_remove = table.remove
+local tostring = tostring
+local GetTime = GetTime
+local math_min = math.min
+local math_max = math.max
+local next = next
+local strlen = string.len
+local GetFramerate = GetFramerate
+local strlower = string.lower
+local unpack,type,pairs,wipe = unpack,type,pairs,wipe
+local UnitInRaid,GetNumPartyMembers = UnitInRaid,GetNumPartyMembers
+
+
+-----------------------------------------------------------------------
+-- Double-linked ring implementation
+
+local Ring = {}
+local RingMeta = { __index = Ring }
+
+function Ring:New()
+ local ret = {}
+ setmetatable(ret, RingMeta)
+ return ret
+end
+
+function Ring:Add(obj) -- Append at the "far end" of the ring (aka just before the current position)
+ if self.pos then
+ obj.prev = self.pos.prev
+ obj.prev.next = obj
+ obj.next = self.pos
+ obj.next.prev = obj
+ else
+ obj.next = obj
+ obj.prev = obj
+ self.pos = obj
+ end
+end
+
+function Ring:Remove(obj)
+ obj.next.prev = obj.prev
+ obj.prev.next = obj.next
+ if self.pos == obj then
+ self.pos = obj.next
+ if self.pos == obj then
+ self.pos = nil
+ end
+ end
+end
+
+
+
+-----------------------------------------------------------------------
+-- Recycling bin for pipes
+-- A pipe is a plain integer-indexed queue of messages
+-- Pipes normally live in Rings of pipes (3 rings total, one per priority)
+
+ChatThrottleLib.PipeBin = nil -- pre-v19, drastically different
+local PipeBin = setmetatable({}, {__mode="k"})
+
+local function DelPipe(pipe)
+ PipeBin[pipe] = true
+end
+
+local function NewPipe()
+ local pipe = next(PipeBin)
+ if pipe then
+ wipe(pipe)
+ PipeBin[pipe] = nil
+ return pipe
+ end
+ return {}
+end
+
+
+
+
+-----------------------------------------------------------------------
+-- Recycling bin for messages
+
+ChatThrottleLib.MsgBin = nil -- pre-v19, drastically different
+local MsgBin = setmetatable({}, {__mode="k"})
+
+local function DelMsg(msg)
+ msg[1] = nil
+ -- there's more parameters, but they're very repetetive so the string pool doesn't suffer really, and it's faster to just not delete them.
+ MsgBin[msg] = true
+end
+
+local function NewMsg()
+ local msg = next(MsgBin)
+ if msg then
+ MsgBin[msg] = nil
+ return msg
+ end
+ return {}
+end
+
+
+-----------------------------------------------------------------------
+-- ChatThrottleLib:Init
+-- Initialize queues, set up frame for OnUpdate, etc
+
+
+function ChatThrottleLib:Init()
+
+ -- Set up queues
+ if not self.Prio then
+ self.Prio = {}
+ self.Prio["ALERT"] = { ByName = {}, Ring = Ring:New(), avail = 0 }
+ self.Prio["NORMAL"] = { ByName = {}, Ring = Ring:New(), avail = 0 }
+ self.Prio["BULK"] = { ByName = {}, Ring = Ring:New(), avail = 0 }
+ end
+
+ -- v4: total send counters per priority
+ for _, Prio in pairs(self.Prio) do
+ Prio.nTotalSent = Prio.nTotalSent or 0
+ end
+
+ if not self.avail then
+ self.avail = 0 -- v5
+ end
+ if not self.nTotalSent then
+ self.nTotalSent = 0 -- v5
+ end
+
+
+ -- Set up a frame to get OnUpdate events
+ if not self.Frame then
+ self.Frame = CreateFrame("Frame")
+ self.Frame:Hide()
+ end
+ self.Frame:SetScript("OnUpdate", self.OnUpdate)
+ self.Frame:SetScript("OnEvent", self.OnEvent) -- v11: Monitor P_E_W so we can throttle hard for a few seconds
+ self.Frame:RegisterEvent("PLAYER_ENTERING_WORLD")
+ self.OnUpdateDelay = 0
+ self.LastAvailUpdate = GetTime()
+ self.HardThrottlingBeginTime = GetTime() -- v11: Throttle hard for a few seconds after startup
+
+ -- Hook SendChatMessage and SendAddonMessage so we can measure unpiped traffic and avoid overloads (v7)
+ if not self.securelyHooked then
+ -- Use secure hooks as of v16. Old regular hook support yanked out in v21.
+ self.securelyHooked = true
+ --SendChatMessage
+ hooksecurefunc("SendChatMessage", function(...)
+ return ChatThrottleLib.Hook_SendChatMessage(...)
+ end)
+ --SendAddonMessage
+ hooksecurefunc("SendAddonMessage", function(...)
+ return ChatThrottleLib.Hook_SendAddonMessage(...)
+ end)
+ end
+ self.nBypass = 0
+end
+
+
+-----------------------------------------------------------------------
+-- ChatThrottleLib.Hook_SendChatMessage / .Hook_SendAddonMessage
+
+local bMyTraffic = false
+
+function ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destination, ...)
+ if bMyTraffic then
+ return
+ end
+ local self = ChatThrottleLib
+ local size = strlen(tostring(text or "")) + strlen(tostring(destination or "")) + self.MSG_OVERHEAD
+ self.avail = self.avail - size
+ self.nBypass = self.nBypass + size -- just a statistic
+end
+function ChatThrottleLib.Hook_SendAddonMessage(prefix, text, chattype, destination, ...)
+ if bMyTraffic then
+ return
+ end
+ local self = ChatThrottleLib
+ local size = tostring(text or ""):len() + tostring(prefix or ""):len();
+ size = size + tostring(destination or ""):len() + self.MSG_OVERHEAD
+ self.avail = self.avail - size
+ self.nBypass = self.nBypass + size -- just a statistic
+end
+
+
+
+-----------------------------------------------------------------------
+-- ChatThrottleLib:UpdateAvail
+-- Update self.avail with how much bandwidth is currently available
+
+function ChatThrottleLib:UpdateAvail()
+ local now = GetTime()
+ local MAX_CPS = self.MAX_CPS;
+ local newavail = MAX_CPS * (now - self.LastAvailUpdate)
+ local avail = self.avail
+
+ if now - self.HardThrottlingBeginTime < 5 then
+ -- First 5 seconds after startup/zoning: VERY hard clamping to avoid irritating the server rate limiter, it seems very cranky then
+ avail = math_min(avail + (newavail*0.1), MAX_CPS*0.5)
+ self.bChoking = true
+ elseif GetFramerate() < self.MIN_FPS then -- GetFramerate call takes ~0.002 secs
+ avail = math_min(MAX_CPS, avail + newavail*0.5)
+ self.bChoking = true -- just a statistic
+ else
+ avail = math_min(self.BURST, avail + newavail)
+ self.bChoking = false
+ end
+
+ avail = math_max(avail, 0-(MAX_CPS*2)) -- Can go negative when someone is eating bandwidth past the lib. but we refuse to stay silent for more than 2 seconds; if they can do it, we can.
+
+ self.avail = avail
+ self.LastAvailUpdate = now
+
+ return avail
+end
+
+
+-----------------------------------------------------------------------
+-- Despooling logic
+-- Reminder:
+-- - We have 3 Priorities, each containing a "Ring" construct ...
+-- - ... made up of N "Pipe"s (1 for each destination/pipename)
+-- - and each pipe contains messages
+
+function ChatThrottleLib:Despool(Prio)
+ local ring = Prio.Ring
+ while ring.pos and Prio.avail > ring.pos[1].nSize do
+ local msg = table_remove(ring.pos, 1)
+ if not ring.pos[1] then -- did we remove last msg in this pipe?
+ local pipe = Prio.Ring.pos
+ Prio.Ring:Remove(pipe)
+ Prio.ByName[pipe.name] = nil
+ DelPipe(pipe)
+ else
+ Prio.Ring.pos = Prio.Ring.pos.next
+ end
+ local didSend=false
+ local lowerDest = strlower(msg[3] or "")
+ if lowerDest == "raid" and not UnitInRaid("player") then
+ -- do nothing
+ elseif lowerDest == "party" and GetNumPartyMembers() == 0 then
+ -- do nothing
+ else
+ Prio.avail = Prio.avail - msg.nSize
+ bMyTraffic = true
+ msg.f(unpack(msg, 1, msg.n))
+ bMyTraffic = false
+ Prio.nTotalSent = Prio.nTotalSent + msg.nSize
+ DelMsg(msg)
+ didSend = true
+ end
+ -- notify caller of delivery (even if we didn't send it)
+ if msg.callbackFn then
+ msg.callbackFn (msg.callbackArg, didSend)
+ end
+ -- USER CALLBACK MAY ERROR
+ end
+end
+
+
+function ChatThrottleLib.OnEvent(this,event)
+ -- v11: We know that the rate limiter is touchy after login. Assume that it's touchy after zoning, too.
+ local self = ChatThrottleLib
+ if event == "PLAYER_ENTERING_WORLD" then
+ self.HardThrottlingBeginTime = GetTime() -- Throttle hard for a few seconds after zoning
+ self.avail = 0
+ end
+end
+
+
+function ChatThrottleLib.OnUpdate(this,delay)
+ local self = ChatThrottleLib
+
+ self.OnUpdateDelay = self.OnUpdateDelay + delay
+ if self.OnUpdateDelay < 0.08 then
+ return
+ end
+ self.OnUpdateDelay = 0
+
+ self:UpdateAvail()
+
+ if self.avail < 0 then
+ return -- argh. some bastard is spewing stuff past the lib. just bail early to save cpu.
+ end
+
+ -- See how many of our priorities have queued messages (we only have 3, don't worry about the loop)
+ local n = 0
+ for prioname,Prio in pairs(self.Prio) do
+ if Prio.Ring.pos or Prio.avail < 0 then
+ n = n + 1
+ end
+ end
+
+ -- Anything queued still?
+ if n<1 then
+ -- Nope. Move spillover bandwidth to global availability gauge and clear self.bQueueing
+ for prioname, Prio in pairs(self.Prio) do
+ self.avail = self.avail + Prio.avail
+ Prio.avail = 0
+ end
+ self.bQueueing = false
+ self.Frame:Hide()
+ return
+ end
+
+ -- There's stuff queued. Hand out available bandwidth to priorities as needed and despool their queues
+ local avail = self.avail/n
+ self.avail = 0
+
+ for prioname, Prio in pairs(self.Prio) do
+ if Prio.Ring.pos or Prio.avail < 0 then
+ Prio.avail = Prio.avail + avail
+ if Prio.Ring.pos and Prio.avail > Prio.Ring.pos[1].nSize then
+ self:Despool(Prio)
+ -- Note: We might not get here if the user-supplied callback function errors out! Take care!
+ end
+ end
+ end
+
+end
+
+
+
+
+-----------------------------------------------------------------------
+-- Spooling logic
+
+function ChatThrottleLib:Enqueue(prioname, pipename, msg)
+ local Prio = self.Prio[prioname]
+ local pipe = Prio.ByName[pipename]
+ if not pipe then
+ self.Frame:Show()
+ pipe = NewPipe()
+ pipe.name = pipename
+ Prio.ByName[pipename] = pipe
+ Prio.Ring:Add(pipe)
+ end
+
+ pipe[#pipe + 1] = msg
+
+ self.bQueueing = true
+end
+
+function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, language, destination, queueName, callbackFn, callbackArg)
+ if not self or not prio or not prefix or not text or not self.Prio[prio] then
+ error('Usage: ChatThrottleLib:SendChatMessage("{BULK||NORMAL||ALERT}", "prefix", "text"[, "chattype"[, "language"[, "destination"]]]', 2)
+ end
+ if callbackFn and type(callbackFn)~="function" then
+ error('ChatThrottleLib:ChatMessage(): callbackFn: expected function, got '..type(callbackFn), 2)
+ end
+
+ local nSize = text:len()
+
+ if nSize>255 then
+ error("ChatThrottleLib:SendChatMessage(): message length cannot exceed 255 bytes", 2)
+ end
+
+ nSize = nSize + self.MSG_OVERHEAD
+
+ -- Check if there's room in the global available bandwidth gauge to send directly
+ if not self.bQueueing and nSize < self:UpdateAvail() then
+ self.avail = self.avail - nSize
+ bMyTraffic = true
+ _G.SendChatMessage(text, chattype, language, destination)
+ bMyTraffic = false
+ self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize
+ if callbackFn then
+ callbackFn (callbackArg, true)
+ end
+ -- USER CALLBACK MAY ERROR
+ return
+ end
+
+ -- Message needs to be queued
+ local msg = NewMsg()
+ msg.f = _G.SendChatMessage
+ msg[1] = text
+ msg[2] = chattype or "SAY"
+ msg[3] = language
+ msg[4] = destination
+ msg.n = 4
+ msg.nSize = nSize
+ msg.callbackFn = callbackFn
+ msg.callbackArg = callbackArg
+
+ self:Enqueue(prio, queueName or (prefix..(chattype or "SAY")..(destination or "")), msg)
+end
+
+
+function ChatThrottleLib:SendAddonMessage(prio, prefix, text, chattype, target, queueName, callbackFn, callbackArg)
+ if not self or not prio or not prefix or not text or not chattype or not self.Prio[prio] then
+ error('Usage: ChatThrottleLib:SendAddonMessage("{BULK||NORMAL||ALERT}", "prefix", "text", "chattype"[, "target"])', 2)
+ end
+ if callbackFn and type(callbackFn)~="function" then
+ error('ChatThrottleLib:SendAddonMessage(): callbackFn: expected function, got '..type(callbackFn), 2)
+ end
+
+ local nSize = prefix:len() + 1 + text:len();
+
+ if nSize>255 then
+ error("ChatThrottleLib:SendAddonMessage(): prefix + message length cannot exceed 254 bytes", 2)
+ end
+
+ nSize = nSize + self.MSG_OVERHEAD;
+
+ -- Check if there's room in the global available bandwidth gauge to send directly
+ if not self.bQueueing and nSize < self:UpdateAvail() then
+ self.avail = self.avail - nSize
+ bMyTraffic = true
+ _G.SendAddonMessage(prefix, text, chattype, target)
+ bMyTraffic = false
+ self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize
+ if callbackFn then
+ callbackFn (callbackArg, true)
+ end
+ -- USER CALLBACK MAY ERROR
+ return
+ end
+
+ -- Message needs to be queued
+ local msg = NewMsg()
+ msg.f = _G.SendAddonMessage
+ msg[1] = prefix
+ msg[2] = text
+ msg[3] = chattype
+ msg[4] = target
+ msg.n = (target~=nil) and 4 or 3;
+ msg.nSize = nSize
+ msg.callbackFn = callbackFn
+ msg.callbackArg = callbackArg
+
+ self:Enqueue(prio, queueName or (prefix..chattype..(target or "")), msg)
+end
+
+
+
+
+-----------------------------------------------------------------------
+-- Get the ball rolling!
+
+ChatThrottleLib:Init()
+
+--[[ WoWBench debugging snippet
+if(WOWB_VER) then
+ local function SayTimer()
+ print("SAY: "..GetTime().." "..arg1)
+ end
+ ChatThrottleLib.Frame:SetScript("OnEvent", SayTimer)
+ ChatThrottleLib.Frame:RegisterEvent("CHAT_MSG_SAY")
+end
+]]
+
+
diff --git a/ElvUI/Libraries/Ace3/AceConsole-3.0/AceConsole-3.0.lua b/ElvUI/Libraries/Ace3/AceConsole-3.0/AceConsole-3.0.lua
new file mode 100644
index 0000000..3f46b36
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceConsole-3.0/AceConsole-3.0.lua
@@ -0,0 +1,250 @@
+--- **AceConsole-3.0** provides registration facilities for slash commands.
+-- You can register slash commands to your custom functions and use the `GetArgs` function to parse them
+-- to your addons individual needs.
+--
+-- **AceConsole-3.0** can be embeded into your addon, either explicitly by calling AceConsole:Embed(MyAddon) or by
+-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
+-- and can be accessed directly, without having to explicitly call AceConsole itself.\\
+-- It is recommended to embed AceConsole, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceConsole.
+-- @class file
+-- @name AceConsole-3.0
+-- @release $Id$
+local MAJOR,MINOR = "AceConsole-3.0", 7
+
+local AceConsole, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceConsole then return end -- No upgrade needed
+
+AceConsole.embeds = AceConsole.embeds or {} -- table containing objects AceConsole is embedded in.
+AceConsole.commands = AceConsole.commands or {} -- table containing commands registered
+AceConsole.weakcommands = AceConsole.weakcommands or {} -- table containing self, command => func references for weak commands that don't persist through enable/disable
+
+-- Lua APIs
+local tconcat, tostring, select = table.concat, tostring, select
+local type, pairs, error = type, pairs, error
+local format, strfind, strsub = string.format, string.find, string.sub
+local max = math.max
+
+-- WoW APIs
+local _G = _G
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: DEFAULT_CHAT_FRAME, SlashCmdList, hash_SlashCmdList
+
+local tmp={}
+local function Print(self,frame,...)
+ local n=0
+ if self ~= AceConsole then
+ n=n+1
+ tmp[n] = "|cff33ff99"..tostring( self ).."|r:"
+ end
+ for i=1, select("#", ...) do
+ n=n+1
+ tmp[n] = tostring(select(i, ...))
+ end
+ frame:AddMessage( tconcat(tmp," ",1,n) )
+end
+
+--- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
+-- @paramsig [chatframe ,] ...
+-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
+-- @param ... List of any values to be printed
+function AceConsole:Print(...)
+ local frame = ...
+ if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
+ return Print(self, frame, select(2,...))
+ else
+ return Print(self, DEFAULT_CHAT_FRAME, ...)
+ end
+end
+
+
+--- Formatted (using format()) print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
+-- @paramsig [chatframe ,] "format"[, ...]
+-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
+-- @param format Format string - same syntax as standard Lua format()
+-- @param ... Arguments to the format string
+function AceConsole:Printf(...)
+ local frame = ...
+ if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
+ return Print(self, frame, format(select(2,...)))
+ else
+ return Print(self, DEFAULT_CHAT_FRAME, format(...))
+ end
+end
+
+
+
+
+--- Register a simple chat command
+-- @param command Chat command to be registered WITHOUT leading "/"
+-- @param func Function to call when the slash command is being used (funcref or methodname)
+-- @param persist if false, the command will be soft disabled/enabled when aceconsole is used as a mixin (default: true)
+function AceConsole:RegisterChatCommand( command, func, persist )
+ if type(command)~="string" then error([[Usage: AceConsole:RegisterChatCommand( "command", func[, persist ]): 'command' - expected a string]], 2) end
+
+ if persist==nil then persist=true end -- I'd rather have my addon's "/addon enable" around if the author screws up. Having some extra slash regged when it shouldnt be isn't as destructive. True is a better default. /Mikk
+
+ local name = "ACECONSOLE_"..command:upper()
+
+ if type( func ) == "string" then
+ SlashCmdList[name] = function(input, editBox)
+ self[func](self, input, editBox)
+ end
+ else
+ SlashCmdList[name] = func
+ end
+ _G["SLASH_"..name.."1"] = "/"..command:lower()
+ AceConsole.commands[command] = name
+ -- non-persisting commands are registered for enabling disabling
+ if not persist then
+ if not AceConsole.weakcommands[self] then AceConsole.weakcommands[self] = {} end
+ AceConsole.weakcommands[self][command] = func
+ end
+ return true
+end
+
+--- Unregister a chatcommand
+-- @param command Chat command to be unregistered WITHOUT leading "/"
+function AceConsole:UnregisterChatCommand( command )
+ local name = AceConsole.commands[command]
+ if name then
+ SlashCmdList[name] = nil
+ _G["SLASH_" .. name .. "1"] = nil
+ hash_SlashCmdList["/" .. command:upper()] = nil
+ AceConsole.commands[command] = nil
+ end
+end
+
+--- Get an iterator over all Chat Commands registered with AceConsole
+-- @return Iterator (pairs) over all commands
+function AceConsole:IterateChatCommands() return pairs(AceConsole.commands) end
+
+
+local function nils(n, ...)
+ if n>1 then
+ return nil, nils(n-1, ...)
+ elseif n==1 then
+ return nil, ...
+ else
+ return ...
+ end
+end
+
+
+--- Retreive one or more space-separated arguments from a string.
+-- Treats quoted strings and itemlinks as non-spaced.
+-- @param str The raw argument string
+-- @param numargs How many arguments to get (default 1)
+-- @param startpos Where in the string to start scanning (default 1)
+-- @return Returns arg1, arg2, ..., nextposition\\
+-- Missing arguments will be returned as nils. 'nextposition' is returned as 1e9 at the end of the string.
+function AceConsole:GetArgs(str, numargs, startpos)
+ numargs = numargs or 1
+ startpos = max(startpos or 1, 1)
+
+ local pos=startpos
+
+ -- find start of new arg
+ pos = strfind(str, "[^ ]", pos)
+ if not pos then -- whoops, end of string
+ return nils(numargs, 1e9)
+ end
+
+ if numargs<1 then
+ return pos
+ end
+
+ -- quoted or space separated? find out which pattern to use
+ local delim_or_pipe
+ local ch = strsub(str, pos, pos)
+ if ch=='"' then
+ pos = pos + 1
+ delim_or_pipe='([|"])'
+ elseif ch=="'" then
+ pos = pos + 1
+ delim_or_pipe="([|'])"
+ else
+ delim_or_pipe="([| ])"
+ end
+
+ startpos = pos
+
+ while true do
+ -- find delimiter or hyperlink
+ local ch,_
+ pos,_,ch = strfind(str, delim_or_pipe, pos)
+
+ if not pos then break end
+
+ if ch=="|" then
+ -- some kind of escape
+
+ if strsub(str,pos,pos+1)=="|H" then
+ -- It's a |H....|hhyper link!|h
+ pos=strfind(str, "|h", pos+2) -- first |h
+ if not pos then break end
+
+ pos=strfind(str, "|h", pos+2) -- second |h
+ if not pos then break end
+ elseif strsub(str,pos, pos+1) == "|T" then
+ -- It's a |T....|t texture
+ pos=strfind(str, "|t", pos+2)
+ if not pos then break end
+ end
+
+ pos=pos+2 -- skip past this escape (last |h if it was a hyperlink)
+
+ else
+ -- found delimiter, done with this arg
+ return strsub(str, startpos, pos-1), AceConsole:GetArgs(str, numargs-1, pos+1)
+ end
+
+ end
+
+ -- search aborted, we hit end of string. return it all as one argument. (yes, even if it's an unterminated quote or hyperlink)
+ return strsub(str, startpos), nils(numargs-1, 1e9)
+end
+
+
+--- embedding and embed handling
+
+local mixins = {
+ "Print",
+ "Printf",
+ "RegisterChatCommand",
+ "UnregisterChatCommand",
+ "GetArgs",
+}
+
+-- Embeds AceConsole into the target object making the functions from the mixins list available on target:..
+-- @param target target object to embed AceBucket in
+function AceConsole:Embed( target )
+ for k, v in pairs( mixins ) do
+ target[v] = self[v]
+ end
+ self.embeds[target] = true
+ return target
+end
+
+function AceConsole:OnEmbedEnable( target )
+ if AceConsole.weakcommands[target] then
+ for command, func in pairs( AceConsole.weakcommands[target] ) do
+ target:RegisterChatCommand( command, func, false, true ) -- nonpersisting and silent registry
+ end
+ end
+end
+
+function AceConsole:OnEmbedDisable( target )
+ if AceConsole.weakcommands[target] then
+ for command, func in pairs( AceConsole.weakcommands[target] ) do
+ target:UnregisterChatCommand( command ) -- TODO: this could potentially unregister a command from another application in case of command conflicts. Do we care?
+ end
+ end
+end
+
+for addon in pairs(AceConsole.embeds) do
+ AceConsole:Embed(addon)
+end
diff --git a/ElvUI/Libraries/Ace3/AceConsole-3.0/AceConsole-3.0.xml b/ElvUI/Libraries/Ace3/AceConsole-3.0/AceConsole-3.0.xml
new file mode 100644
index 0000000..be9f47c
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceConsole-3.0/AceConsole-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/Ace3/AceDB-3.0/AceDB-3.0.lua b/ElvUI/Libraries/Ace3/AceDB-3.0/AceDB-3.0.lua
new file mode 100644
index 0000000..ec431a6
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceDB-3.0/AceDB-3.0.lua
@@ -0,0 +1,741 @@
+--- **AceDB-3.0** manages the SavedVariables of your addon.
+-- It offers profile management, smart defaults and namespaces for modules.\\
+-- Data can be saved in different data-types, depending on its intended usage.
+-- The most common data-type is the `profile` type, which allows the user to choose
+-- the active profile, and manage the profiles of all of his characters.\\
+-- The following data types are available:
+-- * **char** Character-specific data. Every character has its own database.
+-- * **realm** Realm-specific data. All of the players characters on the same realm share this database.
+-- * **class** Class-specific data. All of the players characters of the same class share this database.
+-- * **race** Race-specific data. All of the players characters of the same race share this database.
+-- * **faction** Faction-specific data. All of the players characters of the same faction share this database.
+-- * **factionrealm** Faction and realm specific data. All of the players characters on the same realm and of the same faction share this database.
+-- * **locale** Locale specific data, based on the locale of the players game client.
+-- * **global** Global Data. All characters on the same account share this database.
+-- * **profile** Profile-specific data. All characters using the same profile share this database. The user can control which profile should be used.
+--
+-- Creating a new Database using the `:New` function will return a new DBObject. A database will inherit all functions
+-- of the DBObjectLib listed here. \\
+-- If you create a new namespaced child-database (`:RegisterNamespace`), you'll get a DBObject as well, but note
+-- that the child-databases cannot individually change their profile, and are linked to their parents profile - and because of that,
+-- the profile related APIs are not available. Only `:RegisterDefaults` and `:ResetProfile` are available on child-databases.
+--
+-- For more details on how to use AceDB-3.0, see the [[AceDB-3.0 Tutorial]].
+--
+-- You may also be interested in [[libdualspec-1-0|LibDualSpec-1.0]] to do profile switching automatically when switching specs.
+--
+-- @usage
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("DBExample")
+--
+-- -- declare defaults to be used in the DB
+-- local defaults = {
+-- profile = {
+-- setting = true,
+-- }
+-- }
+--
+-- function MyAddon:OnInitialize()
+-- -- Assuming the .toc says ## SavedVariables: MyAddonDB
+-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
+-- end
+-- @class file
+-- @name AceDB-3.0.lua
+-- @release $Id$
+local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 27
+local AceDB = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
+
+if not AceDB then return end -- No upgrade needed
+
+-- Lua APIs
+local type, pairs, next, error = type, pairs, next, error
+local setmetatable, rawset, rawget = setmetatable, rawset, rawget
+
+-- WoW APIs
+local _G = _G
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: LibStub
+
+AceDB.db_registry = AceDB.db_registry or {}
+AceDB.frame = AceDB.frame or CreateFrame("Frame")
+
+local CallbackHandler
+local CallbackDummy = { Fire = function() end }
+
+local DBObjectLib = {}
+
+--[[-------------------------------------------------------------------------
+ AceDB Utility Functions
+---------------------------------------------------------------------------]]
+
+-- Simple shallow copy for copying defaults
+local function copyTable(src, dest)
+ if type(dest) ~= "table" then dest = {} end
+ if type(src) == "table" then
+ for k,v in pairs(src) do
+ if type(v) == "table" then
+ -- try to index the key first so that the metatable creates the defaults, if set, and use that table
+ v = copyTable(v, dest[k])
+ end
+ dest[k] = v
+ end
+ end
+ return dest
+end
+
+-- Called to add defaults to a section of the database
+--
+-- When a ["*"] default section is indexed with a new key, a table is returned
+-- and set in the host table. These tables must be cleaned up by removeDefaults
+-- in order to ensure we don't write empty default tables.
+local function copyDefaults(dest, src)
+ -- this happens if some value in the SV overwrites our default value with a non-table
+ --if type(dest) ~= "table" then return end
+ for k, v in pairs(src) do
+ if k == "*" or k == "**" then
+ if type(v) == "table" then
+ -- This is a metatable used for table defaults
+ local mt = {
+ -- This handles the lookup and creation of new subtables
+ __index = function(t,k)
+ if k == nil then return nil end
+ local tbl = {}
+ copyDefaults(tbl, v)
+ rawset(t, k, tbl)
+ return tbl
+ end,
+ }
+ setmetatable(dest, mt)
+ -- handle already existing tables in the SV
+ for dk, dv in pairs(dest) do
+ if not rawget(src, dk) and type(dv) == "table" then
+ copyDefaults(dv, v)
+ end
+ end
+ else
+ -- Values are not tables, so this is just a simple return
+ local mt = {__index = function(t,k) return k~=nil and v or nil end}
+ setmetatable(dest, mt)
+ end
+ elseif type(v) == "table" then
+ if not rawget(dest, k) then rawset(dest, k, {}) end
+ if type(dest[k]) == "table" then
+ copyDefaults(dest[k], v)
+ if src['**'] then
+ copyDefaults(dest[k], src['**'])
+ end
+ end
+ else
+ if rawget(dest, k) == nil then
+ rawset(dest, k, v)
+ end
+ end
+ end
+end
+
+-- Called to remove all defaults in the default table from the database
+local function removeDefaults(db, defaults, blocker)
+ -- remove all metatables from the db, so we don't accidentally create new sub-tables through them
+ setmetatable(db, nil)
+ -- loop through the defaults and remove their content
+ for k,v in pairs(defaults) do
+ if k == "*" or k == "**" then
+ if type(v) == "table" then
+ -- Loop through all the actual k,v pairs and remove
+ for key, value in pairs(db) do
+ if type(value) == "table" then
+ -- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables
+ if defaults[key] == nil and (not blocker or blocker[key] == nil) then
+ removeDefaults(value, v)
+ -- if the table is empty afterwards, remove it
+ if next(value) == nil then
+ db[key] = nil
+ end
+ -- if it was specified, only strip ** content, but block values which were set in the key table
+ elseif k == "**" then
+ removeDefaults(value, v, defaults[key])
+ end
+ end
+ end
+ elseif k == "*" then
+ -- check for non-table default
+ for key, value in pairs(db) do
+ if defaults[key] == nil and v == value then
+ db[key] = nil
+ end
+ end
+ end
+ elseif type(v) == "table" and type(db[k]) == "table" then
+ -- if a blocker was set, dive into it, to allow multi-level defaults
+ removeDefaults(db[k], v, blocker and blocker[k])
+ if next(db[k]) == nil then
+ db[k] = nil
+ end
+ else
+ -- check if the current value matches the default, and that its not blocked by another defaults table
+ if db[k] == defaults[k] and (not blocker or blocker[k] == nil) then
+ db[k] = nil
+ end
+ end
+ end
+end
+
+-- This is called when a table section is first accessed, to set up the defaults
+local function initSection(db, section, svstore, key, defaults)
+ local sv = rawget(db, "sv")
+
+ local tableCreated
+ if not sv[svstore] then sv[svstore] = {} end
+ if not sv[svstore][key] then
+ sv[svstore][key] = {}
+ tableCreated = true
+ end
+
+ local tbl = sv[svstore][key]
+
+ if defaults then
+ copyDefaults(tbl, defaults)
+ end
+ rawset(db, section, tbl)
+
+ return tableCreated, tbl
+end
+
+-- Metatable to handle the dynamic creation of sections and copying of sections.
+local dbmt = {
+ __index = function(t, section)
+ local keys = rawget(t, "keys")
+ local key = keys[section]
+ if key then
+ local defaultTbl = rawget(t, "defaults")
+ local defaults = defaultTbl and defaultTbl[section]
+
+ if section == "profile" then
+ local new = initSection(t, section, "profiles", key, defaults)
+ if new then
+ -- Callback: OnNewProfile, database, newProfileKey
+ t.callbacks:Fire("OnNewProfile", t, key)
+ end
+ elseif section == "profiles" then
+ local sv = rawget(t, "sv")
+ if not sv.profiles then sv.profiles = {} end
+ rawset(t, "profiles", sv.profiles)
+ elseif section == "global" then
+ local sv = rawget(t, "sv")
+ if not sv.global then sv.global = {} end
+ if defaults then
+ copyDefaults(sv.global, defaults)
+ end
+ rawset(t, section, sv.global)
+ else
+ initSection(t, section, section, key, defaults)
+ end
+ end
+
+ return rawget(t, section)
+ end
+}
+
+local function validateDefaults(defaults, keyTbl, offset)
+ if not defaults then return end
+ offset = offset or 0
+ for k in pairs(defaults) do
+ if not keyTbl[k] or k == "profiles" then
+ error(("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype."):format(k), 3 + offset)
+ end
+ end
+end
+
+local preserve_keys = {
+ ["callbacks"] = true,
+ ["RegisterCallback"] = true,
+ ["UnregisterCallback"] = true,
+ ["UnregisterAllCallbacks"] = true,
+ ["children"] = true,
+}
+
+local realmKey = GetRealmName()
+local charKey = UnitName("player") .. " - " .. realmKey
+local _, classKey = UnitClass("player")
+local _, raceKey = UnitRace("player")
+local factionKey = UnitFactionGroup("player")
+local factionrealmKey = factionKey .. " - " .. realmKey
+local factionrealmregionKey = factionrealmKey .. " - " .. string.sub(GetCVar("realmList"), 1, 2):upper()
+local localeKey = GetLocale():lower()
+
+-- Actual database initialization function
+local function initdb(sv, defaults, defaultProfile, olddb, parent)
+ -- Generate the database keys for each section
+
+ -- map "true" to our "Default" profile
+ if defaultProfile == true then defaultProfile = "Default" end
+
+ local profileKey
+ if not parent then
+ -- Make a container for profile keys
+ if not sv.profileKeys then sv.profileKeys = {} end
+
+ -- Try to get the profile selected from the char db
+ profileKey = sv.profileKeys[charKey] or defaultProfile or charKey
+
+ -- save the selected profile for later
+ sv.profileKeys[charKey] = profileKey
+ else
+ -- Use the profile of the parents DB
+ profileKey = parent.keys.profile or defaultProfile or charKey
+
+ -- clear the profileKeys in the DB, namespaces don't need to store them
+ sv.profileKeys = nil
+ end
+
+ -- This table contains keys that enable the dynamic creation
+ -- of each section of the table. The 'global' and 'profiles'
+ -- have a key of true, since they are handled in a special case
+ local keyTbl= {
+ ["char"] = charKey,
+ ["realm"] = realmKey,
+ ["class"] = classKey,
+ ["race"] = raceKey,
+ ["faction"] = factionKey,
+ ["factionrealm"] = factionrealmKey,
+ ["factionrealmregion"] = factionrealmregionKey,
+ ["profile"] = profileKey,
+ ["locale"] = localeKey,
+ ["global"] = true,
+ ["profiles"] = true,
+ }
+
+ validateDefaults(defaults, keyTbl, 1)
+
+ -- This allows us to use this function to reset an entire database
+ -- Clear out the old database
+ if olddb then
+ for k,v in pairs(olddb) do if not preserve_keys[k] then olddb[k] = nil end end
+ end
+
+ -- Give this database the metatable so it initializes dynamically
+ local db = setmetatable(olddb or {}, dbmt)
+
+ if not rawget(db, "callbacks") then
+ -- try to load CallbackHandler-1.0 if it loaded after our library
+ if not CallbackHandler then CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0", true) end
+ db.callbacks = CallbackHandler and CallbackHandler:New(db) or CallbackDummy
+ end
+
+ -- Copy methods locally into the database object, to avoid hitting
+ -- the metatable when calling methods
+
+ if not parent then
+ for name, func in pairs(DBObjectLib) do
+ db[name] = func
+ end
+ else
+ -- hack this one in
+ db.RegisterDefaults = DBObjectLib.RegisterDefaults
+ db.ResetProfile = DBObjectLib.ResetProfile
+ end
+
+ -- Set some properties in the database object
+ db.profiles = sv.profiles
+ db.keys = keyTbl
+ db.sv = sv
+ --db.sv_name = name
+ db.defaults = defaults
+ db.parent = parent
+
+ -- store the DB in the registry
+ AceDB.db_registry[db] = true
+
+ return db
+end
+
+-- handle PLAYER_LOGOUT
+-- strip all defaults from all databases
+-- and cleans up empty sections
+local function logoutHandler(frame, event)
+ if event == "PLAYER_LOGOUT" then
+ for db in pairs(AceDB.db_registry) do
+ db.callbacks:Fire("OnDatabaseShutdown", db)
+ db:RegisterDefaults(nil)
+
+ -- cleanup sections that are empty without defaults
+ local sv = rawget(db, "sv")
+ for section in pairs(db.keys) do
+ if rawget(sv, section) then
+ -- global is special, all other sections have sub-entrys
+ -- also don't delete empty profiles on main dbs, only on namespaces
+ if section ~= "global" and (section ~= "profiles" or rawget(db, "parent")) then
+ for key in pairs(sv[section]) do
+ if not next(sv[section][key]) then
+ sv[section][key] = nil
+ end
+ end
+ end
+ if not next(sv[section]) then
+ sv[section] = nil
+ end
+ end
+ end
+ end
+ end
+end
+
+AceDB.frame:RegisterEvent("PLAYER_LOGOUT")
+AceDB.frame:SetScript("OnEvent", logoutHandler)
+
+
+--[[-------------------------------------------------------------------------
+ AceDB Object Method Definitions
+---------------------------------------------------------------------------]]
+
+--- Sets the defaults table for the given database object by clearing any
+-- that are currently set, and then setting the new defaults.
+-- @param defaults A table of defaults for this database
+function DBObjectLib:RegisterDefaults(defaults)
+ if defaults and type(defaults) ~= "table" then
+ error(("Usage: AceDBObject:RegisterDefaults(defaults): 'defaults' - table or nil expected, got %q."):format(type(defaults)), 2)
+ end
+
+ validateDefaults(defaults, self.keys)
+
+ -- Remove any currently set defaults
+ if self.defaults then
+ for section,key in pairs(self.keys) do
+ if self.defaults[section] and rawget(self, section) then
+ removeDefaults(self[section], self.defaults[section])
+ end
+ end
+ end
+
+ -- Set the DBObject.defaults table
+ self.defaults = defaults
+
+ -- Copy in any defaults, only touching those sections already created
+ if defaults then
+ for section,key in pairs(self.keys) do
+ if defaults[section] and rawget(self, section) then
+ copyDefaults(self[section], defaults[section])
+ end
+ end
+ end
+end
+
+--- Changes the profile of the database and all of it's namespaces to the
+-- supplied named profile
+-- @param name The name of the profile to set as the current profile
+function DBObjectLib:SetProfile(name)
+ if type(name) ~= "string" then
+ error(("Usage: AceDBObject:SetProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
+ end
+
+ -- changing to the same profile, dont do anything
+ if name == self.keys.profile then return end
+
+ local oldProfile = self.profile
+ local defaults = self.defaults and self.defaults.profile
+
+ -- Callback: OnProfileShutdown, database
+ self.callbacks:Fire("OnProfileShutdown", self)
+
+ if oldProfile and defaults then
+ -- Remove the defaults from the old profile
+ removeDefaults(oldProfile, defaults)
+ end
+
+ self.profile = nil
+ self.keys["profile"] = name
+
+ -- if the storage exists, save the new profile
+ -- this won't exist on namespaces.
+ if self.sv.profileKeys then
+ self.sv.profileKeys[charKey] = name
+ end
+
+ -- populate to child namespaces
+ if self.children then
+ for _, db in pairs(self.children) do
+ DBObjectLib.SetProfile(db, name)
+ end
+ end
+
+ -- Callback: OnProfileChanged, database, newProfileKey
+ self.callbacks:Fire("OnProfileChanged", self, name)
+end
+
+--- Returns a table with the names of the existing profiles in the database.
+-- You can optionally supply a table to re-use for this purpose.
+-- @param tbl A table to store the profile names in (optional)
+function DBObjectLib:GetProfiles(tbl)
+ if tbl and type(tbl) ~= "table" then
+ error(("Usage: AceDBObject:GetProfiles(tbl): 'tbl' - table or nil expected, got %q."):format(type(tbl)), 2)
+ end
+
+ -- Clear the container table
+ if tbl then
+ for k,v in pairs(tbl) do tbl[k] = nil end
+ else
+ tbl = {}
+ end
+
+ local curProfile = self.keys.profile
+
+ local i = 0
+ for profileKey in pairs(self.profiles) do
+ i = i + 1
+ tbl[i] = profileKey
+ if curProfile and profileKey == curProfile then curProfile = nil end
+ end
+
+ -- Add the current profile, if it hasn't been created yet
+ if curProfile then
+ i = i + 1
+ tbl[i] = curProfile
+ end
+
+ return tbl, i
+end
+
+--- Returns the current profile name used by the database
+function DBObjectLib:GetCurrentProfile()
+ return self.keys.profile
+end
+
+--- Deletes a named profile. This profile must not be the active profile.
+-- @param name The name of the profile to be deleted
+-- @param silent If true, do not raise an error when the profile does not exist
+function DBObjectLib:DeleteProfile(name, silent)
+ if type(name) ~= "string" then
+ error(("Usage: AceDBObject:DeleteProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
+ end
+
+ if self.keys.profile == name then
+ error(("Cannot delete the active profile (%q) in an AceDBObject."):format(name), 2)
+ end
+
+ if not rawget(self.profiles, name) and not silent then
+ error(("Cannot delete profile %q as it does not exist."):format(name), 2)
+ end
+
+ self.profiles[name] = nil
+
+ -- populate to child namespaces
+ if self.children then
+ for _, db in pairs(self.children) do
+ DBObjectLib.DeleteProfile(db, name, true)
+ end
+ end
+
+ -- switch all characters that use this profile back to the default
+ if self.sv.profileKeys then
+ for key, profile in pairs(self.sv.profileKeys) do
+ if profile == name then
+ self.sv.profileKeys[key] = nil
+ end
+ end
+ end
+
+ -- Callback: OnProfileDeleted, database, profileKey
+ self.callbacks:Fire("OnProfileDeleted", self, name)
+end
+
+--- Copies a named profile into the current profile, overwriting any conflicting
+-- settings.
+-- @param name The name of the profile to be copied into the current profile
+-- @param silent If true, do not raise an error when the profile does not exist
+function DBObjectLib:CopyProfile(name, silent)
+ if type(name) ~= "string" then
+ error(("Usage: AceDBObject:CopyProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
+ end
+
+ if name == self.keys.profile then
+ error(("Cannot have the same source and destination profiles (%q)."):format(name), 2)
+ end
+
+ if not rawget(self.profiles, name) and not silent then
+ error(("Cannot copy profile %q as it does not exist."):format(name), 2)
+ end
+
+ -- Reset the profile before copying
+ DBObjectLib.ResetProfile(self, nil, true)
+
+ local profile = self.profile
+ local source = self.profiles[name]
+
+ copyTable(source, profile)
+
+ -- populate to child namespaces
+ if self.children then
+ for _, db in pairs(self.children) do
+ DBObjectLib.CopyProfile(db, name, true)
+ end
+ end
+
+ -- Callback: OnProfileCopied, database, sourceProfileKey
+ self.callbacks:Fire("OnProfileCopied", self, name)
+end
+
+--- Resets the current profile to the default values (if specified).
+-- @param noChildren if set to true, the reset will not be populated to the child namespaces of this DB object
+-- @param noCallbacks if set to true, won't fire the OnProfileReset callback
+function DBObjectLib:ResetProfile(noChildren, noCallbacks)
+ local profile = self.profile
+
+ for k,v in pairs(profile) do
+ profile[k] = nil
+ end
+
+ local defaults = self.defaults and self.defaults.profile
+ if defaults then
+ copyDefaults(profile, defaults)
+ end
+
+ -- populate to child namespaces
+ if self.children and not noChildren then
+ for _, db in pairs(self.children) do
+ DBObjectLib.ResetProfile(db, nil, noCallbacks)
+ end
+ end
+
+ -- Callback: OnProfileReset, database
+ if not noCallbacks then
+ self.callbacks:Fire("OnProfileReset", self)
+ end
+end
+
+--- Resets the entire database, using the string defaultProfile as the new default
+-- profile.
+-- @param defaultProfile The profile name to use as the default
+function DBObjectLib:ResetDB(defaultProfile)
+ if defaultProfile and type(defaultProfile) ~= "string" then
+ error(("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or nil expected, got %q."):format(type(defaultProfile)), 2)
+ end
+
+ local sv = self.sv
+ for k,v in pairs(sv) do
+ sv[k] = nil
+ end
+
+ initdb(sv, self.defaults, defaultProfile, self)
+
+ -- fix the child namespaces
+ if self.children then
+ if not sv.namespaces then sv.namespaces = {} end
+ for name, db in pairs(self.children) do
+ if not sv.namespaces[name] then sv.namespaces[name] = {} end
+ initdb(sv.namespaces[name], db.defaults, self.keys.profile, db, self)
+ end
+ end
+
+ -- Callback: OnDatabaseReset, database
+ self.callbacks:Fire("OnDatabaseReset", self)
+ -- Callback: OnProfileChanged, database, profileKey
+ self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"])
+
+ return self
+end
+
+--- Creates a new database namespace, directly tied to the database. This
+-- is a full scale database in it's own rights other than the fact that
+-- it cannot control its profile individually
+-- @param name The name of the new namespace
+-- @param defaults A table of values to use as defaults
+function DBObjectLib:RegisterNamespace(name, defaults)
+ if type(name) ~= "string" then
+ error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - string expected, got %q."):format(type(name)), 2)
+ end
+ if defaults and type(defaults) ~= "table" then
+ error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'defaults' - table or nil expected, got %q."):format(type(defaults)), 2)
+ end
+ if self.children and self.children[name] then
+ error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - a namespace called %q already exists."):format(name), 2)
+ end
+
+ local sv = self.sv
+ if not sv.namespaces then sv.namespaces = {} end
+ if not sv.namespaces[name] then
+ sv.namespaces[name] = {}
+ end
+
+ local newDB = initdb(sv.namespaces[name], defaults, self.keys.profile, nil, self)
+
+ if not self.children then self.children = {} end
+ self.children[name] = newDB
+ return newDB
+end
+
+--- Returns an already existing namespace from the database object.
+-- @param name The name of the new namespace
+-- @param silent if true, the addon is optional, silently return nil if its not found
+-- @usage
+-- local namespace = self.db:GetNamespace('namespace')
+-- @return the namespace object if found
+function DBObjectLib:GetNamespace(name, silent)
+ if type(name) ~= "string" then
+ error(("Usage: AceDBObject:GetNamespace(name): 'name' - string expected, got %q."):format(type(name)), 2)
+ end
+ if not silent and not (self.children and self.children[name]) then
+ error(("Usage: AceDBObject:GetNamespace(name): 'name' - namespace %q does not exist."):format(name), 2)
+ end
+ if not self.children then self.children = {} end
+ return self.children[name]
+end
+
+--[[-------------------------------------------------------------------------
+ AceDB Exposed Methods
+---------------------------------------------------------------------------]]
+
+--- Creates a new database object that can be used to handle database settings and profiles.
+-- By default, an empty DB is created, using a character specific profile.
+--
+-- You can override the default profile used by passing any profile name as the third argument,
+-- or by passing //true// as the third argument to use a globally shared profile called "Default".
+--
+-- Note that there is no token replacement in the default profile name, passing a defaultProfile as "char"
+-- will use a profile named "char", and not a character-specific profile.
+-- @param tbl The name of variable, or table to use for the database
+-- @param defaults A table of database defaults
+-- @param defaultProfile The name of the default profile. If not set, a character specific profile will be used as the default.
+-- You can also pass //true// to use a shared global profile called "Default".
+-- @usage
+-- -- Create an empty DB using a character-specific default profile.
+-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB")
+-- @usage
+-- -- Create a DB using defaults and using a shared default profile
+-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
+function AceDB:New(tbl, defaults, defaultProfile)
+ if type(tbl) == "string" then
+ local name = tbl
+ tbl = _G[name]
+ if not tbl then
+ tbl = {}
+ _G[name] = tbl
+ end
+ end
+
+ if type(tbl) ~= "table" then
+ error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'tbl' - table expected, got %q."):format(type(tbl)), 2)
+ end
+
+ if defaults and type(defaults) ~= "table" then
+ error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected, got %q."):format(type(defaults)), 2)
+ end
+
+ if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then
+ error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string or true expected, got %q."):format(type(defaultProfile)), 2)
+ end
+
+ return initdb(tbl, defaults, defaultProfile)
+end
+
+-- upgrade existing databases
+for db in pairs(AceDB.db_registry) do
+ if not db.parent then
+ for name,func in pairs(DBObjectLib) do
+ db[name] = func
+ end
+ else
+ db.RegisterDefaults = DBObjectLib.RegisterDefaults
+ db.ResetProfile = DBObjectLib.ResetProfile
+ end
+end
diff --git a/ElvUI/Libraries/Ace3/AceDB-3.0/AceDB-3.0.xml b/ElvUI/Libraries/Ace3/AceDB-3.0/AceDB-3.0.xml
new file mode 100644
index 0000000..46b20ba
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceDB-3.0/AceDB-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/Ace3/AceEvent-3.0/AceEvent-3.0.lua b/ElvUI/Libraries/Ace3/AceEvent-3.0/AceEvent-3.0.lua
new file mode 100644
index 0000000..9f96bf3
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceEvent-3.0/AceEvent-3.0.lua
@@ -0,0 +1,126 @@
+--- AceEvent-3.0 provides event registration and secure dispatching.
+-- All dispatching is done using **CallbackHandler-1.0**. AceEvent is a simple wrapper around
+-- CallbackHandler, and dispatches all game events or addon message to the registrees.
+--
+-- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent:Embed(MyAddon) or by
+-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
+-- and can be accessed directly, without having to explicitly call AceEvent itself.\\
+-- It is recommended to embed AceEvent, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceEvent.
+-- @class file
+-- @name AceEvent-3.0
+-- @release $Id$
+local CallbackHandler = LibStub("CallbackHandler-1.0")
+
+local MAJOR, MINOR = "AceEvent-3.0", 4
+local AceEvent = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceEvent then return end
+
+-- Lua APIs
+local pairs = pairs
+
+AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame
+AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib
+
+-- APIs and registry for blizzard events, using CallbackHandler lib
+if not AceEvent.events then
+ AceEvent.events = CallbackHandler:New(AceEvent,
+ "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents")
+end
+
+function AceEvent.events:OnUsed(target, eventname)
+ AceEvent.frame:RegisterEvent(eventname)
+end
+
+function AceEvent.events:OnUnused(target, eventname)
+ AceEvent.frame:UnregisterEvent(eventname)
+end
+
+
+-- APIs and registry for IPC messages, using CallbackHandler lib
+if not AceEvent.messages then
+ AceEvent.messages = CallbackHandler:New(AceEvent,
+ "RegisterMessage", "UnregisterMessage", "UnregisterAllMessages"
+ )
+ AceEvent.SendMessage = AceEvent.messages.Fire
+end
+
+--- embedding and embed handling
+local mixins = {
+ "RegisterEvent", "UnregisterEvent",
+ "RegisterMessage", "UnregisterMessage",
+ "SendMessage",
+ "UnregisterAllEvents", "UnregisterAllMessages",
+}
+
+--- Register for a Blizzard Event.
+-- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied)
+-- Any arguments to the event will be passed on after that.
+-- @name AceEvent:RegisterEvent
+-- @class function
+-- @paramsig event[, callback [, arg]]
+-- @param event The event to register for
+-- @param callback The callback function to call when the event is triggered (funcref or method, defaults to a method with the event name)
+-- @param arg An optional argument to pass to the callback function
+
+--- Unregister an event.
+-- @name AceEvent:UnregisterEvent
+-- @class function
+-- @paramsig event
+-- @param event The event to unregister
+
+--- Register for a custom AceEvent-internal message.
+-- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied)
+-- Any arguments to the event will be passed on after that.
+-- @name AceEvent:RegisterMessage
+-- @class function
+-- @paramsig message[, callback [, arg]]
+-- @param message The message to register for
+-- @param callback The callback function to call when the message is triggered (funcref or method, defaults to a method with the event name)
+-- @param arg An optional argument to pass to the callback function
+
+--- Unregister a message
+-- @name AceEvent:UnregisterMessage
+-- @class function
+-- @paramsig message
+-- @param message The message to unregister
+
+--- Send a message over the AceEvent-3.0 internal message system to other addons registered for this message.
+-- @name AceEvent:SendMessage
+-- @class function
+-- @paramsig message, ...
+-- @param message The message to send
+-- @param ... Any arguments to the message
+
+
+-- Embeds AceEvent into the target object making the functions from the mixins list available on target:..
+-- @param target target object to embed AceEvent in
+function AceEvent:Embed(target)
+ for k, v in pairs(mixins) do
+ target[v] = self[v]
+ end
+ self.embeds[target] = true
+ return target
+end
+
+-- AceEvent:OnEmbedDisable( target )
+-- target (object) - target object that is being disabled
+--
+-- Unregister all events messages etc when the target disables.
+-- this method should be called by the target manually or by an addon framework
+function AceEvent:OnEmbedDisable(target)
+ target:UnregisterAllEvents()
+ target:UnregisterAllMessages()
+end
+
+-- Script to fire blizzard events into the event listeners
+local events = AceEvent.events
+AceEvent.frame:SetScript("OnEvent", function(this, event, ...)
+ events:Fire(event, ...)
+end)
+
+--- Finally: upgrade our old embeds
+for target, v in pairs(AceEvent.embeds) do
+ AceEvent:Embed(target)
+end
diff --git a/ElvUI/Libraries/Ace3/AceEvent-3.0/AceEvent-3.0.xml b/ElvUI/Libraries/Ace3/AceEvent-3.0/AceEvent-3.0.xml
new file mode 100644
index 0000000..313ef4d
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceEvent-3.0/AceEvent-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/Ace3/AceHook-3.0/AceHook-3.0.lua b/ElvUI/Libraries/Ace3/AceHook-3.0/AceHook-3.0.lua
new file mode 100644
index 0000000..96f18a5
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceHook-3.0/AceHook-3.0.lua
@@ -0,0 +1,511 @@
+--- **AceHook-3.0** offers safe Hooking/Unhooking of functions, methods and frame scripts.
+-- Using AceHook-3.0 is recommended when you need to unhook your hooks again, so the hook chain isn't broken
+-- when you manually restore the original function.
+--
+-- **AceHook-3.0** can be embeded into your addon, either explicitly by calling AceHook:Embed(MyAddon) or by
+-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
+-- and can be accessed directly, without having to explicitly call AceHook itself.\\
+-- It is recommended to embed AceHook, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceHook.
+-- @class file
+-- @name AceHook-3.0
+-- @release $Id$
+local ACEHOOK_MAJOR, ACEHOOK_MINOR = "AceHook-3.0", 8
+local AceHook, oldminor = LibStub:NewLibrary(ACEHOOK_MAJOR, ACEHOOK_MINOR)
+
+if not AceHook then return end -- No upgrade needed
+
+AceHook.embeded = AceHook.embeded or {}
+AceHook.registry = AceHook.registry or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end })
+AceHook.handlers = AceHook.handlers or {}
+AceHook.actives = AceHook.actives or {}
+AceHook.scripts = AceHook.scripts or {}
+AceHook.onceSecure = AceHook.onceSecure or {}
+AceHook.hooks = AceHook.hooks or {}
+
+-- local upvalues
+local registry = AceHook.registry
+local handlers = AceHook.handlers
+local actives = AceHook.actives
+local scripts = AceHook.scripts
+local onceSecure = AceHook.onceSecure
+
+-- Lua APIs
+local pairs, next, type = pairs, next, type
+local format = string.format
+local assert, error = assert, error
+
+-- WoW APIs
+local issecurevariable, hooksecurefunc = issecurevariable, hooksecurefunc
+local _G = _G
+
+-- functions for later definition
+local donothing, createHook, hook
+
+local protectedScripts = {
+ OnClick = true,
+}
+
+-- upgrading of embeded is done at the bottom of the file
+
+local mixins = {
+ "Hook", "SecureHook",
+ "HookScript", "SecureHookScript",
+ "Unhook", "UnhookAll",
+ "IsHooked",
+ "RawHook", "RawHookScript"
+}
+
+-- AceHook:Embed( target )
+-- target (object) - target object to embed AceHook in
+--
+-- Embeds AceEevent into the target object making the functions from the mixins list available on target:..
+function AceHook:Embed( target )
+ for k, v in pairs( mixins ) do
+ target[v] = self[v]
+ end
+ self.embeded[target] = true
+ -- inject the hooks table safely
+ target.hooks = target.hooks or {}
+ return target
+end
+
+-- AceHook:OnEmbedDisable( target )
+-- target (object) - target object that is being disabled
+--
+-- Unhooks all hooks when the target disables.
+-- this method should be called by the target manually or by an addon framework
+function AceHook:OnEmbedDisable( target )
+ target:UnhookAll()
+end
+
+function createHook(self, handler, orig, secure, failsafe)
+ local uid
+ local method = type(handler) == "string"
+ if failsafe and not secure then
+ -- failsafe hook creation
+ uid = function(...)
+ if actives[uid] then
+ if method then
+ self[handler](self, ...)
+ else
+ handler(...)
+ end
+ end
+ return orig(...)
+ end
+ -- /failsafe hook
+ else
+ -- all other hooks
+ uid = function(...)
+ if actives[uid] then
+ if method then
+ return self[handler](self, ...)
+ else
+ return handler(...)
+ end
+ elseif not secure then -- backup on non secure
+ return orig(...)
+ end
+ end
+ -- /hook
+ end
+ return uid
+end
+
+function donothing() end
+
+function hook(self, obj, method, handler, script, secure, raw, forceSecure, usage)
+ if not handler then handler = method end
+
+ -- These asserts make sure AceHooks's devs play by the rules.
+ assert(not script or type(script) == "boolean")
+ assert(not secure or type(secure) == "boolean")
+ assert(not raw or type(raw) == "boolean")
+ assert(not forceSecure or type(forceSecure) == "boolean")
+ assert(usage)
+
+ -- Error checking Battery!
+ if obj and type(obj) ~= "table" then
+ error(format("%s: 'object' - nil or table expected got %s", usage, type(obj)), 3)
+ end
+ if type(method) ~= "string" then
+ error(format("%s: 'method' - string expected got %s", usage, type(method)), 3)
+ end
+ if type(handler) ~= "string" and type(handler) ~= "function" then
+ error(format("%s: 'handler' - nil, string, or function expected got %s", usage, type(handler)), 3)
+ end
+ if type(handler) == "string" and type(self[handler]) ~= "function" then
+ error(format("%s: 'handler' - Handler specified does not exist at self[handler]", usage), 3)
+ end
+ if script then
+ if not obj or not obj.GetScript or not obj:HasScript(method) then
+ error(format("%s: You can only hook a script on a frame object", usage), 3)
+ end
+ if not secure and obj.IsProtected and obj:IsProtected() and protectedScripts[method] then
+ error(format("Cannot hook secure script %q; Use SecureHookScript(obj, method, [handler]) instead.", method), 3)
+ end
+ else
+ local issecure
+ if obj then
+ issecure = onceSecure[obj] and onceSecure[obj][method] or issecurevariable(obj, method)
+ else
+ issecure = onceSecure[method] or issecurevariable(method)
+ end
+ if issecure then
+ if forceSecure then
+ if obj then
+ onceSecure[obj] = onceSecure[obj] or {}
+ onceSecure[obj][method] = true
+ else
+ onceSecure[method] = true
+ end
+ elseif not secure then
+ error(format("%s: Attempt to hook secure function %s. Use `SecureHook' or add `true' to the argument list to override.", usage, method), 3)
+ end
+ end
+ end
+
+ local uid
+ if obj then
+ uid = registry[self][obj] and registry[self][obj][method]
+ else
+ uid = registry[self][method]
+ end
+
+ if uid then
+ if actives[uid] then
+ -- Only two sane choices exist here. We either a) error 100% of the time or b) always unhook and then hook
+ -- choice b would likely lead to odd debuging conditions or other mysteries so we're going with a.
+ error(format("Attempting to rehook already active hook %s.", method))
+ end
+
+ if handlers[uid] == handler then -- turn on a decative hook, note enclosures break this ability, small memory leak
+ actives[uid] = true
+ return
+ elseif obj then -- is there any reason not to call unhook instead of doing the following several lines?
+ if self.hooks and self.hooks[obj] then
+ self.hooks[obj][method] = nil
+ end
+ registry[self][obj][method] = nil
+ else
+ if self.hooks then
+ self.hooks[method] = nil
+ end
+ registry[self][method] = nil
+ end
+ handlers[uid], actives[uid], scripts[uid] = nil, nil, nil
+ uid = nil
+ end
+
+ local orig
+ if script then
+ orig = obj:GetScript(method) or donothing
+ elseif obj then
+ orig = obj[method]
+ else
+ orig = _G[method]
+ end
+
+ if not orig then
+ error(format("%s: Attempting to hook a non existing target", usage), 3)
+ end
+
+ uid = createHook(self, handler, orig, secure, not (raw or secure))
+
+ if obj then
+ self.hooks[obj] = self.hooks[obj] or {}
+ registry[self][obj] = registry[self][obj] or {}
+ registry[self][obj][method] = uid
+
+ if not secure then
+ self.hooks[obj][method] = orig
+ end
+
+ if script then
+ if not secure then
+ obj:SetScript(method, uid)
+ else
+ obj:HookScript(method, uid)
+ end
+ else
+ if not secure then
+ obj[method] = uid
+ else
+ hooksecurefunc(obj, method, uid)
+ end
+ end
+ else
+ registry[self][method] = uid
+
+ if not secure then
+ _G[method] = uid
+ self.hooks[method] = orig
+ else
+ hooksecurefunc(method, uid)
+ end
+ end
+
+ actives[uid], handlers[uid], scripts[uid] = true, handler, script and true or nil
+end
+
+--- Hook a function or a method on an object.
+-- The hook created will be a "safe hook", that means that your handler will be called
+-- before the hooked function ("Pre-Hook"), and you don't have to call the original function yourself,
+-- however you cannot stop the execution of the function, or modify any of the arguments/return values.\\
+-- This type of hook is typically used if you need to know if some function got called, and don't want to modify it.
+-- @paramsig [object], method, [handler], [hookSecure]
+-- @param object The object to hook a method from
+-- @param method If object was specified, the name of the method, or the name of the function to hook.
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked function)
+-- @param hookSecure If true, AceHook will allow hooking of secure functions.
+-- @usage
+-- -- create an addon with AceHook embeded
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
+--
+-- function MyAddon:OnEnable()
+-- -- Hook ActionButton_UpdateHotkeys, overwriting the secure status
+-- self:Hook("ActionButton_UpdateHotkeys", true)
+-- end
+--
+-- function MyAddon:ActionButton_UpdateHotkeys(button, type)
+-- print(button:GetName() .. " is updating its HotKey")
+-- end
+function AceHook:Hook(object, method, handler, hookSecure)
+ if type(object) == "string" then
+ method, handler, hookSecure, object = object, method, handler, nil
+ end
+
+ if handler == true then
+ handler, hookSecure = nil, true
+ end
+
+ hook(self, object, method, handler, false, false, false, hookSecure or false, "Usage: Hook([object], method, [handler], [hookSecure])")
+end
+
+--- RawHook a function or a method on an object.
+-- The hook created will be a "raw hook", that means that your handler will completly replace
+-- the original function, and your handler has to call the original function (or not, depending on your intentions).\\
+-- The original function will be stored in `self.hooks[object][method]` or `self.hooks[functionName]` respectively.\\
+-- This type of hook can be used for all purposes, and is usually the most common case when you need to modify arguments
+-- or want to control execution of the original function.
+-- @paramsig [object], method, [handler], [hookSecure]
+-- @param object The object to hook a method from
+-- @param method If object was specified, the name of the method, or the name of the function to hook.
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked function)
+-- @param hookSecure If true, AceHook will allow hooking of secure functions.
+-- @usage
+-- -- create an addon with AceHook embeded
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
+--
+-- function MyAddon:OnEnable()
+-- -- Hook ActionButton_UpdateHotkeys, overwriting the secure status
+-- self:RawHook("ActionButton_UpdateHotkeys", true)
+-- end
+--
+-- function MyAddon:ActionButton_UpdateHotkeys(button, type)
+-- if button:GetName() == "MyButton" then
+-- -- do stuff here
+-- else
+-- self.hooks.ActionButton_UpdateHotkeys(button, type)
+-- end
+-- end
+function AceHook:RawHook(object, method, handler, hookSecure)
+ if type(object) == "string" then
+ method, handler, hookSecure, object = object, method, handler, nil
+ end
+
+ if handler == true then
+ handler, hookSecure = nil, true
+ end
+
+ hook(self, object, method, handler, false, false, true, hookSecure or false, "Usage: RawHook([object], method, [handler], [hookSecure])")
+end
+
+--- SecureHook a function or a method on an object.
+-- This function is a wrapper around the `hooksecurefunc` function in the WoW API. Using AceHook
+-- extends the functionality of secure hooks, and adds the ability to unhook once the hook isn't
+-- required anymore, or the addon is being disabled.\\
+-- Secure Hooks should be used if the secure-status of the function is vital to its function,
+-- and taint would block execution. Secure Hooks are always called after the original function was called
+-- ("Post Hook"), and you cannot modify the arguments, return values or control the execution.
+-- @paramsig [object], method, [handler]
+-- @param object The object to hook a method from
+-- @param method If object was specified, the name of the method, or the name of the function to hook.
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked function)
+function AceHook:SecureHook(object, method, handler)
+ if type(object) == "string" then
+ method, handler, object = object, method, nil
+ end
+
+ hook(self, object, method, handler, false, true, false, false, "Usage: SecureHook([object], method, [handler])")
+end
+
+--- Hook a script handler on a frame.
+-- The hook created will be a "safe hook", that means that your handler will be called
+-- before the hooked script ("Pre-Hook"), and you don't have to call the original function yourself,
+-- however you cannot stop the execution of the function, or modify any of the arguments/return values.\\
+-- This is the frame script equivalent of the :Hook safe-hook. It would typically be used to be notified
+-- when a certain event happens to a frame.
+-- @paramsig frame, script, [handler]
+-- @param frame The Frame to hook the script on
+-- @param script The script to hook
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked script)
+-- @usage
+-- -- create an addon with AceHook embeded
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
+--
+-- function MyAddon:OnEnable()
+-- -- Hook the OnShow of FriendsFrame
+-- self:HookScript(FriendsFrame, "OnShow", "FriendsFrameOnShow")
+-- end
+--
+-- function MyAddon:FriendsFrameOnShow(frame)
+-- print("The FriendsFrame was shown!")
+-- end
+function AceHook:HookScript(frame, script, handler)
+ hook(self, frame, script, handler, true, false, false, false, "Usage: HookScript(object, method, [handler])")
+end
+
+--- RawHook a script handler on a frame.
+-- The hook created will be a "raw hook", that means that your handler will completly replace
+-- the original script, and your handler has to call the original script (or not, depending on your intentions).\\
+-- The original script will be stored in `self.hooks[frame][script]`.\\
+-- This type of hook can be used for all purposes, and is usually the most common case when you need to modify arguments
+-- or want to control execution of the original script.
+-- @paramsig frame, script, [handler]
+-- @param frame The Frame to hook the script on
+-- @param script The script to hook
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked script)
+-- @usage
+-- -- create an addon with AceHook embeded
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
+--
+-- function MyAddon:OnEnable()
+-- -- Hook the OnShow of FriendsFrame
+-- self:RawHookScript(FriendsFrame, "OnShow", "FriendsFrameOnShow")
+-- end
+--
+-- function MyAddon:FriendsFrameOnShow(frame)
+-- -- Call the original function
+-- self.hooks[frame].OnShow(frame)
+-- -- Do our processing
+-- -- .. stuff
+-- end
+function AceHook:RawHookScript(frame, script, handler)
+ hook(self, frame, script, handler, true, false, true, false, "Usage: RawHookScript(object, method, [handler])")
+end
+
+--- SecureHook a script handler on a frame.
+-- This function is a wrapper around the `frame:HookScript` function in the WoW API. Using AceHook
+-- extends the functionality of secure hooks, and adds the ability to unhook once the hook isn't
+-- required anymore, or the addon is being disabled.\\
+-- Secure Hooks should be used if the secure-status of the function is vital to its function,
+-- and taint would block execution. Secure Hooks are always called after the original function was called
+-- ("Post Hook"), and you cannot modify the arguments, return values or control the execution.
+-- @paramsig frame, script, [handler]
+-- @param frame The Frame to hook the script on
+-- @param script The script to hook
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked script)
+function AceHook:SecureHookScript(frame, script, handler)
+ hook(self, frame, script, handler, true, true, false, false, "Usage: SecureHookScript(object, method, [handler])")
+end
+
+--- Unhook from the specified function, method or script.
+-- @paramsig [obj], method
+-- @param obj The object or frame to unhook from
+-- @param method The name of the method, function or script to unhook from.
+function AceHook:Unhook(obj, method)
+ local usage = "Usage: Unhook([obj], method)"
+ if type(obj) == "string" then
+ method, obj = obj, nil
+ end
+
+ if obj and type(obj) ~= "table" then
+ error(format("%s: 'obj' - expecting nil or table got %s", usage, type(obj)), 2)
+ end
+ if type(method) ~= "string" then
+ error(format("%s: 'method' - expeting string got %s", usage, type(method)), 2)
+ end
+
+ local uid
+ if obj then
+ uid = registry[self][obj] and registry[self][obj][method]
+ else
+ uid = registry[self][method]
+ end
+
+ if not uid or not actives[uid] then
+ -- Declining to error on an unneeded unhook since the end effect is the same and this would just be annoying.
+ return false
+ end
+
+ actives[uid], handlers[uid] = nil, nil
+
+ if obj then
+ registry[self][obj][method] = nil
+ registry[self][obj] = next(registry[self][obj]) and registry[self][obj] or nil
+
+ -- if the hook reference doesnt exist, then its a secure hook, just bail out and dont do any unhooking
+ if not self.hooks[obj] or not self.hooks[obj][method] then return true end
+
+ if scripts[uid] and obj:GetScript(method) == uid then -- unhooks scripts
+ obj:SetScript(method, self.hooks[obj][method] ~= donothing and self.hooks[obj][method] or nil)
+ scripts[uid] = nil
+ elseif obj and self.hooks[obj] and self.hooks[obj][method] and obj[method] == uid then -- unhooks methods
+ obj[method] = self.hooks[obj][method]
+ end
+
+ self.hooks[obj][method] = nil
+ self.hooks[obj] = next(self.hooks[obj]) and self.hooks[obj] or nil
+ else
+ registry[self][method] = nil
+
+ -- if self.hooks[method] doesn't exist, then this is a SecureHook, just bail out
+ if not self.hooks[method] then return true end
+
+ if self.hooks[method] and _G[method] == uid then -- unhooks functions
+ _G[method] = self.hooks[method]
+ end
+
+ self.hooks[method] = nil
+ end
+ return true
+end
+
+--- Unhook all existing hooks for this addon.
+function AceHook:UnhookAll()
+ for key, value in pairs(registry[self]) do
+ if type(key) == "table" then
+ for method in pairs(value) do
+ self:Unhook(key, method)
+ end
+ else
+ self:Unhook(key)
+ end
+ end
+end
+
+--- Check if the specific function, method or script is already hooked.
+-- @paramsig [obj], method
+-- @param obj The object or frame to unhook from
+-- @param method The name of the method, function or script to unhook from.
+function AceHook:IsHooked(obj, method)
+ -- we don't check if registry[self] exists, this is done by evil magicks in the metatable
+ if type(obj) == "string" then
+ if registry[self][obj] and actives[registry[self][obj]] then
+ return true, handlers[registry[self][obj]]
+ end
+ else
+ if registry[self][obj] and registry[self][obj][method] and actives[registry[self][obj][method]] then
+ return true, handlers[registry[self][obj][method]]
+ end
+ end
+
+ return false, nil
+end
+
+--- Upgrade our old embeded
+for target, v in pairs( AceHook.embeded ) do
+ AceHook:Embed( target )
+end
diff --git a/ElvUI/Libraries/Ace3/AceHook-3.0/AceHook-3.0.xml b/ElvUI/Libraries/Ace3/AceHook-3.0/AceHook-3.0.xml
new file mode 100644
index 0000000..add0f26
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceHook-3.0/AceHook-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/Ace3/AceLocale-3.0/AceLocale-3.0.lua b/ElvUI/Libraries/Ace3/AceLocale-3.0/AceLocale-3.0.lua
new file mode 100644
index 0000000..162b08a
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceLocale-3.0/AceLocale-3.0.lua
@@ -0,0 +1,143 @@
+--- **AceLocale-3.0** manages localization in addons, allowing for multiple locale to be registered with fallback to the base locale for untranslated strings.
+-- @class file
+-- @name AceLocale-3.0
+-- @release $Id$
+local MAJOR,MINOR = "AceLocale-3.0-ElvUI", 6
+
+local AceLocale, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceLocale then return end -- no upgrade needed
+
+-- Lua APIs
+local assert, tostring, error = assert, tostring, error
+local getmetatable, setmetatable, rawset, rawget = getmetatable, setmetatable, rawset, rawget
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: GAME_LOCALE, geterrorhandler
+
+local gameLocale = GetLocale()
+if gameLocale == "enGB" then
+ gameLocale = "enUS"
+end
+
+AceLocale.apps = AceLocale.apps or {} -- array of ["AppName"]=localetableref
+AceLocale.appnames = AceLocale.appnames or {} -- array of [localetableref]="AppName"
+
+-- This metatable is used on all tables returned from GetLocale
+local readmeta = {
+ __index = function(self, key) -- requesting totally unknown entries: fire off a nonbreaking error and return key
+ rawset(self, key, key) -- only need to see the warning once, really
+ geterrorhandler()(MAJOR..": "..tostring(AceLocale.appnames[self])..": Missing entry for '"..tostring(key).."'")
+ return key
+ end
+}
+
+-- This metatable is used on all tables returned from GetLocale if the silent flag is true, it does not issue a warning on unknown keys
+local readmetasilent = {
+ __index = function(self, key) -- requesting totally unknown entries: return key
+ rawset(self, key, key) -- only need to invoke this function once
+ return key
+ end
+}
+
+-- Remember the locale table being registered right now (it gets set by :NewLocale())
+-- NOTE: Do never try to register 2 locale tables at once and mix their definition.
+local registering
+
+-- local assert false function
+local assertfalse = function() assert(false) end
+
+-- This metatable proxy is used when registering nondefault locales
+local writeproxy = setmetatable({}, {
+ __newindex = function(self, key, value)
+ rawset(registering, key, value == true and key or value) -- assigning values: replace 'true' with key string
+ end,
+ __index = assertfalse
+})
+
+-- This metatable proxy is used when registering the default locale.
+-- It refuses to overwrite existing values
+-- Reason 1: Allows loading locales in any order
+-- Reason 2: If 2 modules have the same string, but only the first one to be
+-- loaded has a translation for the current locale, the translation
+-- doesn't get overwritten.
+--
+local writedefaultproxy = setmetatable({}, {
+ __newindex = function(self, key, value)
+ if not rawget(registering, key) then
+ rawset(registering, key, value == true and key or value)
+ end
+ end,
+ __index = assertfalse
+})
+
+--- Register a new locale (or extend an existing one) for the specified application.
+-- :NewLocale will return a table you can fill your locale into, or nil if the locale isn't needed for the players
+-- game locale.
+-- @paramsig application, locale[, isDefault[, silent]]
+-- @param application Unique name of addon / module
+-- @param locale Name of the locale to register, e.g. "enUS", "deDE", etc.
+-- @param isDefault If this is the default locale being registered (your addon is written in this language, generally enUS)
+-- @param silent If true, the locale will not issue warnings for missing keys. Must be set on the first locale registered. If set to "raw", nils will be returned for unknown keys (no metatable used).
+-- @usage
+-- -- enUS.lua
+-- local L = LibStub("AceLocale-3.0"):NewLocale("TestLocale", "enUS", true)
+-- L["string1"] = true
+--
+-- -- deDE.lua
+-- local L = LibStub("AceLocale-3.0"):NewLocale("TestLocale", "deDE")
+-- if not L then return end
+-- L["string1"] = "Zeichenkette1"
+-- @return Locale Table to add localizations to, or nil if the current locale is not required.
+function AceLocale:NewLocale(application, locale, isDefault, silent)
+ local app = AceLocale.apps[application]
+
+ if silent and app and getmetatable(app) ~= readmetasilent then
+ geterrorhandler()("Usage: NewLocale(application, locale[, isDefault[, silent]]): 'silent' must be specified for the first locale registered")
+ end
+
+ if not app then
+ if silent=="raw" then
+ app = {}
+ else
+ app = setmetatable({}, silent and readmetasilent or readmeta)
+ end
+ AceLocale.apps[application] = app
+ AceLocale.appnames[app] = application
+ end
+
+ -- ElvUI block
+ if (not app[locale]) or (app[locale] and type(app[locale]) ~= 'table') then
+ -- app[locale] = setmetatable({}, silent and readmetasilent or readmeta) -- To find missing keys
+ app[locale] = setmetatable({}, readmetasilent)
+ end
+
+ registering = app[locale] -- remember globally for writeproxy and writedefaultproxy
+ -- end block
+
+ if isDefault then
+ return writedefaultproxy
+ end
+
+ return writeproxy
+end
+
+--- Returns localizations for the current locale (or default locale if translations are missing).
+-- Errors if nothing is registered (spank developer, not just a missing translation)
+-- @param application Unique name of addon / module
+-- @param silent If true, the locale is optional, silently return nil if it's not found (defaults to false, optional)
+-- @return The locale table for the current language.
+--- Modified by ElvUI to add `locale` as second arg
+function AceLocale:GetLocale(application, locale, silent)
+ if type(locale) == "boolean" then
+ silent = locale
+ locale = gameLocale
+ end
+
+ if not silent and not AceLocale.apps[application] then
+ error("Usage: GetLocale(application[,locale[, silent]]): 'application' - No locales registered for '"..tostring(application).."'", 2)
+ end
+
+ return AceLocale.apps[application][locale] or AceLocale.apps[application][gameLocale] -- Just in case the table doesn't exist it reverts to default
+end
diff --git a/ElvUI/Libraries/Ace3/AceLocale-3.0/AceLocale-3.0.xml b/ElvUI/Libraries/Ace3/AceLocale-3.0/AceLocale-3.0.xml
new file mode 100644
index 0000000..e017af0
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceLocale-3.0/AceLocale-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/Ace3/AceSerializer-3.0/AceSerializer-3.0.lua b/ElvUI/Libraries/Ace3/AceSerializer-3.0/AceSerializer-3.0.lua
new file mode 100644
index 0000000..a526626
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceSerializer-3.0/AceSerializer-3.0.lua
@@ -0,0 +1,281 @@
+--- **AceSerializer-3.0** can serialize any variable (except functions or userdata) into a string format,
+-- that can be send over the addon comm channel. AceSerializer was designed to keep all data intact, especially
+-- very large numbers or floating point numbers, and table structures. The only caveat currently is, that multiple
+-- references to the same table will be send individually.
+--
+-- **AceSerializer-3.0** can be embeded into your addon, either explicitly by calling AceSerializer:Embed(MyAddon) or by
+-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
+-- and can be accessed directly, without having to explicitly call AceSerializer itself.\\
+-- It is recommended to embed AceSerializer, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceSerializer.
+-- @class file
+-- @name AceSerializer-3.0
+-- @release $Id$
+local MAJOR,MINOR = "AceSerializer-3.0", 3
+local AceSerializer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceSerializer then return end
+
+-- Lua APIs
+local strbyte, strchar, gsub, gmatch, format = string.byte, string.char, string.gsub, string.gmatch, string.format
+local assert, error, pcall = assert, error, pcall
+local type, tostring, tonumber = type, tostring, tonumber
+local pairs, select, frexp = pairs, select, math.frexp
+local tconcat = table.concat
+
+-- quick copies of string representations of wonky numbers
+local serNaN = tostring(0/0)
+local serInf = tostring(1/0)
+local serNegInf = tostring(-1/0)
+
+
+-- Serialization functions
+
+local function SerializeStringHelper(ch) -- Used by SerializeValue for strings
+ -- We use \126 ("~") as an escape character for all nonprints plus a few more
+ local n = strbyte(ch)
+ if n==30 then -- v3 / ticket 115: catch a nonprint that ends up being "~^" when encoded... DOH
+ return "\126\122"
+ elseif n<=32 then -- nonprint + space
+ return "\126"..strchar(n+64)
+ elseif n==94 then -- value separator
+ return "\126\125"
+ elseif n==126 then -- our own escape character
+ return "\126\124"
+ elseif n==127 then -- nonprint (DEL)
+ return "\126\123"
+ else
+ assert(false) -- can't be reached if caller uses a sane regex
+ end
+end
+
+local function SerializeValue(v, res, nres)
+ -- We use "^" as a value separator, followed by one byte for type indicator
+ local t=type(v)
+
+ if t=="string" then -- ^S = string (escaped to remove nonprints, "^"s, etc)
+ res[nres+1] = "^S"
+ res[nres+2] = gsub(v,"[%c \94\126\127]", SerializeStringHelper)
+ nres=nres+2
+
+ elseif t=="number" then -- ^N = number (just tostring()ed) or ^F (float components)
+ local str = tostring(v)
+ if tonumber(str)==v or str==serNaN or str==serInf or str==serNegInf then
+ -- translates just fine, transmit as-is
+ res[nres+1] = "^N"
+ res[nres+2] = str
+ nres=nres+2
+ else
+ local m,e = frexp(v)
+ res[nres+1] = "^F"
+ res[nres+2] = format("%.0f",m*2^53) -- force mantissa to become integer (it's originally 0.5--0.9999)
+ res[nres+3] = "^f"
+ res[nres+4] = tostring(e-53) -- adjust exponent to counteract mantissa manipulation
+ nres=nres+4
+ end
+
+ elseif t=="table" then -- ^T...^t = table (list of key,value pairs)
+ nres=nres+1
+ res[nres] = "^T"
+ for k,v in pairs(v) do
+ nres = SerializeValue(k, res, nres)
+ nres = SerializeValue(v, res, nres)
+ end
+ nres=nres+1
+ res[nres] = "^t"
+
+ elseif t=="boolean" then -- ^B = true, ^b = false
+ nres=nres+1
+ if v then
+ res[nres] = "^B" -- true
+ else
+ res[nres] = "^b" -- false
+ end
+
+ elseif t=="nil" then -- ^Z = nil (zero, "N" was taken :P)
+ nres=nres+1
+ res[nres] = "^Z"
+
+ else
+ error(MAJOR..": Cannot serialize a value of type '"..t.."'") -- can't produce error on right level, this is wildly recursive
+ end
+
+ return nres
+end
+
+
+
+local serializeTbl = { "^1" } -- "^1" = Hi, I'm data serialized by AceSerializer protocol rev 1
+
+--- Serialize the data passed into the function.
+-- Takes a list of values (strings, numbers, booleans, nils, tables)
+-- and returns it in serialized form (a string).\\
+-- May throw errors on invalid data types.
+-- @param ... List of values to serialize
+-- @return The data in its serialized form (string)
+function AceSerializer:Serialize(...)
+ local nres = 1
+
+ for i=1,select("#", ...) do
+ local v = select(i, ...)
+ nres = SerializeValue(v, serializeTbl, nres)
+ end
+
+ serializeTbl[nres+1] = "^^" -- "^^" = End of serialized data
+
+ return tconcat(serializeTbl, "", 1, nres+1)
+end
+
+-- Deserialization functions
+local function DeserializeStringHelper(escape)
+ if escape<"~\122" then
+ return strchar(strbyte(escape,2,2)-64)
+ elseif escape=="~\122" then -- v3 / ticket 115: special case encode since 30+64=94 ("^") - OOPS.
+ return "\030"
+ elseif escape=="~\123" then
+ return "\127"
+ elseif escape=="~\124" then
+ return "\126"
+ elseif escape=="~\125" then
+ return "\94"
+ end
+ error("DeserializeStringHelper got called for '"..escape.."'?!?") -- can't be reached unless regex is screwed up
+end
+
+local function DeserializeNumberHelper(number)
+ if number == serNaN then
+ return 0/0
+ elseif number == serNegInf then
+ return -1/0
+ elseif number == serInf then
+ return 1/0
+ else
+ return tonumber(number)
+ end
+end
+
+-- DeserializeValue: worker function for :Deserialize()
+-- It works in two modes:
+-- Main (top-level) mode: Deserialize a list of values and return them all
+-- Recursive (table) mode: Deserialize only a single value (_may_ of course be another table with lots of subvalues in it)
+--
+-- The function _always_ works recursively due to having to build a list of values to return
+--
+-- Callers are expected to pcall(DeserializeValue) to trap errors
+
+local function DeserializeValue(iter,single,ctl,data)
+
+ if not single then
+ ctl,data = iter()
+ end
+
+ if not ctl then
+ error("Supplied data misses AceSerializer terminator ('^^')")
+ end
+
+ if ctl=="^^" then
+ -- ignore extraneous data
+ return
+ end
+
+ local res
+
+ if ctl=="^S" then
+ res = gsub(data, "~.", DeserializeStringHelper)
+ elseif ctl=="^N" then
+ res = DeserializeNumberHelper(data)
+ if not res then
+ error("Invalid serialized number: '"..tostring(data).."'")
+ end
+ elseif ctl=="^F" then -- ^F^f
+ local ctl2,e = iter()
+ if ctl2~="^f" then
+ error("Invalid serialized floating-point number, expected '^f', not '"..tostring(ctl2).."'")
+ end
+ local m=tonumber(data)
+ e=tonumber(e)
+ if not (m and e) then
+ error("Invalid serialized floating-point number, expected mantissa and exponent, got '"..tostring(m).."' and '"..tostring(e).."'")
+ end
+ res = m*(2^e)
+ elseif ctl=="^B" then -- yeah yeah ignore data portion
+ res = true
+ elseif ctl=="^b" then -- yeah yeah ignore data portion
+ res = false
+ elseif ctl=="^Z" then -- yeah yeah ignore data portion
+ res = nil
+ elseif ctl=="^T" then
+ -- ignore ^T's data, future extensibility?
+ res = {}
+ local k,v
+ while true do
+ ctl,data = iter()
+ if ctl=="^t" then break end -- ignore ^t's data
+ k = DeserializeValue(iter,true,ctl,data)
+ if k==nil then
+ error("Invalid AceSerializer table format (no table end marker)")
+ end
+ ctl,data = iter()
+ v = DeserializeValue(iter,true,ctl,data)
+ if v==nil then
+ error("Invalid AceSerializer table format (no table end marker)")
+ end
+ res[k]=v
+ end
+ else
+ error("Invalid AceSerializer control code '"..ctl.."'")
+ end
+
+ if not single then
+ return res,DeserializeValue(iter)
+ else
+ return res
+ end
+end
+
+--- Deserializes the data into its original values.
+-- Accepts serialized data, ignoring all control characters and whitespace.
+-- @param str The serialized data (from :Serialize)
+-- @return true followed by a list of values, OR false followed by an error message
+function AceSerializer:Deserialize(str)
+ str = gsub(str, "[%c ]", "") -- ignore all control characters; nice for embedding in email and stuff
+
+ local iter = gmatch(str, "(^.)([^^]*)") -- Any ^x followed by string of non-^
+ local ctl,data = iter()
+ if not ctl or ctl~="^1" then
+ -- we purposefully ignore the data portion of the start code, it can be used as an extension mechanism
+ return false, "Supplied data is not AceSerializer data (rev 1)"
+ end
+
+ return pcall(DeserializeValue, iter)
+end
+
+
+----------------------------------------
+-- Base library stuff
+----------------------------------------
+
+AceSerializer.internals = { -- for test scripts
+ SerializeValue = SerializeValue,
+ SerializeStringHelper = SerializeStringHelper,
+}
+
+local mixins = {
+ "Serialize",
+ "Deserialize",
+}
+
+AceSerializer.embeds = AceSerializer.embeds or {}
+
+function AceSerializer:Embed(target)
+ for k, v in pairs(mixins) do
+ target[v] = self[v]
+ end
+ self.embeds[target] = true
+ return target
+end
+
+-- Update embeds
+for target, v in pairs(AceSerializer.embeds) do
+ AceSerializer:Embed(target)
+end
diff --git a/ElvUI/Libraries/Ace3/AceSerializer-3.0/AceSerializer-3.0.xml b/ElvUI/Libraries/Ace3/AceSerializer-3.0/AceSerializer-3.0.xml
new file mode 100644
index 0000000..94924af
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceSerializer-3.0/AceSerializer-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/Ace3/AceTimer-3.0/AceTimer-3.0.lua b/ElvUI/Libraries/Ace3/AceTimer-3.0/AceTimer-3.0.lua
new file mode 100644
index 0000000..f2304b4
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceTimer-3.0/AceTimer-3.0.lua
@@ -0,0 +1,327 @@
+--- **AceTimer-3.0** provides a central facility for registering timers.
+-- AceTimer supports one-shot timers and repeating timers. All timers are stored in an efficient
+-- data structure that allows easy dispatching and fast rescheduling. Timers can be registered
+-- or canceled at any time, even from within a running timer, without conflict or large overhead.\\
+-- AceTimer is currently limited to firing timers at a frequency of 0.01s.
+--
+-- All `:Schedule` functions will return a handle to the current timer, which you will need to store if you
+-- need to cancel the timer you just registered.
+--
+-- **AceTimer-3.0** can be embeded into your addon, either explicitly by calling AceTimer:Embed(MyAddon) or by
+-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
+-- and can be accessed directly, without having to explicitly call AceTimer itself.\\
+-- It is recommended to embed AceTimer, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceTimer.
+-- @class file
+-- @name AceTimer-3.0
+-- @release $Id$
+
+local MAJOR, MINOR = "AceTimer-3.0", 1017 -- Bump minor on changes
+local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceTimer then return end -- No upgrade needed
+AceTimer.frame = AceTimer.frame or CreateFrame("Frame", "AceTimer30Frame")
+AceTimer.activeTimers = AceTimer.activeTimers or {} -- Active timer list
+local activeTimers = AceTimer.activeTimers -- Upvalue our private data
+
+-- Lua APIs
+local assert, loadstring, rawset, tconcat = assert, loadstring, rawset, table.concat
+local type, unpack, next, error, select = type, unpack, next, error, select
+-- WoW APIs
+local GetTime = GetTime
+
+--[[
+ xpcall safecall implementation
+]]
+local xpcall = xpcall
+
+local function errorhandler(err)
+ return geterrorhandler()(err)
+end
+
+local function CreateDispatcher(argCount)
+ local code = [[
+ local xpcall, eh = ...
+ local method, ARGS
+ local function call() return method(ARGS) end
+
+ local function dispatch(func, ...)
+ method = func
+ if not method then return end
+ ARGS = ...
+ return xpcall(call, eh)
+ end
+
+ return dispatch
+ ]]
+
+ local ARGS = {}
+ for i = 1, argCount do ARGS[i] = "arg"..i end
+ code = code:gsub("ARGS", tconcat(ARGS, ", "))
+ return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
+end
+
+local Dispatchers = setmetatable({}, {__index=function(self, argCount)
+ local dispatcher = CreateDispatcher(argCount)
+ rawset(self, argCount, dispatcher)
+ return dispatcher
+end})
+Dispatchers[0] = function(func)
+ return xpcall(func, errorhandler)
+end
+
+local function safecall(func, ...)
+ return Dispatchers[select("#", ...)](func, ...)
+end
+
+local function new(self, loop, func, delay, ...)
+ if delay < 0.01 then
+ delay = 0.01 -- Restrict to the lowest time
+ end
+
+ local timer = {
+ object = self,
+ func = func,
+ looping = loop,
+ argsCount = select("#", ...),
+ delay = delay,
+ timeleft = delay,
+ ends = GetTime() + delay,
+ ...
+ }
+
+ activeTimers[timer] = timer
+
+ return timer
+end
+
+--- Schedule a new one-shot timer.
+-- The timer will fire once in `delay` seconds, unless canceled before.
+-- @param callback Callback function for the timer pulse (funcref or method name).
+-- @param delay Delay for the timer, in seconds.
+-- @param ... An optional, unlimited amount of arguments to pass to the callback function.
+-- @usage
+-- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
+--
+-- function MyAddOn:OnEnable()
+-- self:ScheduleTimer("TimerFeedback", 5)
+-- end
+--
+-- function MyAddOn:TimerFeedback()
+-- print("5 seconds passed")
+-- end
+function AceTimer:ScheduleTimer(func, delay, ...)
+ if not func or not delay then
+ error(MAJOR..": ScheduleTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
+ end
+ if type(func) == "string" then
+ if type(self) ~= "table" then
+ error(MAJOR..": ScheduleTimer(callback, delay, args...): 'self' - must be a table.", 2)
+ elseif not self[func] then
+ error(MAJOR..": ScheduleTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
+ end
+ end
+ return new(self, nil, func, delay, ...)
+end
+
+--- Schedule a repeating timer.
+-- The timer will fire every `delay` seconds, until canceled.
+-- @param callback Callback function for the timer pulse (funcref or method name).
+-- @param delay Delay for the timer, in seconds.
+-- @param ... An optional, unlimited amount of arguments to pass to the callback function.
+-- @usage
+-- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
+--
+-- function MyAddOn:OnEnable()
+-- self.timerCount = 0
+-- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5)
+-- end
+--
+-- function MyAddOn:TimerFeedback()
+-- self.timerCount = self.timerCount + 1
+-- print(("%d seconds passed"):format(5 * self.timerCount))
+-- -- run 30 seconds in total
+-- if self.timerCount == 6 then
+-- self:CancelTimer(self.testTimer)
+-- end
+-- end
+function AceTimer:ScheduleRepeatingTimer(func, delay, ...)
+ if not func or not delay then
+ error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
+ end
+ if type(func) == "string" then
+ if type(self) ~= "table" then
+ error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'self' - must be a table.", 2)
+ elseif not self[func] then
+ error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
+ end
+ end
+ return new(self, true, func, delay, ...)
+end
+
+--- Cancels a timer with the given id, registered by the same addon object as used for `:ScheduleTimer`
+-- Both one-shot and repeating timers can be canceled with this function, as long as the `id` is valid
+-- and the timer has not fired yet or was canceled before.
+-- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
+function AceTimer:CancelTimer(id)
+ local timer = activeTimers[id]
+
+ if not timer then
+ return false
+ else
+ timer.cancelled = true
+ activeTimers[id] = nil
+ return true
+ end
+end
+
+--- Cancels all timers registered to the current addon object ('self')
+function AceTimer:CancelAllTimers()
+ for k,v in next, activeTimers do
+ if v.object == self then
+ AceTimer.CancelTimer(self, k)
+ end
+ end
+end
+
+--- Returns the time left for a timer with the given id, registered by the current addon object ('self').
+-- This function will return 0 when the id is invalid.
+-- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
+-- @return The time left on the timer.
+function AceTimer:TimeLeft(id)
+ local timer = activeTimers[id]
+ if not timer then
+ return 0
+ else
+ return timer.ends - GetTime()
+ end
+end
+
+
+-- ---------------------------------------------------------------------
+-- Upgrading
+
+-- Upgrade from old hash-bucket based timers to C_Timer.After timers.
+if oldminor and oldminor < 10 then
+ -- disable old timer logic
+ AceTimer.frame:SetScript("OnUpdate", nil)
+ AceTimer.frame:SetScript("OnEvent", nil)
+ AceTimer.frame:UnregisterAllEvents()
+ -- convert timers
+ for object,timers in next, AceTimer.selfs do
+ for handle,timer in next, timers do
+ if type(timer) == "table" and timer.callback then
+ local newTimer
+ if timer.delay then
+ newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.callback, timer.delay, timer.arg)
+ else
+ newTimer = AceTimer.ScheduleTimer(timer.object, timer.callback, timer.when - GetTime(), timer.arg)
+ end
+ -- Use the old handle for old timers
+ activeTimers[newTimer] = nil
+ activeTimers[handle] = newTimer
+ newTimer.handle = handle
+ end
+ end
+ end
+ AceTimer.selfs = nil
+ AceTimer.hash = nil
+ AceTimer.debug = nil
+elseif oldminor and oldminor < 17 then
+ -- Upgrade from old animation based timers to C_Timer.After timers.
+ AceTimer.inactiveTimers = nil
+ local oldTimers = AceTimer.activeTimers
+ -- Clear old timer table and update upvalue
+ AceTimer.activeTimers = {}
+ activeTimers = AceTimer.activeTimers
+ for handle, timer in next, oldTimers do
+ local newTimer
+ -- Stop the old timer animation
+ local duration, elapsed = timer:GetDuration(), timer:GetElapsed()
+ timer:GetParent():Stop()
+ if timer.looping then
+ newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.func, duration, unpack(timer.args, 1, timer.argsCount))
+ else
+ newTimer = AceTimer.ScheduleTimer(timer.object, timer.func, duration - elapsed, unpack(timer.args, 1, timer.argsCount))
+ end
+ -- Use the old handle for old timers
+ activeTimers[newTimer] = nil
+ activeTimers[handle] = newTimer
+ newTimer.handle = handle
+ end
+
+ -- Migrate transitional handles
+ if oldminor < 13 and AceTimer.hashCompatTable then
+ for handle, id in next, AceTimer.hashCompatTable do
+ local t = activeTimers[id]
+ if t then
+ activeTimers[id] = nil
+ activeTimers[handle] = t
+ t.handle = handle
+ end
+ end
+ AceTimer.hashCompatTable = nil
+ end
+end
+
+-- ---------------------------------------------------------------------
+-- Embed handling
+
+AceTimer.embeds = AceTimer.embeds or {}
+
+local mixins = {
+ "ScheduleTimer", "ScheduleRepeatingTimer",
+ "CancelTimer", "CancelAllTimers",
+ "TimeLeft"
+}
+
+function AceTimer:Embed(target)
+ AceTimer.embeds[target] = true
+ for _,v in next, mixins do
+ target[v] = AceTimer[v]
+ end
+ return target
+end
+
+-- AceTimer:OnEmbedDisable(target)
+-- target (object) - target object that AceTimer is embedded in.
+--
+-- cancel all timers registered for the object
+function AceTimer:OnEmbedDisable(target)
+ target:CancelAllTimers()
+end
+
+for addon in next, AceTimer.embeds do
+ AceTimer:Embed(addon)
+end
+
+AceTimer.frame:SetScript("OnUpdate", function(self, elapsed)
+ for _, timer in next, activeTimers do
+ if not timer.cancelled then
+ if timer.timeleft > elapsed then
+ timer.timeleft = timer.timeleft - elapsed
+ else
+ if type(timer.func) == "string" then
+ -- We manually set the unpack count to prevent issues with an arg set that contains nil and ends with nil
+ -- e.g. local t = {1, 2, nil, 3, nil} print(#t) will result in 2, instead of 5. This fixes said issue.
+ safecall(timer.object[timer.func], timer.object, unpack(timer, 1, timer.argsCount))
+ else
+ safecall(timer.func, unpack(timer, 1, timer.argsCount))
+ end
+
+ if timer.looping and not timer.cancelled then
+ -- Compensate delay to get a perfect average delay, even if individual times don't match up perfectly
+ -- due to fps differences
+ local time = GetTime()
+ local delay = timer.delay - (time - timer.ends)
+ -- Ensure the delay doesn't go below the threshold
+ if delay < 0.01 then delay = 0.01 end
+ timer.ends = time + delay
+ timer.timeleft = timer.delay
+ else
+ activeTimers[timer.handle or timer] = nil
+ end
+ end
+ end
+ end
+end)
\ No newline at end of file
diff --git a/ElvUI/Libraries/Ace3/AceTimer-3.0/AceTimer-3.0.xml b/ElvUI/Libraries/Ace3/AceTimer-3.0/AceTimer-3.0.xml
new file mode 100644
index 0000000..38e9021
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/AceTimer-3.0/AceTimer-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/Ace3/CallbackHandler-1.0/CallbackHandler-1.0.lua b/ElvUI/Libraries/Ace3/CallbackHandler-1.0/CallbackHandler-1.0.lua
new file mode 100644
index 0000000..2a64013
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/CallbackHandler-1.0/CallbackHandler-1.0.lua
@@ -0,0 +1,238 @@
+--[[ $Id: CallbackHandler-1.0.lua 18 2014-10-16 02:52:20Z mikk $ ]]
+local MAJOR, MINOR = "CallbackHandler-1.0", 6
+local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not CallbackHandler then return end -- No upgrade needed
+
+local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
+
+-- Lua APIs
+local tconcat = table.concat
+local assert, error, loadstring = assert, error, loadstring
+local setmetatable, rawset, rawget = setmetatable, rawset, rawget
+local next, select, pairs, type, tostring = next, select, pairs, type, tostring
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: geterrorhandler
+
+local xpcall = xpcall
+
+local function errorhandler(err)
+ return geterrorhandler()(err)
+end
+
+local function CreateDispatcher(argCount)
+ local code = [[
+ local next, xpcall, eh = ...
+
+ local method, ARGS
+ local function call() method(ARGS) end
+
+ local function dispatch(handlers, ...)
+ local index
+ index, method = next(handlers)
+ if not method then return end
+ local OLD_ARGS = ARGS
+ ARGS = ...
+ repeat
+ xpcall(call, eh)
+ index, method = next(handlers, index)
+ until not method
+ ARGS = OLD_ARGS
+ end
+
+ return dispatch
+ ]]
+
+ local ARGS, OLD_ARGS = {}, {}
+ for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end
+ code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", "))
+ return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler)
+end
+
+local Dispatchers = setmetatable({}, {__index=function(self, argCount)
+ local dispatcher = CreateDispatcher(argCount)
+ rawset(self, argCount, dispatcher)
+ return dispatcher
+end})
+
+--------------------------------------------------------------------------
+-- CallbackHandler:New
+--
+-- target - target object to embed public APIs in
+-- RegisterName - name of the callback registration API, default "RegisterCallback"
+-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
+-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
+
+function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName)
+
+ RegisterName = RegisterName or "RegisterCallback"
+ UnregisterName = UnregisterName or "UnregisterCallback"
+ if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
+ UnregisterAllName = "UnregisterAllCallbacks"
+ end
+
+ -- we declare all objects and exported APIs inside this closure to quickly gain access
+ -- to e.g. function names, the "target" parameter, etc
+
+
+ -- Create the registry object
+ local events = setmetatable({}, meta)
+ local registry = { recurse=0, events=events }
+
+ -- registry:Fire() - fires the given event/message into the registry
+ function registry:Fire(eventname, ...)
+ if not rawget(events, eventname) or not next(events[eventname]) then return end
+ local oldrecurse = registry.recurse
+ registry.recurse = oldrecurse + 1
+
+ Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...)
+
+ registry.recurse = oldrecurse
+
+ if registry.insertQueue and oldrecurse==0 then
+ -- Something in one of our callbacks wanted to register more callbacks; they got queued
+ for eventname,callbacks in pairs(registry.insertQueue) do
+ local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
+ for self,func in pairs(callbacks) do
+ events[eventname][self] = func
+ -- fire OnUsed callback?
+ if first and registry.OnUsed then
+ registry.OnUsed(registry, target, eventname)
+ first = nil
+ end
+ end
+ end
+ registry.insertQueue = nil
+ end
+ end
+
+ -- Registration of a callback, handles:
+ -- self["method"], leads to self["method"](self, ...)
+ -- self with function ref, leads to functionref(...)
+ -- "addonId" (instead of self) with function ref, leads to functionref(...)
+ -- all with an optional arg, which, if present, gets passed as first argument (after self if present)
+ target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
+ if type(eventname) ~= "string" then
+ error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
+ end
+
+ method = method or eventname
+
+ local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
+
+ if type(method) ~= "string" and type(method) ~= "function" then
+ error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
+ end
+
+ local regfunc
+
+ if type(method) == "string" then
+ -- self["method"] calling style
+ if type(self) ~= "table" then
+ error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
+ elseif self==target then
+ error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
+ elseif type(self[method]) ~= "function" then
+ error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
+ end
+
+ if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
+ local arg=select(1,...)
+ regfunc = function(...) self[method](self,arg,...) end
+ else
+ regfunc = function(...) self[method](self,...) end
+ end
+ else
+ -- function ref with self=object or self="addonId" or self=thread
+ if type(self)~="table" and type(self)~="string" and type(self)~="thread" then
+ error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2)
+ end
+
+ if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
+ local arg=select(1,...)
+ regfunc = function(...) method(arg,...) end
+ else
+ regfunc = method
+ end
+ end
+
+
+ if events[eventname][self] or registry.recurse<1 then
+ -- if registry.recurse<1 then
+ -- we're overwriting an existing entry, or not currently recursing. just set it.
+ events[eventname][self] = regfunc
+ -- fire OnUsed callback?
+ if registry.OnUsed and first then
+ registry.OnUsed(registry, target, eventname)
+ end
+ else
+ -- we're currently processing a callback in this registry, so delay the registration of this new entry!
+ -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
+ registry.insertQueue = registry.insertQueue or setmetatable({},meta)
+ registry.insertQueue[eventname][self] = regfunc
+ end
+ end
+
+ -- Unregister a callback
+ target[UnregisterName] = function(self, eventname)
+ if not self or self==target then
+ error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
+ end
+ if type(eventname) ~= "string" then
+ error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
+ end
+ if rawget(events, eventname) and events[eventname][self] then
+ events[eventname][self] = nil
+ -- Fire OnUnused callback?
+ if registry.OnUnused and not next(events[eventname]) then
+ registry.OnUnused(registry, target, eventname)
+ end
+ end
+ if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
+ registry.insertQueue[eventname][self] = nil
+ end
+ end
+
+ -- OPTIONAL: Unregister all callbacks for given selfs/addonIds
+ if UnregisterAllName then
+ target[UnregisterAllName] = function(...)
+ if select("#",...)<1 then
+ error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
+ end
+ if select("#",...)==1 and ...==target then
+ error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
+ end
+
+
+ for i=1,select("#",...) do
+ local self = select(i,...)
+ if registry.insertQueue then
+ for eventname, callbacks in pairs(registry.insertQueue) do
+ if callbacks[self] then
+ callbacks[self] = nil
+ end
+ end
+ end
+ for eventname, callbacks in pairs(events) do
+ if callbacks[self] then
+ callbacks[self] = nil
+ -- Fire OnUnused callback?
+ if registry.OnUnused and not next(callbacks) then
+ registry.OnUnused(registry, target, eventname)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ return registry
+end
+
+
+-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
+-- try to upgrade old implicit embeds since the system is selfcontained and
+-- relies on closures to work.
+
diff --git a/ElvUI/Libraries/Ace3/LibStub/LibStub.lua b/ElvUI/Libraries/Ace3/LibStub/LibStub.lua
new file mode 100644
index 0000000..cf5c842
--- /dev/null
+++ b/ElvUI/Libraries/Ace3/LibStub/LibStub.lua
@@ -0,0 +1,51 @@
+-- $Id: LibStub.lua 103 2014-10-16 03:02:50Z mikk $
+-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/addons/libstub/ for more info
+-- LibStub is hereby placed in the Public Domain
+-- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
+local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
+local LibStub = _G[LIBSTUB_MAJOR]
+
+-- Check to see is this version of the stub is obsolete
+if not LibStub or LibStub.minor < LIBSTUB_MINOR then
+ LibStub = LibStub or {libs = {}, minors = {} }
+ _G[LIBSTUB_MAJOR] = LibStub
+ LibStub.minor = LIBSTUB_MINOR
+
+ -- LibStub:NewLibrary(major, minor)
+ -- major (string) - the major version of the library
+ -- minor (string or number ) - the minor version of the library
+ --
+ -- returns nil if a newer or same version of the lib is already present
+ -- returns empty library object or old library object if upgrade is needed
+ function LibStub:NewLibrary(major, minor)
+ assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
+ minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
+
+ local oldminor = self.minors[major]
+ if oldminor and oldminor >= minor then return nil end
+ self.minors[major], self.libs[major] = minor, self.libs[major] or {}
+ return self.libs[major], oldminor
+ end
+
+ -- LibStub:GetLibrary(major, [silent])
+ -- major (string) - the major version of the library
+ -- silent (boolean) - if true, library is optional, silently return nil if its not found
+ --
+ -- throws an error if the library can not be found (except silent is set)
+ -- returns the library object if found
+ function LibStub:GetLibrary(major, silent)
+ if not self.libs[major] and not silent then
+ error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
+ end
+ return self.libs[major], self.minors[major]
+ end
+
+ -- LibStub:IterateLibraries()
+ --
+ -- Returns an iterator for the currently registered libraries
+ function LibStub:IterateLibraries()
+ return pairs(self.libs)
+ end
+
+ setmetatable(LibStub, { __call = LibStub.GetLibrary })
+end
diff --git a/ElvUI/Libraries/HealPredict/healpredict.lua b/ElvUI/Libraries/HealPredict/healpredict.lua
new file mode 100644
index 0000000..5a03c9b
--- /dev/null
+++ b/ElvUI/Libraries/HealPredict/healpredict.lua
@@ -0,0 +1,542 @@
+--[[
+API:
+ * RegisterCallback(addon, callback)
+ `callback` is called whenever some heal state (new heal/ heal stop/ heal delay) changes.
+ callback`'s arguments will be all units affected by the change in heal state, e.g.,
+ `callback("Tankguy", "Dpsguy")`.
+
+ * UnregisterCallback(addon)
+ Remove all callbacks registered by `addon`.
+
+ * UnitGetIncomingHeals(unit[, healer])
+ Return predicted incoming heals on unit. If `healer`, only predict incoming heals from healer.
+]]
+local ADDON_NAME = "HealPredict"
+
+-- Wow API
+local CheckInteractDistance = CheckInteractDistance
+local CreateFrame = CreateFrame
+local GetInventoryItemLink = GetInventoryItemLink
+local GetLocale = GetLocale
+local GetNumRaidMembers = GetNumRaidMembers
+local GetSpellInfo = GetSpellInfo
+local GetTime = GetTime
+local SendAddonMessage = SendAddonMessage
+local strjoin = strjoin
+local strsplit = strsplit
+local UIParent = UIParent
+local UnitBuff = UnitBuff
+local UnitCanAssist =UnitCanAssist
+local UnitCastingInfo = UnitCastingInfo
+local UnitChannelInfo = UnitChannelInfo
+local UnitHealth = UnitHealth
+local UnitHealthMax = UnitHealthMax
+local UnitInRaid = UnitInRaid
+local UnitName = UnitName
+local UnitIsDeadOrGhost = UnitIsDeadOrGhost
+
+-- Addon message constants:
+local HEALSTOP = "HealStop"
+local HEALDELAY = "HealDelay"
+local HEAL = "Heal"
+local SEP = "/"
+
+-- Localize spell names:
+local BEACON_OF_LIGHT
+do
+ local locales = {
+ deDE = "Flamme des Glaubens",
+ enUS = "Beacon of Light",
+ esES = "Señal de la Luz",
+ esMX = "Señal de la Luz",
+ frFR = "Guide de lumière",
+ itIT = "Faro di Luce",
+ koKR = "빛의 봉화",
+ ptBR = "Foco de Luz",
+ ruRU = "Частица Света",
+ zhCN = "圣光道标",
+ zhTW = "聖光信標",
+ }
+
+ BEACON_OF_LIGHT = locales[GetLocale()] or locales.enUS
+end
+
+local CHAIN_HEAL
+do
+ local locales = {
+ deDE = "Kettenheilung",
+ enUS = "Chain Heal",
+ esES = "Sanación en cadena",
+ esMX = "Sanación en cadena",
+ frFR = "Salve de guérison",
+ itIT = "Catena di Guarigione",
+ koKR = "연쇄 치유",
+ ptBR = "Cura Encadeada",
+ ruRU = "Цепное исцеление",
+ zhCN = "治疗链",
+ zhTW = "治療鍊",
+ }
+
+ CHAIN_HEAL = locales[GetLocale()] or locales.enUS
+end
+
+local PRAYER_OF_HEALING
+do
+ local locales = {
+ deDE = "Gebet der Heilung",
+ enUS = "Prayer of Healing",
+ esES = "Rezo de curación",
+ esMX = "Rezo de sanación",
+ frFR = "Prière de soins",
+ itIT = "Preghiera di Cura",
+ koKR = "치유의 기원",
+ ptBR = "Prece de Cura",
+ ruRU = "Молитва исцеления",
+ zhCN = "治疗祷言",
+ zhTW = "治療禱言",
+ }
+
+ PRAYER_OF_HEALING = locales[GetLocale()] or locales.enUS
+end
+
+local PRAYER_OF_PRESERVATION = "Prayer of Preservation"
+
+local TRANQUILITY
+do
+ local locales = {
+ deDE = "Gelassenheit",
+ enUS = "Tranquility",
+ esES = "Tranquilidad",
+ esMX = "Tranquilidad",
+ frFR = "Tranquillité",
+ itIT = "Tranquillità",
+ koKR = "평온",
+ ptBR = "Tranquilidade",
+ ruRU = "Спокойствие",
+ zhCN = "宁静",
+ zhTW = "寧靜",
+ }
+
+ TRANQUILITY = locales[GetLocale()] or locales.enUS
+end
+
+local SMART_HEALS = { }
+SMART_HEALS[TRANQUILITY] = 5
+SMART_HEALS[PRAYER_OF_PRESERVATION] = 5
+SMART_HEALS[CHAIN_HEAL] = 3
+
+-- Addon locals
+local player = UnitName("player")
+local heals, callbacks, cache, gear_string = { }, { }, { }, ""
+local is_healing, beacon_info, current_target
+
+-- API functions
+local healpredict = CreateFrame("Frame")
+function healpredict.UnitGetIncomingHeals(unit, healer)
+ if UnitIsDeadOrGhost(unit) then return 0 end
+
+ local name = UnitName(unit)
+
+ if not heals[name] then
+ return 0
+ end
+
+ local sumheal, time = 0, GetTime()
+
+ for sender, amount in pairs(heals[name]) do
+ if amount[2] <= time then
+ heals[name][sender] = nil
+ elseif not healer or sender == healer then
+ sumheal = sumheal + amount[1]
+ end
+ end
+
+ return sumheal
+end
+
+function healpredict.RegisterCallback(addon, callback)
+ callbacks[addon] = callback
+end
+
+function healpredict.UnregisterCallback(addon)
+ callbacks[addon] = nil
+end
+
+-- Private functions
+local function UpdateCache(spell, heal)
+ --[[
+ cache total of all heals and number of casts
+ for calculating a rolling average of the heal
+ ]]
+ local heal = tonumber(heal)
+
+ if not cache[spell] then
+ cache[spell] = {heal, 1}
+ else
+ cache[spell][1] = cache[spell][1] + heal
+ cache[spell][2] = cache[spell][2] + 1
+ end
+end
+
+local function handleCallbacks(...)
+ for _, v in pairs(callbacks) do
+ v(...)
+ end
+end
+
+local function Heal(sender, target, amount, duration)
+ heals[target] = heals[target] or { }
+ heals[target][sender] = {amount, GetTime() + duration / 1000}
+
+ handleCallbacks(target)
+end
+
+local function HealStop(sender)
+ local affected = { }
+ for target, _ in pairs(heals) do
+ for tsender in pairs(heals[target]) do
+ if sender == tsender then
+ heals[target][tsender] = nil
+ table.insert(affected, target)
+ end
+ end
+ end
+
+ handleCallbacks(unpack(affected))
+end
+
+local function HealDelay(sender, delay)
+ if type(delay) ~= "string" then
+ local delay = delay / 1000
+ local affected = { }
+ for target, _ in pairs(heals) do
+ for tsender, amount in pairs(heals[target]) do
+ if sender == tsender then
+ amount[2] = amount[2] + delay
+ table.insert(affected, target)
+ end
+ end
+ end
+ handleCallbacks(unpack(affected))
+ end
+end
+
+local function SendHealMsg(msg)
+ SendAddonMessage(ADDON_NAME, msg, "RAID")
+ SendAddonMessage(ADDON_NAME, msg, "BATTLEGROUND")
+end
+
+local function max(targets)
+ local currentmax = -1
+ local raidname
+
+ for name, pct in pairs(targets) do
+ if pct > currentmax then
+ currentmax = pct
+ raidname = name
+ end
+ end
+
+ return raidname
+end
+
+local function BeaconTarget()
+ if beacon_info then
+ local beacon_target, endtime = unpack(beacon_info)
+ if endtime > GetTime() then
+ beacon_info = nil
+ else
+ return beacon_target
+ end
+ end
+end
+
+local function GroupHeal(amount, casttime)
+ local partyN, partyname, beacon_found
+ local beacon_target = BeaconTarget()
+
+ for i=1,4 do
+ partyN = "party"..i
+
+ if CheckInteractDistance(partyN, 4) then
+ partyname = (UnitName(partyN))
+ if beacon_target and partyname == beacon_target then
+ beacon_found = true
+ Heal(player, partyname, amount * 1.4, casttime)
+ SendHealMsg(strjoin(SEP, HEAL, partyname, amount * 1.4, casttime))
+ elseif partyname then
+ Heal(player, partyname, amount, casttime)
+ SendHealMsg(strjoin(SEP, HEAL, partyname, amount, casttime))
+ end
+ end
+ end
+
+ if beacon_target and not beacon_found then
+ Heal(player, beacon_target, amount * .4, casttime)
+ SendHealMsg(strjoin(SEP, HEAL, beacon_target, amount * .4, casttime))
+ end
+
+ Heal(player, player, amount, casttime)
+ SendHealMsg(strjoin(SEP, HEAL, player, amount, casttime))
+end
+
+local function SmartHeal(amount, casttime, n)
+ if not UnitInRaid("player") then
+ return GroupHeal(amount, casttime)
+ end
+
+ local beacon_target = BeaconTarget()
+ local beacon_found
+
+ local healthpct, currentmax
+ local pcts = { }
+ local raidN, raidname
+
+ for i=1,GetNumRaidMembers() do
+ raidN = "raid"..i
+
+ if not UnitIsDeadOrGhost(raidN) and CheckInteractDistance(raidN, 4) then
+ raidname = (UnitName(raidN))
+ healthpct = UnitHealth(raidN) / UnitHealthMax(raidname)
+
+ if #pcts < n then
+ pcts[raidname] = healthpct
+
+ if not currentmax or healthpct > pcts[currentmax] then
+ currentmax = raidname
+ end
+
+ elseif healthpct < pcts[currentmax] then
+ pcts[currentmax] = nil
+ pcts[raidname] = healthpct
+ currentmax = max(pcts)
+ end
+ end
+ end
+
+ for target, _ in pairs(pcts) do
+ if beacon_target and target == beacon_target then
+ beacon_found = true
+ Heal(player, target, amount * 1.4, casttime)
+ SendHealMsg(strjoin(SEP, HEAL, target, amount * 1.4, casttime))
+ else
+ Heal(player, target, amount, casttime)
+ SendHealMsg(strjoin(SEP, HEAL, target, amount, casttime))
+ end
+ end
+
+ if beacon_target and not beacon_found then
+ Heal(player, beacon_target, amount * .4, casttime)
+ SendHealMsg(strjoin(SEP, HEAL, beacon_target, amount * .4, casttime))
+ end
+end
+
+local function UnitByName(name)
+ if name == player then
+ return "player"
+ end
+
+ local unit
+
+ if UnitInRaid("player") then
+ for i=1,GetNumRaidMembers() do
+ unit = "raid"..i
+
+ if (UnitName(unit)) == name then
+ return unit
+ end
+ end
+ end
+
+ for i=1,4 do
+ unit = "party"..i
+
+ if (UnitName(unit)) == name then
+ return unit
+ end
+ end
+end
+
+-- Message passing
+healpredict:RegisterEvent("CHAT_MSG_ADDON")
+healpredict:SetScript("OnEvent", function(_, _, prefix, msg, _, sender)
+ if prefix == ADDON_NAME then
+ local command, target_or_delay, amount, casttime = strsplit(SEP, msg)
+ if command == HEALSTOP then
+ HealStop(sender)
+ elseif command == HEAL then
+ Heal(sender, target_or_delay, amount, casttime)
+ elseif command == HEALDELAY then
+ HealDelay(sender, target_or_delay)
+ end
+ end
+end)
+
+-- Reset cache on skill or inventory change
+local resetcache = CreateFrame("Frame")
+resetcache:RegisterEvent("SKILL_LINES_CHANGED")
+resetcache:RegisterEvent("UNIT_INVENTORY_CHANGED")
+resetcache:SetScript("OnEvent", function(_, event, player)
+ if player ~= "player" then
+ return
+ end
+
+ if event == "UNIT_INVENTORY_CHANGED" then
+ local gear = ""
+ for id = 1, 18 do
+ gear = gear .. (GetInventoryItemLink("player",id) or "")
+ end
+
+ if gear == gear_string then
+ return
+ end
+
+ gear_string = gear
+ end
+
+ -- reset cache
+ cache = { }
+end)
+
+--Event handling
+----------------
+local eventhandler = CreateFrame("Frame", ADDON_NAME .. "EventHandler", UIParent)
+
+eventhandler:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+function eventhandler.COMBAT_LOG_EVENT_UNFILTERED(_, subevent, _, sourcename, _, _, destname, _, spellid, spellname, _, amount)
+ if sourcename ~= player then return end
+
+ if subevent == "SPELL_HEAL" then
+ local _, rank = GetSpellInfo(spellid)
+ local spellrank = spellname..(rank or "")
+ UpdateCache(spellrank, amount)
+
+ if spellname == TRANQUILITY then
+ -- Need to re-acquire tranq targets
+ HealStop(player)
+ SendHealMsg(HEALSTOP)
+
+ local _, _, _, _, starttime, endtime = UnitChannelInfo("player")
+ if starttime ~= nil and endtime ~= nil then
+ local casttime = endtime - starttime
+
+ local total, casts = unpack(cache[spellrank])
+ local amount = total / casts
+
+ SmartHeal(amount, casttime, 5)
+ is_healing = true
+ end
+ end
+ elseif spellname == BEACON_OF_LIGHT then
+ if subevent == "SPELL_AURA_APPLIED" then
+ local unit = UnitByName(destname)
+
+ if not unit then
+ return
+ end
+
+ for i=1,40 do
+ local buff, _, _, _, _, endtime = UnitBuff(unit, i)
+ if buff == BEACON_OF_LIGHT then
+ beacon_info = {destname, endtime}
+ break
+ end
+ end
+
+ elseif subevent == "SPELL_AURA_REMOVED" then
+ beacon_info = nil
+ end
+ end
+end
+
+eventhandler:RegisterEvent("UNIT_SPELLCAST_SENT")
+function eventhandler.UNIT_SPELLCAST_SENT(unit, _, _, target)
+ if unit == "player" then
+ if target == "" then
+ current_target = UnitCanAssist("player", "target") and UnitName("target") or player
+ else
+ current_target = target
+ end
+ end
+end
+
+eventhandler:RegisterEvent("UNIT_SPELLCAST_START")
+function eventhandler.UNIT_SPELLCAST_START(unit)
+ if unit ~= "player" then return end
+
+ local spell, rank, _, _, starttime, endtime = UnitCastingInfo("player")
+ if not spell then
+ spell, rank, _, _, starttime, endtime = UnitChannelInfo("player")
+ end
+ local casttime = endtime - starttime
+ local spellrank = spell..(rank or "")
+
+ if cache[spellrank] then
+ local total, casts = unpack(cache[spellrank])
+ local amount = total / casts
+
+ if spell == PRAYER_OF_HEALING then
+ GroupHeal(amount, casttime)
+ elseif SMART_HEALS[spell] then
+ SmartHeal(amount, casttime, SMART_HEALS[spell])
+ else
+ local beacon_target = BeaconTarget()
+
+ if beacon_target then
+ if beacon_target ~= current_target then
+ Heal(player, current_target, amount, casttime)
+ SendHealMsg(strjoin(SEP, HEAL, current_target, amount, casttime))
+
+ Heal(player, beacon_target, amount * .4, casttime)
+ SendHealMsg(strjoin(SEP, HEAL, beacon_target, amount * .4, casttime))
+ else
+ Heal(player, beacon_target, amount * 1.4, casttime)
+ SendHealMsg(strjoin(SEP, HEAL, beacon_target, amount * 1.4, casttime))
+ end
+ else
+ Heal(player, current_target, amount, casttime)
+ SendHealMsg(strjoin(SEP, HEAL, current_target, amount, casttime))
+ end
+ end
+
+ is_healing = true
+ end
+end
+
+eventhandler:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
+eventhandler.UNIT_SPELLCAST_CHANNEL_START = eventhandler.UNIT_SPELLCAST_START
+
+eventhandler:RegisterEvent("UNIT_SPELLCAST_FAILED")
+function eventhandler.UNIT_SPELLCAST_FAILED(unit)
+ if is_healing and unit == "player" then
+ HealStop(player)
+ SendHealMsg(HEALSTOP)
+ is_healing = nil
+ end
+end
+
+eventhandler:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
+eventhandler.UNIT_SPELLCAST_INTERRUPTED = eventhandler.UNIT_SPELLCAST_FAILED
+
+eventhandler:RegisterEvent("UNIT_SPELLCAST_STOP")
+eventhandler.UNIT_SPELLCAST_STOP = eventhandler.UNIT_SPELLCAST_FAILED
+
+eventhandler:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
+eventhandler.UNIT_SPELLCAST_CHANNEL_STOP = eventhandler.UNIT_SPELLCAST_FAILED
+
+eventhandler:RegisterEvent("UNIT_SPELLCAST_DELAYED")
+function eventhandler.UNIT_SPELLCAST_DELAYED(unit, delay)
+ if is_healing and unit == "player" then
+ HealDelay(player, delay)
+ SendHealMsg(strjoin(SEP, HEALDELAY, delay))
+ end
+end
+
+eventhandler:SetScript("OnEvent", function(_, event, ...)
+ local handler = eventhandler[event]
+ if handler then
+ handler(...)
+ end
+end)
+
+_G[ADDON_NAME] = healpredict
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibActionButton-1.0/LibActionButton-1.0.lua b/ElvUI/Libraries/LibActionButton-1.0/LibActionButton-1.0.lua
new file mode 100644
index 0000000..47d4ebd
--- /dev/null
+++ b/ElvUI/Libraries/LibActionButton-1.0/LibActionButton-1.0.lua
@@ -0,0 +1,1297 @@
+--[[
+Copyright (c) 2010-2016, Hendrik "nevcairiel" Leppkes
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the developer nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+]]
+local MAJOR_VERSION = "LibActionButton-1.0-ElvUI"
+local MINOR_VERSION = 66
+
+if not LibStub then error(MAJOR_VERSION .. " requires LibStub.") end
+local lib, oldversion = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION)
+if not lib then return end
+
+local _G = _G
+local type, error, tostring, tonumber, assert, select = type, error, tostring, tonumber, assert, select
+local setmetatable, wipe, unpack, pairs, next = setmetatable, wipe, unpack, pairs, next
+local match, format = string.match, format
+
+local KeyBound = LibStub("LibKeyBound-1.0", true)
+local CBH = LibStub("CallbackHandler-1.0")
+
+lib.eventFrame = lib.eventFrame or CreateFrame("Frame")
+lib.eventFrame:UnregisterAllEvents()
+
+lib.buttonRegistry = lib.buttonRegistry or {}
+lib.activeButtons = lib.activeButtons or {}
+lib.actionButtons = lib.actionButtons or {}
+lib.nonActionButtons = lib.nonActionButtons or {}
+
+lib.callbacks = lib.callbacks or CBH:New(lib)
+
+local Generic = CreateFrame("CheckButton")
+local Generic_MT = {__index = Generic}
+
+local Action = setmetatable({}, {__index = Generic})
+local Action_MT = {__index = Action}
+
+local PetAction = setmetatable({}, {__index = Generic})
+local PetAction_MT = {__index = PetAction}
+
+local Spell = setmetatable({}, {__index = Generic})
+local Spell_MT = {__index = Spell}
+
+local Item = setmetatable({}, {__index = Generic})
+local Item_MT = {__index = Item}
+
+local Macro = setmetatable({}, {__index = Generic})
+local Macro_MT = {__index = Macro}
+
+local Custom = setmetatable({}, {__index = Generic})
+local Custom_MT = {__index = Custom}
+
+local type_meta_map = {
+ empty = Generic_MT,
+ action = Action_MT,
+ --pet = PetAction_MT,
+ spell = Spell_MT,
+ item = Item_MT,
+ macro = Macro_MT,
+ custom = Custom_MT
+}
+
+local ButtonRegistry, ActiveButtons, ActionButtons, NonActionButtons = lib.buttonRegistry, lib.activeButtons, lib.actionButtons, lib.nonActionButtons
+
+local Update, UpdateButtonState, UpdateUsable, UpdateCount, UpdateCooldown, UpdateTooltip
+local StartFlash, StopFlash, UpdateFlash, UpdateHotkeys, UpdateRangeTimer
+local ShowGrid, HideGrid, UpdateGrid, SetupSecureSnippets, WrapOnClick
+local UpdateRange -- Sezz: new method
+
+local InitializeEventHandler, OnEvent, ForAllButtons, OnUpdate
+
+local DefaultConfig = {
+ outOfRangeColoring = "button",
+ tooltip = "enabled",
+ showGrid = false,
+ useColoring = true,
+ colors = {
+ range = { 0.8, 0.1, 0.1 },
+ mana = { 0.5, 0.5, 1.0 },
+ usable = { 1.0, 1.0, 1.0 },
+ notUsable = { 0.4, 0.4, 0.4 }
+ },
+ hideElements = {
+ macro = false,
+ hotkey = false,
+ equipped = false,
+ },
+ keyBoundTarget = false,
+ clickOnDown = false,
+}
+
+--- Create a new action button.
+-- @param id Internal id of the button (not used by LibActionButton-1.0, only for tracking inside the calling addon)
+-- @param name Name of the button frame to be created (not used by LibActionButton-1.0 aside from naming the frame)
+-- @param header Header that drives these action buttons (if any)
+function lib:CreateButton(id, name, header, config)
+ if type(name) ~= "string" then
+ error("Usage: CreateButton(id, name. header): Buttons must have a valid name!", 2)
+ end
+ if not header then
+ error("Usage: CreateButton(id, name, header): Buttons without a secure header are not yet supported!", 2)
+ end
+
+ if not KeyBound then
+ KeyBound = LibStub("LibKeyBound-1.0", true)
+ end
+
+ local button = setmetatable(CreateFrame("CheckButton", name, header, "SecureActionButtonTemplate, ActionButtonTemplate"), Generic_MT)
+ button:RegisterForDrag("LeftButton", "RightButton")
+ button:RegisterForClicks("AnyUp")
+
+ -- Frame Scripts
+ button:SetScript("OnEnter", Generic.OnEnter)
+ button:SetScript("OnLeave", Generic.OnLeave)
+ button:SetScript("PreClick", Generic.PreClick)
+ button:SetScript("PostClick", Generic.PostClick)
+
+ button.id = id
+ button.header = header
+ -- Mapping of state -> action
+ button.state_types = {}
+ button.state_actions = {}
+
+ -- Store the LAB Version that created this button for debugging
+ button.__LAB_Version = MINOR_VERSION
+
+ -- just in case we're not run by a header, default to state 0
+ button:SetAttribute("state", 0)
+
+ SetupSecureSnippets(button)
+ WrapOnClick(button)
+
+ -- Store all sub frames on the button object for easier access
+ button.icon = _G[name .. "Icon"]
+ button.flash = _G[name .. "Flash"]
+ button.hotkey = _G[name .. "HotKey"]
+ button.count = _G[name .. "Count"]
+ button.actionName = _G[name .. "Name"]
+ button.border = _G[name .. "Border"]
+ button.cooldown = _G[name .. "Cooldown"]
+ button.normalTexture = _G[name .. "NormalTexture"]
+
+ -- adjust hotkey style for better readability
+ button.hotkey:SetFont(button.hotkey:GetFont(), 13, "OUTLINE")
+ button.hotkey:SetVertexColor(0.75, 0.75, 0.75)
+
+ -- Store the button in the registry, needed for event and OnUpdate handling
+ if not next(ButtonRegistry) then
+ InitializeEventHandler()
+ end
+ ButtonRegistry[button] = true
+
+ button:UpdateConfig(config)
+
+ -- run an initial update
+ button:UpdateAction()
+ UpdateHotkeys(button)
+
+ -- somewhat of a hack for the Flyout buttons to not error.
+ button.action = 0
+
+ lib.callbacks:Fire("OnButtonCreated", button)
+
+ return button
+end
+
+function SetupSecureSnippets(button)
+ button:SetAttribute("_custom", Custom.RunCustom)
+ -- secure UpdateState(self, state)
+ -- update the type and action of the button based on the state
+ button:SetAttribute("UpdateState", [[
+ local state = ...
+ self:SetAttribute("state", state)
+ local type, action = (self:GetAttribute(format("labtype-%s", state)) or "empty"), self:GetAttribute(format("labaction-%s", state))
+
+ self:SetAttribute("type", type)
+ if type ~= "empty" and type ~= "custom" then
+ local action_field = (type == "pet") and "action" or type
+ self:SetAttribute(action_field, action)
+ self:SetAttribute("action_field", action_field)
+ end
+ local onStateChanged = self:GetAttribute("OnStateChanged")
+ if onStateChanged then
+ self:Run(onStateChanged, state, type, action)
+ end
+ ]])
+
+ -- this function is invoked by the header when the state changes
+ button:SetAttribute("_childupdate-state", [[
+ control:RunFor(self, self:GetAttribute("UpdateState"), message)
+ ]])
+
+ -- secure PickupButton(self, kind, value, ...)
+ -- utility function to place a object on the cursor
+ button:SetAttribute("PickupButton", [[
+ local kind, value = ...
+ if kind == "empty" then
+ return "clear"
+ elseif kind == "action" or kind == "pet" then
+ local actionType = (kind == "pet") and "petaction" or kind
+ return actionType, value
+ elseif kind == "spell" or kind == "item" or kind == "macro" then
+ return "clear", kind, value
+ else
+ print("LibActionButton-1.0: Unknown type: " .. tostring(kind))
+ return false
+ end
+ ]]);
+
+ button:SetAttribute("OnDragStart", [[
+ if (self:GetAttribute("buttonlock") and not IsModifiedClick("PICKUPACTION")) or self:GetAttribute("LABdisableDragNDrop") then return false end
+ local state = self:GetAttribute("state")
+ local type = self:GetAttribute("type")
+ -- if the button is empty, we can't drag anything off it
+ if type == "empty" or type == "custom" then
+ return false
+ end
+ -- Get the value for the action attribute
+ local action_field = self:GetAttribute("action_field")
+ local action = self:GetAttribute(action_field)
+
+ -- non-action fields need to change their type to empty
+ if type ~= "action" and type ~= "pet" then
+ self:SetAttribute(format("labtype-%s", state), "empty")
+ self:SetAttribute(format("labaction-%s", state), nil)
+ -- update internal state
+ control:RunFor(self, self:GetAttribute("UpdateState"), state)
+ -- send a notification to the insecure code
+ --self:CallMethod("ButtonContentsChanged", state, "empty", nil)
+ end
+ -- return the button contents for pickup
+ return control:RunFor(self, self:GetAttribute("PickupButton"), type, action)
+ ]])
+
+ button:SetAttribute("OnReceiveDrag", [[
+ if self:GetAttribute("LABdisableDragNDrop") then return false end
+ local kind, value, subtype, extra = ...
+ if not kind or not value then return false end
+ local state = self:GetAttribute("state")
+ local buttonType, buttonAction = self:GetAttribute("type"), nil
+ if buttonType == "custom" then return false end
+ -- action buttons can do their magic themself
+ -- for all other buttons, we'll need to update the content now
+ if buttonType ~= "action" and buttonType ~= "pet" then
+ -- with "spell" types, the 4th value contains the actual spell id
+ if kind == "spell" then
+ if extra then
+ value = extra
+ else
+ print("no spell id?", ...)
+ end
+ elseif kind == "item" and value then
+ value = format("item:%d", value)
+ end
+
+ -- Get the action that was on the button before
+ if buttonType ~= "empty" then
+ buttonAction = self:GetAttribute(self:GetAttribute("action_field"))
+ end
+
+ -- TODO: validate what kind of action is being fed in here
+ -- We can only use a handful of the possible things on the cursor
+ -- return false for all those we can't put on buttons
+
+ self:SetAttribute(format("labtype-%s", state), kind)
+ self:SetAttribute(format("labaction-%s", state), value)
+ -- update internal state
+ control:RunFor(self, self:GetAttribute("UpdateState"), state)
+ -- send a notification to the insecure code
+ --self:CallMethod("ButtonContentsChanged", state, kind, value)
+ else
+ -- get the action for (pet-)action buttons
+ buttonAction = self:GetAttribute("action")
+ end
+ return control:RunFor(self, self:GetAttribute("PickupButton"), buttonType, buttonAction)
+ ]])
+
+ button:SetScript("OnDragStart", nil)
+ -- Wrapped OnDragStart(self, button, kind, value, ...)
+ button.header:WrapScript(button, "OnDragStart", [[
+ return control:RunFor(self, self:GetAttribute("OnDragStart"))
+ ]])
+ -- Wrap twice, because the post-script is not run when the pre-script causes a pickup (doh)
+ -- we also need some phony message, or it won't work =/
+ button.header:WrapScript(button, "OnDragStart", [[
+ return "message", "update";
+ ]], [[
+ return control:RunFor(self, self:GetAttribute("UpdateState"), self:GetAttribute("state"))
+ ]])
+
+ button:SetScript("OnReceiveDrag", nil)
+ -- Wrapped OnReceiveDrag(self, button, kind, value, ...)
+ button.header:WrapScript(button, "OnReceiveDrag", [[
+ return control:RunFor(self, self:GetAttribute("OnReceiveDrag"), kind, value, ...)
+ ]])
+ -- Wrap twice, because the post-script is not run when the pre-script causes a pickup (doh)
+ -- we also need some phony message, or it won't work =/
+ button.header:WrapScript(button, "OnReceiveDrag", [[
+ return "message", "update"
+ ]], [[
+ control:RunFor(self, self:GetAttribute("UpdateState"), self:GetAttribute("state"))
+ ]])
+
+ button:SetScript("OnAttributeChanged", function(self, ...)
+ button:ButtonContentsChanged(...)
+ end)
+end
+
+function WrapOnClick(button)
+ -- Wrap OnClick, to catch changes to actions that are applied with a click on the button.
+ button.header:WrapScript(button, "OnClick", [[
+ if self:GetAttribute("type") == "action" then
+ local type, action = GetActionInfo(self:GetAttribute("action"))
+ return nil, format("%s|%s", tostring(type), tostring(action))
+ end
+ ]], [[
+ local type, action = GetActionInfo(self:GetAttribute("action"))
+ if message ~= format("%s|%s", tostring(type), tostring(action)) then
+ return control:RunFor(self, self:GetAttribute("UpdateState"), self:GetAttribute("state"))
+ end
+ ]])
+end
+
+-----------------------------------------------------------
+--- utility
+
+function lib:GetAllButtons()
+ local buttons = {}
+ for button in next, ButtonRegistry do
+ buttons[button] = true
+ end
+ return buttons
+end
+
+function Generic:ClearSetPoint(...)
+ self:ClearAllPoints()
+ self:SetPoint(...)
+end
+
+function Generic:NewHeader(header)
+ self.header = header
+ self:SetParent(header)
+ SetupSecureSnippets(self)
+ WrapOnClick(self)
+end
+
+
+-----------------------------------------------------------
+--- state management
+
+function Generic:ClearStates()
+ for state in pairs(self.state_types) do
+ self:SetAttribute(format("labtype-%s", state), nil)
+ self:SetAttribute(format("labaction-%s", state), nil)
+ end
+ wipe(self.state_types)
+ wipe(self.state_actions)
+end
+
+function Generic:SetState(state, kind, action)
+ if not state then state = self:GetAttribute("state") end
+ state = tostring(state)
+ -- we allow a nil kind for setting a empty state
+ if not kind then kind = "empty" end
+ if not type_meta_map[kind] then
+ error("SetStateAction: unknown action type: " .. tostring(kind), 2)
+ end
+ if kind ~= "empty" and action == nil then
+ error("SetStateAction: an action is required for non-empty states", 2)
+ end
+ if kind ~= "custom" and action ~= nil and type(action) ~= "number" and type(action) ~= "string" or (kind == "custom" and type(action) ~= "table") then
+ error("SetStateAction: invalid action data type, only strings and numbers allowed", 2)
+ end
+
+ if kind == "item" then
+ if tonumber(action) then
+ action = format("item:%s", action)
+ else
+ local itemString = match(action, "^|c%x+|H(item[%d:]+)|h%[")
+ if itemString then
+ action = itemString
+ end
+ end
+ end
+
+ self.state_types[state] = kind
+ self.state_actions[state] = action
+ self:UpdateState(state)
+end
+
+function Generic:UpdateState(state)
+ if not state then state = self:GetAttribute("state") end
+ state = tostring(state)
+ self:SetAttribute(format("labtype-%s", state), self.state_types[state])
+ self:SetAttribute(format("labaction-%s", state), self.state_actions[state])
+ if state ~= tostring(self:GetAttribute("state")) then return end
+ if self.header then
+ self.header:SetFrameRef("updateButton", self)
+ self.header:Execute([[
+ local frame = self:GetFrameRef("updateButton")
+ control:RunFor(frame, frame:GetAttribute("UpdateState"), frame:GetAttribute("state"))
+ ]])
+ else
+ -- TODO
+ end
+ self:UpdateAction()
+end
+
+function Generic:GetAction(state)
+ if not state then state = self:GetAttribute("state") end
+ state = tostring(state)
+ return self.state_types[state] or "empty", self.state_actions[state]
+end
+
+function Generic:UpdateAllStates()
+ for state in pairs(self.state_types) do
+ self:UpdateState(state)
+ end
+end
+
+function Generic:ButtonContentsChanged(state, kind, value)
+ state = tostring(state)
+ self.state_types[state] = kind or "empty"
+ self.state_actions[state] = value
+ lib.callbacks:Fire("OnButtonContentsChanged", self, state, self.state_types[state], self.state_actions[state])
+ self:UpdateAction(self)
+end
+
+function Generic:DisableDragNDrop(flag)
+ if InCombatLockdown() then
+ error("LibActionButton-1.0: You can only toggle DragNDrop out of combat!", 2)
+ end
+ if flag then
+ self:SetAttribute("LABdisableDragNDrop", true)
+ else
+ self:SetAttribute("LABdisableDragNDrop", nil)
+ end
+end
+
+function Generic:AddToButtonFacade(group)
+ if type(group) ~= "table" or type(group.AddButton) ~= "function" then
+ error("LibActionButton-1.0:AddToButtonFacade: You need to supply a proper group to use!", 2)
+ end
+ group:AddButton(self)
+ self.LBFSkinned = true
+end
+
+function Generic:AddToMasque(group)
+ if type(group) ~= "table" or type(group.AddButton) ~= "function" then
+ error("LibActionButton-1.0:AddToMasque: You need to supply a proper group to use!", 2)
+ end
+ group:AddButton(self)
+ self.MasqueSkinned = true
+end
+
+-----------------------------------------------------------
+--- frame scripts
+
+-- copied (and adjusted) from SecureHandlers.lua
+local function PickupAny(kind, target, detail, ...)
+ if kind == "clear" then
+ ClearCursor()
+ kind, target, detail = target, detail, ...
+ end
+
+ if kind == 'action' then
+ PickupAction(target)
+ elseif kind == 'item' then
+ PickupItem(target)
+ elseif kind == 'macro' then
+ PickupMacro(target)
+ elseif kind == 'petaction' then
+ PickupPetAction(target)
+ elseif kind == 'spell' then
+ PickupSpell(target)
+ elseif kind == 'companion' then
+ PickupCompanion(target, detail)
+ elseif kind == 'equipmentset' then
+ PickupEquipmentSet(target)
+ end
+end
+
+function Generic:OnUpdate(elapsed)
+ if not GetCVarBool('lockActionBars') then return; end
+
+ self.lastupdate = (self.lastupdate or 0) + elapsed;
+ if (self.lastupdate < .2) then return end
+ self.lastupdate = 0
+
+ local isDragKeyDown
+ if GetModifiedClick("PICKUPACTION") == 'ALT' then
+ isDragKeyDown = IsAltKeyDown()
+ elseif GetModifiedClick("PICKUPACTION") == 'CTRL' then
+ isDragKeyDown = IsControlKeyDown()
+ elseif GetModifiedClick("PICKUPACTION") == 'SHIFT' then
+ isDragKeyDown = IsShiftKeyDown()
+ end
+
+ if isDragKeyDown and (self.clickState == 'AnyDown' or self.clickState == nil) then
+ self.clickState = 'AnyUp'
+ self:RegisterForClicks(self.clickState)
+ elseif self.clickState == 'AnyUp' and not isDragKeyDown then
+ self.clickState = 'AnyDown'
+ self:RegisterForClicks(self.clickState)
+ end
+end
+
+function Generic:OnEnter()
+ if self.config.tooltip ~= "disabled" and (self.config.tooltip ~= "nocombat" or not InCombatLockdown()) then
+ UpdateTooltip(self)
+ end
+ if KeyBound then
+ KeyBound:Set(self)
+ end
+
+ if self.config.clickOnDown then
+ self:SetScript('OnUpdate', Generic.OnUpdate)
+ end
+end
+
+function Generic:OnLeave()
+ GameTooltip:Hide()
+ self:SetScript('OnUpdate', nil)
+end
+
+-- Insecure drag handler to allow clicking on the button with an action on the cursor
+-- to place it on the button. Like action buttons work.
+function Generic:PreClick()
+ if self._state_type == "action" or self._state_type == "pet"
+ or InCombatLockdown() or self:GetAttribute("LABdisableDragNDrop")
+ then
+ return
+ end
+ -- check if there is actually something on the cursor
+ local kind, value, subtype = GetCursorInfo()
+ if not (kind and value) then return end
+ self._old_type = self._state_type
+ if self._state_type and self._state_type ~= "empty" then
+ self._old_type = self._state_type
+ self:SetAttribute("type", "empty")
+ --self:SetState(nil, "empty", nil)
+ end
+ self._receiving_drag = true
+end
+
+local function formatHelper(input)
+ if type(input) == "string" then
+ return format("%q", input)
+ else
+ return tostring(input)
+ end
+end
+
+function Generic:PostClick()
+ UpdateButtonState(self)
+ if self._receiving_drag and not InCombatLockdown() then
+ if self._old_type then
+ self:SetAttribute("type", self._old_type)
+ self._old_type = nil
+ end
+ local oldType, oldAction = self._state_type, self._state_action
+ local kind, data, subtype = GetCursorInfo()
+ self.header:SetFrameRef("updateButton", self)
+ self.header:Execute(format([[
+ local frame = self:GetFrameRef("updateButton")
+ control:RunFor(frame, frame:GetAttribute("OnReceiveDrag"), %s, %s, %s)
+ control:RunFor(frame, frame:GetAttribute("UpdateState"), %s)
+ ]], formatHelper(kind), formatHelper(data), formatHelper(subtype), formatHelper(self:GetAttribute("state"))))
+ PickupAny("clear", oldType, oldAction)
+ end
+ self._receiving_drag = nil
+end
+
+-----------------------------------------------------------
+--- configuration
+
+local function merge(target, source, default)
+ for k,v in pairs(default) do
+ if type(v) ~= "table" then
+ if source and source[k] ~= nil then
+ target[k] = source[k]
+ else
+ target[k] = v
+ end
+ else
+ if type(target[k]) ~= "table" then target[k] = {} else wipe(target[k]) end
+ merge(target[k], type(source) == "table" and source[k], v)
+ end
+ end
+ return target
+end
+
+function Generic:UpdateConfig(config)
+ if config and type(config) ~= "table" then
+ error("LibActionButton-1.0: UpdateConfig requires a valid configuration!", 2)
+ end
+
+ self.config = {}
+ -- merge the two configs
+ merge(self.config, config, DefaultConfig)
+
+ if self.config.hideElements.macro then
+ self.actionName:Hide()
+ else
+ self.actionName:Show()
+ end
+
+ UpdateHotkeys(self)
+ UpdateGrid(self)
+ Update(self, true)
+
+ self:RegisterForClicks(self.config.clickOnDown and "AnyDown" or "AnyUp")
+end
+
+-----------------------------------------------------------
+--- event handler
+
+function ForAllButtons(method, onlyWithAction)
+ assert(type(method) == "function")
+ for button in next, (onlyWithAction and ActiveButtons or ButtonRegistry) do
+ method(button)
+ end
+end
+
+function InitializeEventHandler()
+ lib.eventFrame:SetScript("OnEvent", OnEvent)
+ lib.eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
+ lib.eventFrame:RegisterEvent("ACTIONBAR_SHOWGRID")
+ lib.eventFrame:RegisterEvent("ACTIONBAR_HIDEGRID")
+ --lib.eventFrame:RegisterEvent("ACTIONBAR_PAGE_CHANGED")
+ --lib.eventFrame:RegisterEvent("UPDATE_BONUS_ACTIONBAR")
+ lib.eventFrame:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
+ lib.eventFrame:RegisterEvent("UPDATE_BINDINGS")
+ lib.eventFrame:RegisterEvent("UPDATE_SHAPESHIFT_FORM")
+
+ lib.eventFrame:RegisterEvent("ACTIONBAR_UPDATE_STATE")
+ lib.eventFrame:RegisterEvent("ACTIONBAR_UPDATE_USABLE")
+ lib.eventFrame:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN")
+ lib.eventFrame:RegisterEvent("PLAYER_TARGET_CHANGED")
+ lib.eventFrame:RegisterEvent("TRADE_SKILL_SHOW")
+ lib.eventFrame:RegisterEvent("TRADE_SKILL_CLOSE")
+ lib.eventFrame:RegisterEvent("PLAYER_ENTER_COMBAT")
+ lib.eventFrame:RegisterEvent("PLAYER_LEAVE_COMBAT")
+ lib.eventFrame:RegisterEvent("START_AUTOREPEAT_SPELL")
+ lib.eventFrame:RegisterEvent("STOP_AUTOREPEAT_SPELL")
+ lib.eventFrame:RegisterEvent("UNIT_ENTERED_VEHICLE")
+ lib.eventFrame:RegisterEvent("UNIT_EXITED_VEHICLE")
+ lib.eventFrame:RegisterEvent("COMPANION_UPDATE")
+ lib.eventFrame:RegisterEvent("UNIT_INVENTORY_CHANGED")
+ lib.eventFrame:RegisterEvent("LEARNED_SPELL_IN_TAB")
+ lib.eventFrame:RegisterEvent("PET_STABLE_UPDATE")
+ lib.eventFrame:RegisterEvent("PET_STABLE_SHOW")
+
+ -- With those two, do we still need the ACTIONBAR equivalents of them?
+ lib.eventFrame:RegisterEvent("SPELL_UPDATE_COOLDOWN")
+ lib.eventFrame:RegisterEvent("SPELL_UPDATE_USABLE")
+ lib.eventFrame:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
+
+ lib.eventFrame:Show()
+ lib.eventFrame:SetScript("OnUpdate", OnUpdate)
+end
+
+function OnEvent(frame, event, arg1, ...)
+ if (event == "UNIT_INVENTORY_CHANGED" and arg1 == "player") or event == "LEARNED_SPELL_IN_TAB" then
+ local tooltipOwner = GameTooltip:GetOwner()
+ if ButtonRegistry[tooltipOwner] then
+ tooltipOwner:SetTooltip()
+ end
+ elseif event == "ACTIONBAR_SLOT_CHANGED" then
+ for button in next, ButtonRegistry do
+ if button._state_type == "action" and (arg1 == 0 or arg1 == tonumber(button._state_action)) then
+ Update(button)
+ end
+ end
+ elseif event == "PLAYER_ENTERING_WORLD" or event == "UPDATE_SHAPESHIFT_FORM" then
+ ForAllButtons(Update)
+ elseif event == "ACTIONBAR_PAGE_CHANGED" or event == "UPDATE_BONUS_ACTIONBAR" then
+ -- TODO: Are these even needed?
+ elseif event == "ACTIONBAR_SHOWGRID" then
+ ShowGrid()
+ elseif event == "ACTIONBAR_HIDEGRID" then
+ HideGrid()
+ elseif event == "UPDATE_BINDINGS" then
+ ForAllButtons(UpdateHotkeys)
+ elseif event == "PLAYER_TARGET_CHANGED" then
+ UpdateRangeTimer()
+ elseif (event == "ACTIONBAR_UPDATE_STATE") or
+ ((event == "UNIT_ENTERED_VEHICLE" or event == "UNIT_EXITED_VEHICLE") and (arg1 == "player")) or
+ ((event == "COMPANION_UPDATE") and (arg1 == "MOUNT")) then
+ ForAllButtons(UpdateButtonState, true)
+ elseif event == "ACTIONBAR_UPDATE_USABLE" then
+ for button in next, ActionButtons do
+ UpdateUsable(button)
+ end
+ elseif event == "SPELL_UPDATE_USABLE" then
+ for button in next, NonActionButtons do
+ UpdateUsable(button)
+ end
+ elseif event == "ACTIONBAR_UPDATE_COOLDOWN" then
+ for button in next, ActionButtons do
+ UpdateCooldown(button)
+ if GameTooltip:GetOwner() == button then
+ UpdateTooltip(button)
+ end
+ end
+ elseif event == "SPELL_UPDATE_COOLDOWN" then
+ for button in next, NonActionButtons do
+ UpdateCooldown(button)
+ if GameTooltip:GetOwner() == button then
+ UpdateTooltip(button)
+ end
+ end
+ elseif event == "TRADE_SKILL_SHOW" or event == "TRADE_SKILL_CLOSE" then
+ ForAllButtons(UpdateButtonState, true)
+ elseif event == "PLAYER_ENTER_COMBAT" then
+ for button in next, ActiveButtons do
+ if button:IsAttack() then
+ StartFlash(button)
+ end
+ end
+ elseif event == "PLAYER_LEAVE_COMBAT" then
+ for button in next, ActiveButtons do
+ if button:IsAttack() then
+ StopFlash(button)
+ end
+ end
+ elseif event == "START_AUTOREPEAT_SPELL" then
+ for button in next, ActiveButtons do
+ if button:IsAutoRepeat() then
+ StartFlash(button)
+ end
+ end
+ elseif event == "STOP_AUTOREPEAT_SPELL" then
+ for button in next, ActiveButtons do
+ if button.flashing == 1 and not button:IsAttack() then
+ StopFlash(button)
+ end
+ end
+ elseif event == "PET_STABLE_UPDATE" or event == "PET_STABLE_SHOW" then
+ ForAllButtons(Update)
+ elseif event == "PLAYER_EQUIPMENT_CHANGED" then
+ for button in next, ActiveButtons do
+ if button._state_type == "item" then
+ Update(button)
+ end
+ end
+ end
+end
+
+local flashTime = 0
+local rangeTimer = -1
+function OnUpdate(_, elapsed)
+ flashTime = flashTime - elapsed
+ rangeTimer = rangeTimer - elapsed
+ -- Run the loop only when there is something to update
+ if rangeTimer <= 0 or flashTime <= 0 then
+ for button in next, ActiveButtons do
+ -- Flashing
+ if button.flashing == 1 and flashTime <= 0 then
+ if button.flash:IsShown() then
+ button.flash:Hide()
+ else
+ button.flash:Show()
+ end
+ end
+
+ -- Range
+ if rangeTimer <= 0 then
+ UpdateRange(button) -- Sezz
+ end
+ end
+
+ -- Update values
+ if flashTime <= 0 then
+ flashTime = flashTime + ATTACK_BUTTON_FLASH_TIME
+ end
+ if rangeTimer <= 0 then
+ rangeTimer = TOOLTIP_UPDATE_TIME
+ end
+ end
+end
+
+local gridCounter = 0
+function ShowGrid()
+ gridCounter = gridCounter + 1
+ if gridCounter >= 1 then
+ for button in next, ButtonRegistry do
+ if button:IsShown() then
+ button:SetAlpha(1.0)
+ end
+ end
+ end
+end
+
+function HideGrid()
+ if gridCounter > 0 then
+ gridCounter = gridCounter - 1
+ end
+ if gridCounter == 0 then
+ for button in next, ButtonRegistry do
+ if button:IsShown() and not button:HasAction() and not button.config.showGrid then
+ button:SetAlpha(0.0)
+ end
+ end
+ end
+end
+
+function UpdateGrid(self)
+ if self.config.showGrid then
+ self:SetAlpha(1.0)
+ elseif gridCounter == 0 and self:IsShown() and not self:HasAction() then
+ self:SetAlpha(0.0)
+ end
+end
+
+function UpdateRange(self, force) -- Sezz: moved from OnUpdate
+ local inRange = self:IsInRange()
+ local oldRange = self.outOfRange
+ self.outOfRange = (inRange == false)
+ if force or (oldRange ~= self.outOfRange) then
+ if self.config.outOfRangeColoring == "button" then
+ UpdateUsable(self)
+ elseif self.config.outOfRangeColoring == "hotkey" then
+ local hotkey = self.hotkey
+ if hotkey:GetText() == RANGE_INDICATOR then
+ if inRange == false then
+ hotkey:Show()
+ else
+ hotkey:Hide()
+ end
+ end
+
+ if inRange == false then
+ hotkey:SetVertexColor(unpack(self.config.colors.range))
+ else
+ hotkey:SetVertexColor(unpack(self.config.colors.usable))
+ end
+ end
+ end
+end
+
+-----------------------------------------------------------
+--- KeyBound integration
+
+function Generic:GetBindingAction()
+ return self.config.keyBoundTarget or "CLICK "..self:GetName()..":LeftButton"
+end
+
+function Generic:GetHotkey()
+ local name = "CLICK "..self:GetName()..":LeftButton"
+ local key = GetBindingKey(self.config.keyBoundTarget or name)
+ if not key and self.config.keyBoundTarget then
+ key = GetBindingKey(name)
+ end
+ if key then
+ return KeyBound and KeyBound:ToShortKey(key) or key
+ end
+end
+
+local function getKeys(binding, keys)
+ keys = keys or ""
+ for i = 1, select("#", GetBindingKey(binding)) do
+ local hotKey = select(i, GetBindingKey(binding))
+ if keys ~= "" then
+ keys = keys .. ", "
+ end
+ keys = keys .. GetBindingText(hotKey)
+ end
+ return keys
+end
+
+function Generic:GetBindings()
+ local keys
+
+ if self.config.keyBoundTarget then
+ keys = getKeys(self.config.keyBoundTarget)
+ end
+
+ keys = getKeys("CLICK "..self:GetName()..":LeftButton", keys)
+
+ return keys
+end
+
+function Generic:SetKey(key)
+ if self.config.keyBoundTarget then
+ SetBinding(key, self.config.keyBoundTarget)
+ else
+ SetBindingClick(key, self:GetName(), "LeftButton")
+ end
+ lib.callbacks:Fire("OnKeybindingChanged", self, key)
+end
+
+local function clearBindings(binding)
+ while GetBindingKey(binding) do
+ SetBinding(GetBindingKey(binding), nil)
+ end
+end
+
+function Generic:ClearBindings()
+ if self.config.keyBoundTarget then
+ clearBindings(self.config.keyBoundTarget)
+ end
+ clearBindings("CLICK "..self:GetName()..":LeftButton")
+ lib.callbacks:Fire("OnKeybindingChanged", self, nil)
+end
+
+-----------------------------------------------------------
+--- button management
+
+function Generic:UpdateAction(force)
+ local type, action = self:GetAction()
+ if force or (type ~= self._state_type) or (action ~= self._state_action) then
+ -- type changed, update the metatable
+ if force or (self._state_type ~= type) then
+ local meta = type_meta_map[type] or type_meta_map.empty
+ setmetatable(self, meta)
+ self._state_type = type
+ end
+ self._state_action = action
+ Update(self)
+ end
+end
+
+function Update(self, fromUpdateConfig)
+ if self:HasAction() then
+ ActiveButtons[self] = true
+ if self._state_type == "action" then
+ ActionButtons[self] = true
+ NonActionButtons[self] = nil
+ else
+ ActionButtons[self] = nil
+ NonActionButtons[self] = true
+ end
+ self:SetAlpha(1.0)
+ UpdateUsable(self)
+ UpdateCooldown(self)
+ UpdateFlash(self)
+ else
+ ActiveButtons[self] = nil
+ ActionButtons[self] = nil
+ NonActionButtons[self] = nil
+ if gridCounter == 0 and not self.config.showGrid then
+ self:SetAlpha(0.0)
+ end
+ self.cooldown:Hide()
+ self:SetChecked(0)
+ end
+
+ -- Add a green border if button is an equipped item
+ if self:IsEquipped() and not self.config.hideElements.equipped then
+ self.border:SetVertexColor(0, 1.0, 0, 0.35)
+ self.border:Show()
+ else
+ self.border:Hide()
+ end
+
+ -- Update Action Text
+ if not self:IsConsumableOrStackable() then
+ self.actionName:SetText(self:GetActionText())
+ else
+ self.actionName:SetText("")
+ end
+
+ -- Update icon and hotkey
+ local texture = self:GetTexture()
+ if texture then
+ self.icon:SetTexture(texture)
+ self.icon:Show()
+ self.rangeTimer = - 1
+ self:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
+ if not self.LBFSkinned and not self.MasqueSkinned then
+ self.normalTexture:SetTexCoord(0, 0, 0, 0)
+ end
+ else
+ self.icon:Hide()
+ self.cooldown:Hide()
+ self.rangeTimer = nil
+ self:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
+
+ if not self.LBFSkinned and not self.MasqueSkinned then
+ self.normalTexture:SetTexCoord(-0.15, 1.15, -0.15, 1.17)
+ end
+ end
+
+ self:UpdateLocal()
+
+ UpdateRange(self, fromUpdateConfig) -- Sezz: update range check on state change
+
+ UpdateCount(self)
+
+ UpdateButtonState(self)
+
+ if GameTooltip:GetOwner() == self then
+ UpdateTooltip(self)
+ end
+
+ -- this could've been a spec change, need to call OnStateChanged for action buttons, if present
+ if not InCombatLockdown() and self._state_type == "action" then
+ local onStateChanged = self:GetAttribute("OnStateChanged")
+ if onStateChanged then
+ self.header:SetFrameRef("updateButton", self)
+ self.header:Execute(([[
+ local frame = self:GetFrameRef("updateButton")
+ control:RunFor(frame, frame:GetAttribute("OnStateChanged"), %s, %s, %s)
+ ]]):format(formatHelper(self:GetAttribute("state")), formatHelper(self._state_type), formatHelper(self._state_action)))
+ end
+ end
+ lib.callbacks:Fire("OnButtonUpdate", self)
+end
+
+function Generic:UpdateLocal()
+-- dummy function the other button types can override for special updating
+end
+
+function UpdateButtonState(self)
+ if self:IsCurrentlyActive() or self:IsAutoRepeat() then
+ self:SetChecked(1)
+ else
+ self:SetChecked(0)
+ end
+ lib.callbacks:Fire("OnButtonState", self)
+end
+
+function UpdateUsable(self)
+ if self.config.useColoring then
+ if self.config.outOfRangeColoring == "button" and self.outOfRange then
+ self.icon:SetVertexColor(unpack(self.config.colors.range))
+ else
+ local isUsable, notEnoughMana = self:IsUsable()
+ if isUsable then
+ self.icon:SetVertexColor(unpack(self.config.colors.usable))
+ --self.NormalTexture:SetVertexColor(1.0, 1.0, 1.0)
+ elseif notEnoughMana then
+ self.icon:SetVertexColor(unpack(self.config.colors.mana))
+ --self.NormalTexture:SetVertexColor(0.5, 0.5, 1.0)
+ else
+ self.icon:SetVertexColor(unpack(self.config.colors.notUsable))
+ --self.NormalTexture:SetVertexColor(1.0, 1.0, 1.0)
+ end
+ end
+ else
+ self.icon:SetVertexColor(unpack(self.config.colors.usable))
+ end
+ lib.callbacks:Fire("OnButtonUsable", self)
+end
+
+function UpdateCount(self)
+ if not self:HasAction() then
+ self.count:SetText("")
+ return
+ end
+
+ if self:IsConsumableOrStackable() then
+ local count = self:GetCount()
+ if count > (self.maxDisplayCount or 9999) then
+ self.count:SetText("*")
+ else
+ self.count:SetText(count)
+ end
+ else
+ self.count:SetText("")
+ end
+end
+
+function UpdateCooldown(self)
+ local start, duration, enable = self:GetCooldown()
+ CooldownFrame_SetTimer(self.cooldown, start, duration, enable)
+
+ lib.callbacks:Fire("OnCooldownUpdate", self, start, duration, enable)
+end
+
+function StartFlash(self)
+ self.flashing = 1
+ flashTime = 0
+ UpdateButtonState(self)
+end
+
+function StopFlash(self)
+ self.flashing = 0
+ self.flash:Hide()
+ UpdateButtonState(self)
+end
+
+function UpdateFlash(self)
+ if (self:IsAttack() and self:IsCurrentlyActive()) or self:IsAutoRepeat() then
+ StartFlash(self)
+ else
+ StopFlash(self)
+ end
+end
+
+function UpdateTooltip(self)
+ if (GetCVar("UberTooltips") == "1") then
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ end
+ if self:SetTooltip() then
+ self.UpdateTooltip = UpdateTooltip
+ else
+ self.UpdateTooltip = nil
+ end
+end
+
+function UpdateHotkeys(self)
+ local key = self:GetHotkey()
+ if not key or key == "" or self.config.hideElements.hotkey then
+ self.hotkey:SetText(RANGE_INDICATOR)
+ self.hotkey:SetPoint("TOPRIGHT", 0, -3);
+ self.hotkey:Hide()
+ else
+ self.hotkey:SetText(key)
+ self.hotkey:SetPoint("TOPRIGHT", 0, -3);
+ self.hotkey:Show()
+ end
+
+ if self.postKeybind then
+ self.postKeybind(nil, self)
+ end
+end
+
+function UpdateRangeTimer()
+ rangeTimer = -1
+end
+
+local function GetSpellIdByName(spellName)
+ if not spellName then return end
+ local spellLink = GetSpellLink(spellName)
+ if spellLink then
+ return tonumber(spellLink:match("spell:(%d+)"))
+ end
+ return nil
+end
+
+-----------------------------------------------------------
+--- WoW API mapping
+--- Generic Button
+Generic.HasAction = function(self) return nil end
+Generic.GetActionText = function(self) return "" end
+Generic.GetTexture = function(self) return nil end
+Generic.GetCount = function(self) return 0 end
+Generic.GetCooldown = function(self) return 0, 0, 0 end
+Generic.IsAttack = function(self) return nil end
+Generic.IsEquipped = function(self) return nil end
+Generic.IsCurrentlyActive = function(self) return nil end
+Generic.IsAutoRepeat = function(self) return nil end
+Generic.IsUsable = function(self) return nil end
+Generic.IsConsumableOrStackable = function(self) return nil end
+Generic.IsUnitInRange = function(self, unit) return nil end
+Generic.IsInRange = function(self)
+ local unit = self:GetAttribute("unit")
+ if unit == "player" then
+ unit = nil
+ end
+ local val = self:IsUnitInRange(unit)
+ -- map 1/0 to true false, since the return values are inconsistent between actions and spells
+ if val == 1 then val = true elseif val == 0 then val = false end
+ return val
+end
+Generic.SetTooltip = function(self) return nil end
+Generic.GetSpellId = function(self) return nil end
+
+-----------------------------------------------------------
+--- Action Button
+Action.HasAction = function(self) return HasAction(self._state_action) end
+Action.GetActionText = function(self) return GetActionText(self._state_action) end
+Action.GetTexture = function(self) return GetActionTexture(self._state_action) end
+Action.GetCount = function(self) return GetActionCount(self._state_action) end
+Action.GetCooldown = function(self) return GetActionCooldown(self._state_action) end
+Action.IsAttack = function(self) return IsAttackAction(self._state_action) end
+Action.IsEquipped = function(self) return IsEquippedAction(self._state_action) end
+Action.IsCurrentlyActive = function(self) return IsCurrentAction(self._state_action) end
+Action.IsAutoRepeat = function(self) return IsAutoRepeatAction(self._state_action) end
+Action.IsUsable = function(self) return IsUsableAction(self._state_action) end
+Action.IsConsumableOrStackable = function(self) return IsConsumableAction(self._state_action) or IsStackableAction(self._state_action) end
+Action.IsUnitInRange = function(self, unit) return IsActionInRange(self._state_action, unit) end
+Action.SetTooltip = function(self) return GameTooltip:SetAction(self._state_action) end
+Action.GetSpellId = function(self)
+ local actionType, id, subType, globalID = GetActionInfo(self._state_action)
+ if actionType == "spell" then
+ return globalID
+ elseif actionType == "macro" then
+ return GetSpellIdByName(GetMacroSpell(id))
+ end
+end
+
+-----------------------------------------------------------
+--- Spell Button
+Spell.HasAction = function(self) return true end
+Spell.GetActionText = function(self) return "" end
+Spell.GetTexture = function(self) return GetSpellTexture(self._state_action) end
+Spell.GetCount = function(self) return GetSpellCount(self._state_action) end
+Spell.GetCooldown = function(self) return GetSpellCooldown(self._state_action) end
+Spell.IsAttack = function(self) return IsAttackSpell(FindSpellBookSlotBySpellID(self._state_action), "spell") end -- needs spell book id as of 4.0.1.13066
+Spell.IsEquipped = function(self) return nil end
+Spell.IsCurrentlyActive = function(self) return IsCurrentSpell(self._state_action) end
+Spell.IsAutoRepeat = function(self) return IsAutoRepeatSpell(FindSpellBookSlotBySpellID(self._state_action), "spell") end -- needs spell book id as of 4.0.1.13066
+Spell.IsUsable = function(self) return IsUsableSpell(self._state_action) end
+Spell.IsConsumableOrStackable = function(self) return IsConsumableSpell(self._state_action) end
+Spell.IsUnitInRange = function(self, unit) return IsSpellInRange(FindSpellBookSlotBySpellID(self._state_action), "spell", unit) end -- needs spell book id as of 4.0.1.13066
+Spell.SetTooltip = function(self) return GameTooltip:SetSpellByID(self._state_action) end
+Spell.GetSpellId = function(self) return self._state_action end
+
+-----------------------------------------------------------
+--- Item Button
+local function getItemId(input)
+ return input:match("^item:(%d+)")
+end
+
+Item.HasAction = function(self) return true end
+Item.GetActionText = function(self) return "" end
+Item.GetTexture = function(self) return GetItemIcon(self._state_action) end
+Item.GetCount = function(self) return GetItemCount(self._state_action, nil, true) end
+Item.GetCooldown = function(self) return GetItemCooldown(getItemId(self._state_action)) end
+Item.IsAttack = function(self) return nil end
+Item.IsEquipped = function(self) return IsEquippedItem(self._state_action) end
+Item.IsCurrentlyActive = function(self) return IsCurrentItem(self._state_action) end
+Item.IsAutoRepeat = function(self) return nil end
+Item.IsUsable = function(self) return IsUsableItem(self._state_action) end
+Item.IsConsumableOrStackable = function(self) return IsConsumableItem(self._state_action) end
+Item.IsUnitInRange = function(self, unit) return IsItemInRange(self._state_action, unit) end
+Item.SetTooltip = function(self) return GameTooltip:SetHyperlink(self._state_action) end
+Item.GetSpellId = function(self) return nil end
+
+-----------------------------------------------------------
+--- Macro Button
+-- TODO: map results of GetMacroSpell/GetMacroItem to proper results
+Macro.HasAction = function(self) return true end
+Macro.GetActionText = function(self) return (GetMacroInfo(self._state_action)) end
+Macro.GetTexture = function(self) return (select(2, GetMacroInfo(self._state_action))) end
+Macro.GetCount = function(self) return 0 end
+Macro.GetCooldown = function(self) return 0, 0, 0 end
+Macro.IsAttack = function(self) return nil end
+Macro.IsEquipped = function(self) return nil end
+Macro.IsCurrentlyActive = function(self) return nil end
+Macro.IsAutoRepeat = function(self) return nil end
+Macro.IsUsable = function(self) return nil end
+Macro.IsConsumableOrStackable = function(self) return nil end
+Macro.IsUnitInRange = function(self, unit) return nil end
+Macro.SetTooltip = function(self) return nil end
+Macro.GetSpellId = function(self) return nil end
+
+-----------------------------------------------------------
+--- Custom Button
+Custom.HasAction = function(self) return true end
+Custom.GetActionText = function(self) return "" end
+Custom.GetTexture = function(self) return self._state_action.texture end
+Custom.GetCount = function(self) return 0 end
+Custom.GetCooldown = function(self) return 0, 0, 0 end
+Custom.IsAttack = function(self) return nil end
+Custom.IsEquipped = function(self) return nil end
+Custom.IsCurrentlyActive = function(self) return nil end
+Custom.IsAutoRepeat = function(self) return nil end
+Custom.IsUsable = function(self) return true end
+Custom.IsConsumableOrStackable = function(self) return nil end
+Custom.IsUnitInRange = function(self, unit) return nil end
+Custom.SetTooltip = function(self) return GameTooltip:SetText(self._state_action.tooltip) end
+Custom.GetSpellId = function(self) return nil end
+Custom.RunCustom = function(self, unit, button) return self._state_action.func(self, unit, button) end
+
+-----------------------------------------------------------
+--- Update old Buttons
+if oldversion and next(lib.buttonRegistry) then
+ InitializeEventHandler()
+ for button in next, lib.buttonRegistry do
+ -- this refreshes the metatable on the button
+ Generic.UpdateAction(button, true)
+ SetupSecureSnippets(button)
+ if oldversion < 12 then
+ WrapOnClick(button)
+ end
+ end
+end
diff --git a/ElvUI/Libraries/LibAnim/LibAnim.lua b/ElvUI/Libraries/LibAnim/LibAnim.lua
new file mode 100644
index 0000000..1bc8379
--- /dev/null
+++ b/ElvUI/Libraries/LibAnim/LibAnim.lua
@@ -0,0 +1,1195 @@
+-- LibAnim by Hydra
+local Version = 2.03
+
+-- Note, deprecated items will be removed next version. Please update your usage accordingly. (ctrl + f - "Deprecated")
+
+if (_LibAnim and _LibAnim >= Version) then
+ return
+end
+
+local pi = math.pi
+local cos = math.cos
+local sin = math.sin
+local sqrt = math.sqrt
+local floor = math.floor
+local tinsert = table.insert
+local tremove = table.remove
+local lower = string.lower
+local pairs = pairs
+local Updater = CreateFrame("StatusBar")
+local Texture = Updater:CreateTexture()
+local FontString = Updater:CreateFontString()
+local Initialize = {}
+local Update = {}
+local Easing = {}
+local Callbacks = {["onplay"] = {}, ["onpause"] = {}, ["onresume"] = {}, ["onstop"] = {}, ["onreset"] = {}, ["onfinished"] = {}}
+
+-- Update all current animations
+local AnimationOnUpdate = function(self, elapsed)
+ for i = 1, #self do
+ if self[i] then -- Double check that the index still exists, due to pauses/stops removing them on the fly
+ self[i]:Update(elapsed, i)
+ end
+ end
+
+ if (#self == 0) then
+ self:SetScript("OnUpdate", nil)
+ end
+end
+
+local StartUpdating = function(anim)
+ tinsert(Updater, anim)
+
+ if (not Updater:GetScript("OnUpdate")) then
+ Updater:SetScript("OnUpdate", AnimationOnUpdate)
+ end
+end
+
+local GetColor = function(p, r1, g1, b1, r2, g2, b2)
+ return r1 + (r2 - r1) * p, g1 + (g2 - g1) * p, b1 + (b2 - b1) * p
+end
+
+local Set = {
+ ["backdrop"] = Updater.SetBackdropColor,
+ ["border"] = Updater.SetBackdropBorderColor,
+ ["statusbar"] = Updater.SetStatusBarColor,
+ ["text"] = FontString.SetTextColor,
+ ["texture"] = Texture.SetTexture,
+ ["vertex"] = Texture.SetVertexColor,
+}
+
+local Get = {
+ ["backdrop"] = Updater.GetBackdropColor,
+ ["border"] = Updater.GetBackdropBorderColor,
+ ["statusbar"] = Updater.GetStatusBarColor,
+ ["text"] = FontString.GetTextColor,
+ ["texture"] = Texture.GetVertexColor,
+ ["vertex"] = Texture.GetVertexColor,
+}
+
+-- Linear
+local Linear = function(t, b, c, d)
+ return c * t / d + b
+end
+
+-- Quadratic
+local InQuadratic = function(t, b, c, d)
+ t = t / d
+
+ return c * (t ^ 2) + b
+end
+
+local OutQuadratic = function(t, b, c, d)
+ t = t / d
+
+ return -c * t * (t - 2) + b
+end
+
+local InOutQuadratic = function(t, b, c, d)
+ t = t / d * 2
+
+ if (t < 1) then
+ return c / 2 * (t ^ 2) + b
+ else
+ return -c / 2 * ((t - 1) * (t - 3) - 1) + b
+ end
+end
+
+-- Cubic
+local InCubic = function(t, b, c, d)
+ t = t / d
+
+ return c * (t ^ 3) + b
+end
+
+local OutCubic = function(t, b, c, d)
+ t = t / d - 1
+
+ return c * (t ^ 3 + 1) + b
+end
+
+local InOutCubic = function(t, b, c, d)
+ t = t / d * 2
+
+ if (t < 1) then
+ return c / 2 * (t ^ 3) + b
+ else
+ t = t - 2
+
+ return c / 2 * (t ^ 3 + 2) + b
+ end
+end
+
+-- Quartic
+local InQuartic = function(t, b, c, d)
+ t = t / d
+
+ return c * (t ^ 4) + b
+end
+
+local OutQuartic = function(t, b, c, d)
+ t = t / d - 1
+
+ return -c * (t ^ 4 - 1) + b
+end
+
+local InOutQuartic = function(t, b, c, d)
+ t = t / d * 2
+
+ if (t < 1) then
+ return c / 2 * t ^ 4 + b
+ else
+ t = t - 2
+
+ return -c / 2 * (t ^ 4 - 2) + b
+ end
+end
+
+-- Quintic
+local InQuintic = function(t, b, c, d)
+ t = t / d
+
+ return c * (t ^ 5) + b
+end
+
+local OutQuintic = function(t, b, c, d)
+ t = t / d - 1
+
+ return c * (t ^ 5 + 1) + b
+end
+
+local InOutQuintic = function(t, b, c, d)
+ t = t / d * 2
+
+ if (t < 1) then
+ return c / 2 * t ^ 5 + b
+ else
+ t = t - 2
+
+ return c / 2 * (t ^ 5 + 2) + b
+ end
+end
+
+-- Sinusoidal
+local InSinusoidal = function(t, b, c, d)
+ return -c * cos(t / d * (pi / 2)) + c + b
+end
+
+local OutSinusoidal = function(t, b, c, d)
+ return c * sin(t / d * (pi / 2)) + b
+end
+
+local InOutSinusoidal = function(t, b, c, d)
+ return -c / 2 * (cos(pi * t / d) - 1) + b
+end
+
+-- Exponential
+local InExponential = function(t, b, c, d)
+ if (t == 0) then
+ return b
+ else
+ return c * (2 ^ (10 * (t / d - 1))) + b - c * 0.001
+ end
+end
+
+local OutExponential = function(t, b, c, d)
+ if (t == d) then
+ return b + c
+ else
+ return c * 1.001 * (-(2 ^ (-10 * t / d)) + 1) + b
+ end
+end
+
+local InOutExponential = function(t, b, c, d)
+ if (t == 0) then
+ return b
+ end
+
+ if (t == d) then
+ return b + c
+ end
+
+ t = t / d * 2
+
+ if (t < 1) then
+ return c / 2 * (2 ^ (10 * (t - 1))) + b - c * 0.0005
+ else
+ t = t - 1
+
+ return c / 2 * 1.0005 * (-(2 ^ (-10 * t)) + 2) + b
+ end
+end
+
+-- Circular
+local InCircular = function(t, b, c, d)
+ t = t / d
+
+ return (-c * (sqrt(1 - t * t) - 1) + b)
+end
+
+local OutCircular = function(t, b, c, d)
+ t = t / d - 1
+
+ return (c * sqrt(1 - t * t) + b)
+end
+
+local InOutCircular = function(t, b, c, d)
+ t = t / d * 2
+
+ if (t < 1) then
+ return -c / 2 * (sqrt(1 - t * t) - 1) + b
+ else
+ t = t - 2
+
+ return c / 2 * (sqrt(1 - t * t) + 1) + b
+ end
+end
+
+-- Bounce
+local OutBounce = function(t, b, c, d)
+ t = t / d
+
+ if (t < (1 / 2.75)) then
+ return c * (7.5625 * t * t) + b
+ elseif (t < (2 / 2.75)) then
+ t = t - (1.5 / 2.75)
+
+ return c * (7.5625 * t * t + 0.75) + b
+ elseif (t < (2.5 / 2.75)) then
+ t = t - (2.25 / 2.75)
+
+ return c * (7.5625 * t * t + 0.9375) + b
+ else
+ t = t - (2.625 / 2.75)
+
+ return c * (7.5625 * t * t + 0.984375) + b
+ end
+end
+
+local InBounce = function(t, b, c, d)
+ return c - OutBounce(d - t, 0, c, d) + b
+end
+
+local InOutBounce = function(t, b, c, d)
+ if (t < d / 2) then
+ return InBounce(t * 2, 0, c, d) * 0.5 + b
+ else
+ return OutBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b
+ end
+end
+
+-- Elastic
+local InElastic = function(t, b, c, d)
+ if (t == 0) then
+ return b
+ end
+
+ t = t / d
+
+ if (t == 1) then
+ return b + c
+ end
+
+ local a = c
+ local p = d * 0.3
+ local s = p / 4
+
+ t = t - 1
+
+ return -(a * 2 ^ (10 * t) * sin((t * d - s) * (2 * pi) / p)) + b
+end
+
+local OutElastic = function(t, b, c, d)
+ if (t == 0) then
+ return b
+ end
+
+ t = t / d
+
+ if (t == 1) then
+ return b + c
+ end
+
+ local a = c
+ local p = d * 0.3
+ local s = p / 4
+
+ return a * 2 ^ (-10 * t) * sin((t * d - s) * (2 * pi) / p) + c + b
+end
+
+local InOutElastic = function(t, b, c, d)
+ if (t == 0) then
+ return b
+ end
+
+ t = t / d * 2
+
+ if (t == 2) then
+ return b + c
+ end
+
+ local a = c
+ local p = d * (0.3 * 1.5)
+ local s = p / 4
+
+ if (t < 1) then
+ t = t - 1
+
+ return -0.5 * (a * 2 ^ (10 * t) * sin((t * d - s) * (2 * pi) / p)) + b
+ else
+ t = t - 1
+
+ return a * 2 ^ (-10 * t) * sin((t * d - s) * (2 * pi) / p ) * 0.5 + c + b
+ end
+end
+
+Easing["linear"] = Linear
+Easing["in-quadratic"] = InQuadratic
+Easing["out-quadratic"] = OutQuadratic
+Easing["inout-quadratic"] = InOutQuadratic
+Easing["in-cubic"] = InCubic
+Easing["out-cubic"] = OutCubic
+Easing["inout-cubic"] = InOutCubic
+Easing["in-quartic"] = InQuartic
+Easing["out-quartic"] = OutQuartic
+Easing["inout-quartic"] = InOutQuartic
+Easing["in-quintic"] = InQuintic
+Easing["out-quintic"] = OutQuintic
+Easing["inout-quintic"] = InOutQuintic
+Easing["in-sinusoidal"] = InSinusoidal
+Easing["out-sinusoidal"] = OutSinusoidal
+Easing["inout-sinusoidal"] = InOutSinusoidal
+Easing["in-exponential"] = InExponential
+Easing["out-exponential"] = OutExponential
+Easing["inout-exponential"] = InOutExponential
+Easing["in-circular"] = InCircular
+Easing["out-circular"] = OutCircular
+Easing["inout-circular"] = InOutCircular
+Easing["in-bounce"] = InBounce
+Easing["out-bounce"] = OutBounce
+Easing["inout-bounce"] = InOutBounce
+Easing["in-elastic"] = InElastic
+Easing["out-elastic"] = OutElastic
+Easing["inout-elastic"] = InOutElastic
+
+-- Some fallbacks / lazy options
+Easing["in"] = Easing["in-quadratic"]
+Easing["out"] = Easing["out-quadratic"]
+Easing["inout"] = Easing["inout-quadratic"]
+Easing["bounce"] = Easing["out-bounce"] -- Deprecated, don't use bounce without an explicit motion anymore
+
+local AnimMethods = {
+ All = {
+ Play = function(self)
+ if (not self.Paused) then
+ Initialize[self.Type](self)
+ self:Callback("OnPlay")
+ else
+ StartUpdating(self)
+ self:Callback("OnResume")
+ end
+
+ self.Playing = true
+ self.Paused = false
+ self.Stopped = false
+ end,
+
+ IsPlaying = function(self)
+ return self.Playing
+ end,
+
+ Pause = function(self)
+ for i = 1, #Updater do
+ if (Updater[i] == self) then
+ tremove(Updater, i)
+
+ break
+ end
+ end
+
+ self.Playing = false
+ self.Paused = true
+ self.Stopped = false
+ self:Callback("OnPause")
+ end,
+
+ IsPaused = function(self)
+ return self.Paused
+ end,
+
+ Stop = function(self, reset)
+ for i = 1, #Updater do
+ if (Updater[i] == self) then
+ tremove(Updater, i)
+
+ break
+ end
+ end
+
+ self.Playing = false
+ self.Paused = false
+ self.Stopped = true
+ self.Timer = 0
+
+ if reset then
+ self:Reset()
+ self:Callback("OnReset")
+ else
+ self:Callback("OnStop")
+ end
+ end,
+
+ IsStopped = function(self)
+ return self.Stopped
+ end,
+
+ SetEasing = function(self, easing)
+ easing = lower(easing)
+
+ self.Easing = Easing[easing] and easing or "linear"
+ end,
+
+ GetEasing = function(self)
+ return self.Easing
+ end,
+
+ SetSmoothing = function(self, easing) -- Deprecated, change "SetSmoothing" to "SetEasing"
+ easing = lower(easing)
+
+ self.Easing = Easing[easing] and easing or "linear"
+ end,
+
+ GetSmoothing = function(self) -- Deprecated, change "GetSmoothing" to "GetEasing"
+ return self.Easing
+ end,
+
+ SetDuration = function(self, duration)
+ self.Duration = duration or 0
+ end,
+
+ GetDuration = function(self)
+ return self.Duration
+ end,
+
+ GetProgressByTimer = function(self)
+ return self.Timer
+ end,
+
+ SetOrder = function(self, order)
+ self.Order = order or 1
+
+ if (order > self.Group.MaxOrder) then
+ self.Group.MaxOrder = order
+ end
+ end,
+
+ GetOrder = function(self)
+ return self.Order
+ end,
+
+ GetParent = function(self)
+ return self.Parent
+ end,
+
+ SetScript = function(self, handler, func)
+ handler = lower(handler)
+
+ if Callbacks[handler] then
+ Callbacks[handler][self] = func
+ end
+ end,
+
+ GetScript = function(self, handler)
+ handler = lower(handler)
+
+ if (Callbacks[handler] and Callbacks[handler][self]) then
+ return Callbacks[handler][self]
+ end
+ end,
+
+ Callback = function(self, handler)
+ handler = lower(handler)
+
+ if Callbacks[handler][self] then
+ Callbacks[handler][self](self)
+ end
+ end,
+ },
+
+ move = {
+ SetOffset = function(self, x, y)
+ self.XSetting = x or 0
+ self.YSetting = y or 0
+ end,
+
+ GetOffset = function(self)
+ return self.XSetting, self.YSetting
+ end,
+
+ SetRounded = function(self, flag)
+ self.IsRounded = flag
+ end,
+
+ GetRounded = function(self)
+ return self.IsRounded
+ end,
+
+ GetProgress = function(self)
+ return self.XOffset, self.YOffset
+ end,
+
+ Reset = function(self)
+ self.Timer = 0
+ self.Parent:ClearAllPoints()
+ self.Parent:SetPoint(self.A1, self.P, self.A2, self.StartX, self.StartY)
+
+ if self.IsRounded then
+ self.ModTimer = 0
+ end
+ end,
+ },
+
+ fade = {
+ SetChange = function(self, alpha)
+ self.EndAlphaSetting = alpha or 0
+ end,
+
+ GetChange = function(self)
+ return self.EndAlphaSetting
+ end,
+
+ GetProgress = function(self)
+ return self.AlphaOffset
+ end,
+
+ Reset = function(self)
+ self.Timer = 0
+ self.Parent:SetAlpha(self.StartAlpha)
+ end,
+ },
+
+ height = {
+ SetChange = function(self, height)
+ self.EndHeightSetting = height or 0
+ end,
+
+ GetChange = function(self)
+ return self.EndHeightSetting
+ end,
+
+ GetProgress = function(self)
+ return self.HeightOffset
+ end,
+
+ Reset = function(self)
+ self.Timer = 0
+ self.Parent:SetHeight(self.StartHeight)
+ end,
+ },
+
+ width = {
+ SetChange = function(self, width)
+ self.EndWidthSetting = width or 0
+ end,
+
+ GetChange = function(self)
+ return self.EndWidthSetting
+ end,
+
+ GetProgress = function(self)
+ return self.WidthOffset
+ end,
+
+ Reset = function(self)
+ self.Timer = 0
+ self.Parent:SetWidth(self.StartWidth)
+ end,
+ },
+
+ color = {
+ SetChange = function(self, r, g, b)
+ self.EndRSetting = r or 1
+ self.EndGSetting = g or 1
+ self.EndBSetting = b or 1
+ end,
+
+ GetChange = function(self)
+ return self.EndRSetting, self.EndGSetting, self.EndBSetting
+ end,
+
+ SetColorType = function(self, region)
+ region = lower(region)
+
+ self.ColorType = Set[region] and region or "border"
+ end,
+
+ GetColorType = function(self)
+ return self.ColorType
+ end,
+
+ GetProgress = function(self)
+ return self.ColorOffset
+ end,
+
+ Reset = function(self)
+ self.Timer = 0
+ Set[self.ColorType](self.Parent, self.StartR, self.StartG, self.StartB)
+ end,
+ },
+
+ progress = {
+ SetChange = function(self, value)
+ self.EndValueSetting = value or 0
+ end,
+
+ GetChange = function(self)
+ return self.EndValueSetting
+ end,
+
+ GetProgress = function(self)
+ return self.ValueOffset
+ end,
+
+ Reset = function(self)
+ self.Timer = 0
+ self.Parent:SetValue(self.StartValue)
+ end,
+ },
+
+ number = {
+ SetChange = function(self, value)
+ self.EndNumberSetting = value or 0
+ end,
+
+ GetChange = function(self)
+ return self.EndNumberSetting
+ end,
+
+ SetStart = function(self, value)
+ self.StartNumber = value
+ end,
+
+ GetStart = function(self, value)
+ return self.StartNumber
+ end,
+
+ SetPrefix = function(self, text)
+ self.Prefix = text or ""
+ end,
+
+ GetPrefix = function(self)
+ return self.Prefix
+ end,
+
+ SetPostfix = function(self, text)
+ self.Postfix = text or ""
+ end,
+
+ GetPostfix = function(self)
+ return self.Postfix
+ end,
+
+ GetProgress = function(self)
+ return self.NumberOffset
+ end,
+
+ Reset = function(self)
+ self.Timer = 0
+ self.Parent:SetText(self.StartNumber)
+ end,
+ },
+
+ sleep = {
+ GetProgress = function(self)
+ return self.Timer
+ end,
+
+ Reset = function(self)
+ self.Timer = 0
+ end,
+ },
+}
+
+local GroupMethods = {
+ Play = function(self)
+ for i = 1, #self.Animations do
+ if (self.Animations[i].Order == self.Order) then
+ self.Animations[i]:Play()
+ end
+ end
+
+ self.Playing = true
+ self.Paused = false
+ self.Stopped = false
+
+ self:Callback("OnPlay")
+ end,
+
+ IsPlaying = function(self)
+ return self.Playing
+ end,
+
+ Pause = function(self)
+ for i = 1, #self.Animations do
+ if (self.Animations[i].Order == self.Order) then
+ self.Animations[i]:Pause()
+ end
+ end
+
+ self.Playing = false
+ self.Paused = true
+ self.Stopped = false
+
+ self:Callback("OnPause")
+ end,
+
+ IsPaused = function(self)
+ return self.Paused
+ end,
+
+ Stop = function(self)
+ for i = 1, #self.Animations do
+ self.Animations[i]:Stop()
+ end
+
+ self.Playing = false
+ self.Paused = false
+ self.Stopped = true
+ self.Order = 1
+
+ self:Callback("OnStop")
+ end,
+
+ IsStopped = function(self)
+ return self.Stopped
+ end,
+
+ SetLooping = function(self, shouldLoop)
+ self.Looping = shouldLoop
+ end,
+
+ GetLooping = function(self)
+ return self.Looping
+ end,
+
+ GetParent = function(self)
+ return self.Parent
+ end,
+
+ SetScript = function(self, handler, func)
+ handler = lower(handler)
+
+ if Callbacks[handler] then
+ Callbacks[handler][self] = func
+ end
+ end,
+
+ GetScript = function(self, handler)
+ handler = lower(handler)
+
+ if (Callbacks[handler] and Callbacks[handler][self]) then
+ return Callbacks[handler][self]
+ end
+ end,
+
+ Callback = function(self, handler)
+ handler = lower(handler)
+
+ if Callbacks[handler][self] then
+ Callbacks[handler][self](self)
+ end
+ end,
+
+ CheckOrder = function(self)
+ -- Check if we're done all animations at the current order, then proceed to the next order.
+ local NumAtOrder = 0
+ local NumDoneAtOrder = 0
+
+ for i = 1, #self.Animations do
+ if (self.Animations[i].Order == self.Order) then
+ NumAtOrder = NumAtOrder + 1
+
+ if (not self.Animations[i].Playing) then
+ NumDoneAtOrder = NumDoneAtOrder + 1
+ end
+ end
+ end
+
+ -- All the animations at x order finished, go to next order
+ if (NumAtOrder == NumDoneAtOrder) then
+ self.Order = self.Order + 1
+
+ -- We exceeded max order, reset to 1 and bail the function, or restart if we're looping
+ if (self.Order > self.MaxOrder) then
+ self.Order = 1
+
+ self:Callback("OnFinished")
+
+ if (self.Stopped or not self.Looping) then
+ self.Playing = false
+
+ return
+ end
+ end
+
+ -- Play!
+ for i = 1, #self.Animations do
+ if (self.Animations[i].Order == self.Order) then
+ self.Animations[i]:Play()
+ end
+ end
+ end
+ end,
+
+ CreateAnimation = function(self, style)
+ style = lower(style)
+
+ if (not Initialize[style]) then
+ return
+ end
+
+ local Animation = {}
+
+ -- General methods
+ for key, func in pairs(AnimMethods.All) do
+ Animation[key] = func
+ end
+
+ -- Animation specific methods
+ if AnimMethods[style] then
+ for key, func in pairs(AnimMethods[style]) do
+ Animation[key] = func
+ end
+ end
+
+ -- Set some attributes and defaults
+ Animation.Paused = false
+ Animation.Playing = false
+ Animation.Stopped = false
+ Animation.Looping = false
+ Animation.Type = style
+ Animation.Group = self
+ Animation.Parent = self.Parent
+ Animation.Order = 1
+ Animation.Duration = 0.3
+ Animation.Easing = "linear"
+ Animation.Update = Update[style]
+
+ tinsert(self.Animations, Animation)
+
+ return Animation
+ end,
+}
+
+CreateAnimationGroup = function(parent)
+ local Group = {Animations = {}}
+
+ -- Add methods to the group
+ for key, func in pairs(GroupMethods) do
+ Group[key] = func
+ end
+
+ Group.Parent = parent
+ Group.Playing = false
+ Group.Paused = false
+ Group.Stopped = false
+ Group.Order = 1
+ Group.MaxOrder = 1
+
+ return Group
+end
+
+-- Movement
+Initialize["move"] = function(self)
+ if self.Playing then
+ return
+ end
+
+ local A1, P, A2, X, Y = self.Parent:GetPoint()
+
+ self.Timer = 0
+ self.A1 = A1
+ self.P = P
+ self.A2 = A2
+ self.StartX = X
+ self.EndX = X + self.XSetting or 0
+ self.StartY = Y
+ self.EndY = Y + self.YSetting or 0
+ self.XChange = self.EndX - self.StartX
+ self.YChange = self.EndY - self.StartY
+
+ if self.IsRounded then
+ if (self.XChange == 0 or self.YChange == 0) then -- Double check if we're valid to be rounded
+ self.IsRounded = false
+ else
+ self.ModTimer = 0
+ end
+ end
+
+ StartUpdating(self)
+end
+
+Update["move"] = function(self, elapsed, i)
+ self.Timer = self.Timer + elapsed
+
+ if (self.Timer >= self.Duration) then
+ tremove(Updater, i)
+ self.Parent:SetPoint(self.A1, self.P, self.A2, self.EndX, self.EndY)
+ self.Playing = false
+ self:Callback("OnFinished")
+ self.Group:CheckOrder()
+ else
+ if self.IsRounded then
+ self.ModTimer = Easing[self.Easing](self.Timer, 0, self.Duration, self.Duration)
+ self.XOffset = self.StartX - (-1) * (self.XChange * (1 - cos(90 * self.ModTimer / self.Duration)))
+ self.YOffset = self.StartY + self.YChange * sin(90 * self.ModTimer / self.Duration)
+ else
+ self.XOffset = Easing[self.Easing](self.Timer, self.StartX, self.XChange, self.Duration)
+ self.YOffset = Easing[self.Easing](self.Timer, self.StartY, self.YChange, self.Duration)
+ end
+
+ self.Parent:SetPoint(self.A1, self.P, self.A2, (self.EndX ~= 0 and self.XOffset or self.StartX), (self.EndY ~= 0 and self.YOffset or self.StartY))
+ end
+end
+
+-- Fade
+Initialize["fade"] = function(self)
+ if self.Playing then
+ return
+ end
+
+ self.Timer = 0
+ self.StartAlpha = self.Parent:GetAlpha() or 1
+ self.EndAlpha = self.EndAlphaSetting or 0
+ self.Change = self.EndAlpha - self.StartAlpha
+
+ StartUpdating(self)
+end
+
+Update["fade"] = function(self, elapsed, i)
+ self.Timer = self.Timer + elapsed
+
+ if (self.Timer >= self.Duration) then
+ tremove(Updater, i)
+ self.Parent:SetAlpha(self.EndAlpha)
+ self.Playing = false
+ self:Callback("OnFinished")
+ self.Group:CheckOrder()
+ else
+ self.AlphaOffset = Easing[self.Easing](self.Timer, self.StartAlpha, self.Change, self.Duration)
+ self.Parent:SetAlpha(self.AlphaOffset)
+ end
+end
+
+-- Height
+Initialize["height"] = function(self)
+ if self.Playing then
+ return
+ end
+
+ self.Timer = 0
+ self.StartHeight = self.Parent:GetHeight() or 0
+ self.EndHeight = self.EndHeightSetting or 0
+ self.HeightChange = self.EndHeight - self.StartHeight
+
+ StartUpdating(self)
+end
+
+Update["height"] = function(self, elapsed, i)
+ self.Timer = self.Timer + elapsed
+
+ if (self.Timer >= self.Duration) then
+ tremove(Updater, i)
+ self.Parent:SetHeight(self.EndHeight)
+ self.Playing = false
+ self:Callback("OnFinished")
+ self.Group:CheckOrder()
+ else
+ self.HeightOffset = Easing[self.Easing](self.Timer, self.StartHeight, self.HeightChange, self.Duration)
+ self.Parent:SetHeight(self.HeightOffset)
+ end
+end
+
+-- Width
+Initialize["width"] = function(self)
+ if self.Playing then
+ return
+ end
+
+ self.Timer = 0
+ self.StartWidth = self.Parent:GetWidth() or 0
+ self.EndWidth = self.EndWidthSetting or 0
+ self.WidthChange = self.EndWidth - self.StartWidth
+
+ StartUpdating(self)
+end
+
+Update["width"] = function(self, elapsed, i)
+ self.Timer = self.Timer + elapsed
+
+ if (self.Timer >= self.Duration) then
+ tremove(Updater, i)
+ self.Parent:SetWidth(self.EndWidth)
+ self.Playing = false
+ self:Callback("OnFinished")
+ self.Group:CheckOrder()
+ else
+ self.WidthOffset = Easing[self.Easing](self.Timer, self.StartWidth, self.WidthChange, self.Duration)
+ self.Parent:SetWidth(self.WidthOffset)
+ end
+end
+
+-- Color
+Initialize["color"] = function(self)
+ self.Timer = 0
+ self.ColorType = self.ColorType or "backdrop"
+ self.StartR, self.StartG, self.StartB = Get[self.ColorType](self.Parent)
+ self.EndR = self.EndRSetting or 1
+ self.EndG = self.EndGSetting or 1
+ self.EndB = self.EndBSetting or 1
+
+ StartUpdating(self)
+end
+
+Update["color"] = function(self, elapsed, i)
+ self.Timer = self.Timer + elapsed
+
+ if (self.Timer >= self.Duration) then
+ tremove(Updater, i)
+ Set[self.ColorType](self.Parent, self.EndR, self.EndG, self.EndB)
+ self.Playing = false
+ self:Callback("OnFinished")
+ self.Group:CheckOrder()
+ else
+ self.ColorOffset = Easing[self.Easing](self.Timer, 0, self.Duration, self.Duration)
+ Set[self.ColorType](self.Parent, GetColor(self.Timer / self.Duration, self.StartR, self.StartG, self.StartB, self.EndR, self.EndG, self.EndB))
+ end
+end
+
+-- Progress
+Initialize["progress"] = function(self)
+ self.Timer = 0
+ self.StartValue = self.Parent:GetValue() or 0
+ self.EndValue = self.EndValueSetting or 0
+ self.ProgressChange = self.EndValue - self.StartValue
+
+ StartUpdating(self)
+end
+
+Update["progress"] = function(self, elapsed, i)
+ self.Timer = self.Timer + elapsed
+
+ if (self.Timer >= self.Duration) then
+ tremove(Updater, i)
+ self.Parent:SetValue(self.EndValue)
+ self.Playing = false
+ self:Callback("OnFinished")
+ self.Group:CheckOrder()
+ else
+ self.ValueOffset = Easing[self.Easing](self.Timer, self.StartValue, self.ProgressChange, self.Duration)
+ self.Parent:SetValue(self.ValueOffset)
+ end
+end
+
+-- Sleep
+Initialize["sleep"] = function(self)
+ self.Timer = 0
+
+ StartUpdating(self)
+end
+
+Update["sleep"] = function(self, elapsed, i)
+ self.Timer = self.Timer + elapsed
+
+ if (self.Timer >= self.Duration) then
+ tremove(Updater, i)
+ self.Playing = false
+ self:Callback("OnFinished")
+ self.Group:CheckOrder()
+ end
+end
+
+-- Number
+Initialize["number"] = function(self)
+ self.Timer = 0
+
+ if (not self.StartNumber) then
+ self.StartNumber = tonumber(self.Parent:GetText()) or 0
+ end
+
+ self.EndNumber = self.EndNumberSetting or 0
+ self.NumberChange = self.EndNumberSetting - self.StartNumber
+ self.Prefix = self.Prefix or ""
+ self.Postfix = self.Postfix or ""
+
+ StartUpdating(self)
+end
+
+Update["number"] = function(self, elapsed, i)
+ self.Timer = self.Timer + elapsed
+
+ if (self.Timer >= self.Duration) then
+ tremove(Updater, i)
+ self.Parent:SetText(self.Prefix..floor(self.EndNumber)..self.Postfix)
+ self.Playing = false
+ self:Callback("OnFinished")
+ self.Group:CheckOrder()
+ else
+ self.NumberOffset = Easing[self.Easing](self.Timer, self.StartNumber, self.NumberChange, self.Duration)
+ self.Parent:SetText(self.Prefix..floor(self.NumberOffset)..self.Postfix)
+ end
+end
+
+-- Global exposure
+_G["_LibAnim"] = Version
+
+LibAnimStartUpdating = StartUpdating
+LibAnimUpdater = Updater
+
+function LibAnimAddType(name, init, update)
+ if (type(init) ~= "function" or type(update) ~= "function") then
+ return
+ end
+
+ name = lower(name)
+
+ if Initialize[name] then
+ return
+ end
+
+ Initialize[name] = init
+ Update[name] = update
+end
+
+--[[
+ Want to create your own animations for this system? Follow the example below
+ If you make a custom animation I would love to see it!
+
+ Example:
+
+ local MyInitialize = function(self)
+ self.Timer = 0
+
+ -- do any initialization right before the animation plays
+
+ LibAnimStartUpdating(self)
+ end
+
+ local MyUpdate = function(self, elapsed, i)
+ self.Timer = self.Timer + elapsed
+
+ if (self.Timer >= self.Duration) then
+ table.remove(LibAnimUpdater, i)
+
+ -- Set finished attributes here
+
+ self.Playing = false
+ self:Callback("OnFinished")
+ self.Group:CheckOrder()
+ else
+ -- Do any updating necessary here
+ end
+ end
+
+ LibAnimAddType("MyAnim", MyInitialize, MyUpdate)
+--]]
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibAuraInfo-1.0/LibAuraInfo-1.0.lua b/ElvUI/Libraries/LibAuraInfo-1.0/LibAuraInfo-1.0.lua
new file mode 100644
index 0000000..8ee22fb
--- /dev/null
+++ b/ElvUI/Libraries/LibAuraInfo-1.0/LibAuraInfo-1.0.lua
@@ -0,0 +1,1132 @@
+--[[
+Name: LibAuraInfo-1.0
+Author(s): Cyprias (cyprias@gmail.com)
+Documentation: http://www.wowace.com/addons/libaurainfo-1-0/
+SVN: svn://svn.wowace.com/wow/libaurainfo-1-0/mainline/trunk
+Description: Database of spellID's duration and debuff type.
+Dependencies: LibStub
+]]
+
+local MAJOR, MINOR = "LibAuraInfo-1.0-ElvUI", 18
+if not LibStub then error(MAJOR .. " requires LibStub") return end
+
+local lib = LibStub:NewLibrary(MAJOR, MINOR)
+if not lib then return end
+
+lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib)
+if not lib.callbacks then error(MAJOR .. " requires CallbackHandler-1.0") return end
+
+local pairs = pairs
+local select = select
+local tonumber = tonumber
+local band = bit.band
+local floor = math.floor
+local sub = string.sub
+local tinsert, tremove = table.insert, table.remove
+
+local UnitAura = UnitAura
+local UnitIsUnit = UnitIsUnit
+local UnitExists = UnitExists
+local UnitName = UnitName
+local UnitGUID = UnitGUID
+local GetSpellInfo = GetSpellInfo
+local GetSpellTexture = GetSpellTexture
+local GetTime = GetTime
+local COMBATLOG_OBJECT_TYPE_PLAYER = COMBATLOG_OBJECT_TYPE_PLAYER
+
+lib.confirmedDur = {}
+
+lib.GUIDBlackList = {}
+
+lib.GUIDDurations = {}
+
+lib.GUIDData_name = {}
+lib.GUIDData_flags = {}
+
+--Save debuffType as a number, then return as a string when requested.
+lib.debuffTypes = {
+ Magic = 1,
+ Disease = 2,
+ Poison = 3,
+ Curse = 4,
+}
+for name, id in pairs(lib.debuffTypes) do
+ lib.debuffTypes[id] = name
+end
+
+lib.trackAuras = true
+lib.callbacksUsed = {}
+
+function lib.callbacks:OnUsed(target, eventname)
+ lib.callbacksUsed[eventname] = lib.callbacksUsed[eventname] or {}
+ tinsert(lib.callbacksUsed[eventname], #lib.callbacksUsed[eventname]+1, target)
+ lib.trackAuras = true
+ lib.frame:RegisterEvent('COMBAT_LOG_EVENT_UNFILTERED')
+
+ lib.frame:RegisterEvent('UPDATE_MOUSEOVER_UNIT')
+ lib.frame:RegisterEvent('PLAYER_TARGET_CHANGED')
+ lib.frame:RegisterEvent('UNIT_TARGET')
+ lib.frame:RegisterEvent('UNIT_AURA')
+end
+
+function lib.callbacks:OnUnused(target, eventname)
+ if lib.callbacksUsed[eventname] then
+ for i = #lib.callbacksUsed[eventname], 1, -1 do
+ if lib.callbacksUsed[eventname][i] == target then
+ tremove(lib.callbacksUsed[eventname], i)
+ end
+ end
+ end
+
+ for event, value in pairs(lib.callbacksUsed) do
+ if #value == 0 then
+ lib.callbacksUsed[event] = nil
+ end
+ end
+
+ lib.trackAuras = false
+ lib.frame:UnregisterEvent('COMBAT_LOG_EVENT_UNFILTERED')
+
+ lib.frame:UnregisterEvent('UPDATE_MOUSEOVER_UNIT')
+ lib.frame:UnregisterEvent('PLAYER_TARGET_CHANGED')
+ lib.frame:UnregisterEvent('UNIT_TARGET')
+ lib.frame:UnregisterEvent('UNIT_AURA')
+end
+
+local function Round(num)
+ return floor(num + .5)
+end
+
+local function ResetUnitAuras(unitID)
+ lib:RemoveAllAurasFromGUID(UnitGUID(unitID))
+end
+
+function lib:AddAuraFromUnitID(dstGUID, name, texture, stackCount, debuffType, duration, expirationTime, srcGUID, spellID, filter)
+ self.GUIDAuras[dstGUID] = self.GUIDAuras[dstGUID] or {}
+ self.GUIDAuras[dstGUID][filter] = self.GUIDAuras[dstGUID][filter] or {}
+
+ tinsert(self.GUIDAuras[dstGUID][filter], #self.GUIDAuras[dstGUID][filter]+1, {
+ name = name,
+ texture = texture,
+ stackCount = stackCount,
+ debuffType = debuffType,
+ duration = duration,
+ expirationTime = expirationTime,
+ spellID = spellID,
+ srcGUID = srcGUID
+ })
+end
+
+local CheckUnitAuras
+do
+ local i
+ local _, name, texture, stackCount, dispelType, duration, expirationTime, unitCaster, spellID
+ local dstGUID, dstName, srcGUID
+ function CheckUnitAuras(unitID, filterType)
+ dstGUID, dstName = UnitGUID(unitID), UnitName(unitID)
+
+ if lib.GUIDData_name[dstGUID] ~= dstName then
+ lib.GUIDData_name[dstGUID] = dstName
+ end
+
+ --Since we have a unitID, lets clear our aura table and use 100% accurate aura info.
+ if lib.GUIDAuras[dstGUID] and lib.GUIDAuras[dstGUID][filterType] then
+ for j = #lib.GUIDAuras[dstGUID][filterType], 1, -1 do
+ tremove(lib.GUIDAuras[dstGUID][filterType], j)
+ end
+ end
+
+ i = 1
+ while true do
+ name, _, texture, stackCount, dispelType, duration, expirationTime, unitCaster, _, _, spellID = UnitAura(unitID, i, filterType)
+ if not name then break end
+
+ duration = Round(duration)
+
+ if not lib.spellDuration[spellID] then
+ lib.spellDuration[spellID] = duration
+ lib.spellDebuffType[spellID] = (dispelType and lib.debuffTypes[dispelType] or 0)
+ elseif not lib.auraInfoPvP[spellID] then
+ if unitCaster and UnitExists(unitCaster) then
+ srcGUID = UnitGUID(unitCaster)
+ local baseDuration = lib:GetDuration(spellID) --, nil, nil, UnitIsPlayer(unitID)
+ if baseDuration and baseDuration ~= duration then
+ if duration > 0 then -- Sometimes UnitAura says a spell has 0 duration when it realy has more.
+ --caster's duration doesn't match our DB, they're probably speced into something. lets remember that.
+ lib.GUIDDurations[srcGUID.."-"..spellID] = duration
+ end
+ end
+ end
+ end
+
+ if unitCaster and expirationTime > 0 then
+ srcGUID = srcGUID or UnitGUID(unitCaster)
+ lib:AddAuraFromUnitID(
+ dstGUID,
+ name,
+ texture,
+ stackCount and stackCount > 1 and stackCount or nil,
+ dispelType,
+ duration,
+ expirationTime,
+ srcGUID,
+ spellID,
+ filterType
+ )
+ end
+
+ i = i + 1
+ srcGUID = nil
+ end
+
+ lib.callbacks:Fire("LibAuraInfo_UNIT_AURA", dstGUID)
+ end
+end
+
+lib.frame = lib.frame or CreateFrame("Frame")
+lib.frame:SetScript("OnEvent", function(self, event, ...)
+ if self[event] then
+ self[event](self, event, ...)
+ end
+end)
+
+function lib.frame:UPDATE_MOUSEOVER_UNIT()
+ ResetUnitAuras("mouseover")
+ CheckUnitAuras("mouseover", "HELPFUL")
+ CheckUnitAuras("mouseover", "HARMFUL")
+end
+
+function lib.frame:PLAYER_TARGET_CHANGED()
+ ResetUnitAuras("target")
+ CheckUnitAuras("target", "HELPFUL")
+ CheckUnitAuras("target", "HARMFUL")
+end
+
+do
+ local targetID
+ function lib.frame:UNIT_TARGET(_, unitID)
+ if not UnitIsUnit(unitID, "player") then
+ targetID = unitID.."target"
+ ResetUnitAuras(targetID)
+ CheckUnitAuras(targetID, "HELPFUL")
+ CheckUnitAuras(targetID, "HARMFUL")
+ end
+ end
+end
+
+function lib.frame:UNIT_AURA(_, unitID)
+ if not unitID then return end
+ ResetUnitAuras(unitID)
+ CheckUnitAuras(unitID, "HELPFUL")
+ CheckUnitAuras(unitID, "HARMFUL")
+end
+
+------------------------------------------------------------------------------------------------------
+--~ Dimminshing Returns
+------------------------------------------------------------------------------------------------------
+
+lib.resetDRTime = 18 --Time it tacks for DR to reset.
+
+--[[
+ List of spellID's copied from DRData-1.0 by Shadowed.
+ http://www.wowace.com/addons/drdata-1-0/
+ http://www.wowace.com/profiles/Shadowed/
+]]
+lib.drSpells = {
+ --[[ TAUNT ]]--
+ -- Taunt (Warrior)
+ [355] = "taunt",
+ -- Taunt (Pet)
+ [53477] = "taunt",
+ -- Mocking Blow
+ [694] = "taunt",
+ -- Growl (Druid)
+ [6795] = "taunt",
+ -- Dark Command
+ [56222] = "taunt",
+ -- Hand of Reckoning
+ [62124] = "taunt",
+ -- Righteous Defense
+ [31790] = "taunt",
+ -- Distracting Shot
+ [20736] = "taunt",
+ -- Challenging Shout
+ [1161] = "taunt",
+ -- Challenging Roar
+ [5209] = "taunt",
+ -- Death Grip
+ [49560] = "taunt",
+ -- Challenging Howl
+ [59671] = "taunt",
+ -- Angered Earth
+ [36213] = "taunt",
+
+ --[[ DISORIENTS ]]--
+ -- Dragon's Breath
+ [31661] = "disorient",
+ [33041] = "disorient",
+ [33042] = "disorient",
+ [33043] = "disorient",
+ [42949] = "disorient",
+ [42950] = "disorient",
+
+ -- Hungering Cold
+ [49203] = "disorient",
+
+ -- Sap
+ [6770] = "disorient",
+ [2070] = "disorient",
+ [11297] = "disorient",
+ [51724] = "disorient",
+
+ -- Gouge
+ [1776] = "disorient",
+
+ -- Hex (Guessing)
+ [51514] = "disorient",
+
+ -- Shackle
+ [9484] = "disorient",
+ [9485] = "disorient",
+ [10955] = "disorient",
+
+ -- Polymorph
+ [118] = "disorient",
+ [12824] = "disorient",
+ [12825] = "disorient",
+ [28272] = "disorient",
+ [28271] = "disorient",
+ [12826] = "disorient",
+ [61305] = "disorient",
+ [61025] = "disorient",
+ [61721] = "disorient",
+ [61780] = "disorient",
+
+ -- Freezing Trap
+ [3355] = "disorient",
+ [14308] = "disorient",
+ [14309] = "disorient",
+
+ -- Freezing Arrow
+ [60210] = "disorient",
+
+ -- Wyvern Sting
+ [19386] = "disorient",
+ [24132] = "disorient",
+ [24133] = "disorient",
+ [27068] = "disorient",
+ [49011] = "disorient",
+ [49012] = "disorient",
+
+ -- Repentance
+ [20066] = "disorient",
+
+ --[[ SILENCES ]]--
+ -- Nether Shock
+ [53588] = "silence",
+ [53589] = "silence",
+
+ -- Garrote
+ [1330] = "silence",
+
+ -- Arcane Torrent (Energy version)
+ [25046] = "silence",
+
+ -- Arcane Torrent (Mana version)
+ [28730] = "silence",
+
+ -- Arcane Torrent (Runic power version)
+ [50613] = "silence",
+
+ -- Silence
+ [15487] = "silence",
+
+ -- Silencing Shot
+ [34490] = "silence",
+
+ -- Improved Kick
+ [18425] = "silence",
+
+ -- Improved Counterspell
+ [18469] = "silence",
+
+ -- Spell Lock
+ [19244] = "silence",
+ [19647] = "silence",
+
+ -- Shield of the Templar
+ [63529] = "silence",
+
+ -- Strangulate
+ [47476] = "silence",
+ [49913] = "silence",
+ [49914] = "silence",
+ [49915] = "silence",
+ [49916] = "silence",
+
+ -- Gag Order (Warrior talent)
+ [18498] = "silence",
+
+ --[[ DISARMS ]]--
+ -- Snatch
+ [53542] = "disarm",
+ [53543] = "disarm",
+
+ -- Dismantle
+ [51722] = "disarm",
+
+ -- Disarm
+ [676] = "disarm",
+
+ -- Chimera Shot - Scorpid
+ [53359] = "disarm",
+
+ -- Psychic Horror (Disarm effect)
+ [64058] = "disarm",
+
+ --[[ FEARS ]]--
+ -- Blind
+ [2094] = "fear",
+
+ -- Fear (Warlock)
+ [5782] = "fear",
+ [6213] = "fear",
+ [6215] = "fear",
+
+ -- Seduction (Pet)
+ [6358] = "fear",
+
+ -- Howl of Terror
+ [5484] = "fear",
+ [17928] = "fear",
+
+ -- Psychic scream
+ [8122] = "fear",
+ [8124] = "fear",
+ [10888] = "fear",
+ [10890] = "fear",
+
+ -- Scare Beast
+ [1513] = "fear",
+ [14326] = "fear",
+ [14327] = "fear",
+
+ -- Turn Evil
+ [10326] = "fear",
+
+ -- Intimidating Shout
+ [5246] = "fear",
+
+ --[[ CONTROL STUNS ]]--
+ -- Intercept (Felguard)
+ [30153] = "ctrlstun",
+ [30195] = "ctrlstun",
+ [30197] = "ctrlstun",
+ [47995] = "ctrlstun",
+
+ -- Ravage
+ [50518] = "ctrlstun",
+ [53558] = "ctrlstun",
+ [53559] = "ctrlstun",
+ [53560] = "ctrlstun",
+ [53561] = "ctrlstun",
+ [53562] = "ctrlstun",
+
+ -- Sonic Blast
+ [50519] = "ctrlstun",
+ [53564] = "ctrlstun",
+ [53565] = "ctrlstun",
+ [53566] = "ctrlstun",
+ [53567] = "ctrlstun",
+ [53568] = "ctrlstun",
+
+ -- Concussion Blow
+ [12809] = "ctrlstun",
+
+ -- Shockwave
+ [46968] = "ctrlstun",
+
+ -- Hammer of Justice
+ [853] = "ctrlstun",
+ [5588] = "ctrlstun",
+ [5589] = "ctrlstun",
+ [10308] = "ctrlstun",
+
+ -- Bash
+ [5211] = "ctrlstun",
+ [6798] = "ctrlstun",
+ [8983] = "ctrlstun",
+
+ --***********************************************************
+ -- Intimidation
+ [19577] = "ctrlstun",
+
+ -- Maim
+ [22570] = "ctrlstun",
+ [49802] = "ctrlstun",
+
+ -- Kidney Shot
+ [408] = "ctrlstun",
+ [8643] = "ctrlstun",
+
+ -- War Stomp
+ [20549] = "ctrlstun",
+
+ -- Intercept
+ [20252] = "ctrlstun",
+
+ -- Deep Freeze
+ [44572] = "ctrlstun",
+
+ -- Shadowfury
+ [30283] = "ctrlstun",
+ [30413] = "ctrlstun",
+ [30414] = "ctrlstun",
+
+ -- Holy Wrath
+ [2812] = "ctrlstun",
+
+ -- Inferno Effect
+ [22703] = "ctrlstun",
+
+ -- Demon Charge
+ [60995] = "ctrlstun",
+
+ -- Gnaw (Ghoul)
+ [47481] = "ctrlstun",
+
+ --[[ RANDOM STUNS ]]--
+ -- Impact
+ [12355] = "rndstun",
+
+ -- Stoneclaw Stun
+ [39796] = "rndstun",
+
+ -- Seal of Justice
+ [20170] = "rndstun",
+
+ -- Revenge Stun
+ [12798] = "rndstun",
+
+ --[[ CYCLONE ]]--
+ -- Cyclone
+ [33786] = "cyclone",
+
+ --[[ ROOTS ]]--
+ -- Freeze (Water Elemental)
+ [33395] = "ctrlroot",
+
+ -- Pin (Crab)
+ [50245] = "ctrlroot",
+ [53544] = "ctrlroot",
+ [53545] = "ctrlroot",
+ [53546] = "ctrlroot",
+ [53547] = "ctrlroot",
+ [53548] = "ctrlroot",
+
+ -- Frost Nova
+ [122] = "ctrlroot",
+ [865] = "ctrlroot",
+ [6131] = "ctrlroot",
+ [10230] = "ctrlroot",
+ [27088] = "ctrlroot",
+ [42917] = "ctrlroot",
+
+ -- Entangling Roots
+ [339] = "ctrlroot",
+ [1062] = "ctrlroot",
+ [5195] = "ctrlroot",
+ [5196] = "ctrlroot",
+ [9852] = "ctrlroot",
+ [9853] = "ctrlroot",
+ [26989] = "ctrlroot",
+ [53308] = "ctrlroot",
+
+ -- Nature's Grasp (Uses different spellIDs than Entangling Roots for the same spell)
+ [19970] = "ctrlroot",
+ [19971] = "ctrlroot",
+ [19972] = "ctrlroot",
+ [19973] = "ctrlroot",
+ [19974] = "ctrlroot",
+ [19975] = "ctrlroot",
+ [27010] = "ctrlroot",
+ [53313] = "ctrlroot",
+
+ -- Earthgrab (Storm, Earth and Fire talent)
+ [8377] = "ctrlroot",
+ [31983] = "ctrlroot",
+
+ -- Web (Spider)
+ [4167] = "ctrlroot",
+
+ -- Venom Web Spray (Silithid)
+ [54706] = "ctrlroot",
+ [55505] = "ctrlroot",
+ [55506] = "ctrlroot",
+ [55507] = "ctrlroot",
+ [55508] = "ctrlroot",
+ [55509] = "ctrlroot",
+
+ --[[ RANDOM ROOTS ]]--
+ -- Improved Hamstring
+ [23694] = "rndroot",
+
+ -- Frostbite
+ [12494] = "rndroot",
+
+ -- Shattered Barrier
+ [55080] = "rndroot",
+
+ --[[ SLEEPS ]]--
+ -- Hibernate
+ [2637] = "sleep",
+ [18657] = "sleep",
+ [18658] = "sleep",
+
+ --[[ HORROR ]]--
+ -- Death Coil
+ [6789] = "horror",
+ [17925] = "horror",
+ [17926] = "horror",
+ [27223] = "horror",
+ [47859] = "horror",
+ [47860] = "horror",
+
+ -- Psychic Horror
+ [64044] = "horror",
+
+ --[[ MISC ]]--
+ -- Scatter Shot
+ [19503] = "scatters",
+
+ -- Cheap Shot
+ [1833] = "cheapshot",
+
+ -- Pounce
+ [9005] = "cheapshot",
+ [9823] = "cheapshot",
+ [9827] = "cheapshot",
+ [27006] = "cheapshot",
+ [49803] = "cheapshot",
+
+ -- Charge
+ [7922] = "charge",
+
+ -- Mind Control
+ [605] = "mc",
+
+ -- Banish
+ [710] = "banish",
+ [18647] = "banish",
+
+ -- Entrapment
+ [64804] = "entrapment",
+ [19185] = "entrapment",
+}
+
+lib.pveDR = {
+ ["ctrlstun"] = true,
+ ["rndstun"] = true,
+ ["taunt"] = true,
+ ["cyclone"] = true,
+}
+
+lib.GUIDDrEffects_reset = {}
+lib.GUIDDrEffects_diminished = {}
+
+do
+ local drType, key, reset
+ function lib:GUIDGainedDRAura(dstGUID, spellID, dstIsPlayer)
+ drType = self.drSpells[spellID]
+
+ if dstIsPlayer or self.pveDR[drType] then
+ key = dstGUID..drType
+ reset = self.GUIDDrEffects_reset[key]
+ if reset and reset <= GetTime() then
+ self.GUIDDrEffects_diminished[key] = 1
+ end
+ end
+ end
+end
+
+local function NextDR(diminished)
+ if diminished == 1 then
+ return 0.50
+ elseif diminished == 0.50 then
+ return 0.25
+ end
+
+ return 0
+end
+
+do
+ local drType, key
+ function lib:GUIDRemovedDRAura(dstGUID, spellID, dstIsPlayer)
+ drType = self.drSpells[spellID]
+ if dstIsPlayer or self.pveDR[drType] then
+ key = dstGUID..drType
+ self.GUIDDrEffects_reset[key] = GetTime() + self.resetDRTime
+ self.GUIDDrEffects_diminished[key] = NextDR( self.GUIDDrEffects_diminished[key] or 1.0 )
+ end
+ end
+end
+
+do
+ local drType, key, reset
+ function lib:GetDRDuration(dstGUID, spellID, duration)
+ duration = duration or self:GetDuration(spellID, nil, dstGUID)
+ drType = self.drSpells[spellID]
+ if drType then
+ key = dstGUID..drType
+ reset = self.GUIDDrEffects_reset[key]
+ if reset and GetTime() < reset then
+ return duration * (self.GUIDDrEffects_diminished[key] or 1)
+ end
+ end
+
+ return duration
+ end
+end
+
+-------------------------------------------------------------------------------------------------------
+--~ Combatlog
+-------------------------------------------------------------------------------------------------------
+lib.GUIDAuras = lib.GUIDAuras or {}
+
+local function SaveGUIDInfo(guid, name, flags)
+ lib.GUIDData_name[guid] = name
+ lib.GUIDData_flags[guid] = flags
+end
+
+function lib:GetSpellTexture(spellID)
+ return GetSpellTexture(spellID) or select(3, GetSpellInfo(spellID))
+end
+
+function lib.frame:COMBAT_LOG_EVENT_UNFILTERED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, ...)
+ if lib.GUIDBlackList[dstGUID] then return end
+
+ if srcGUID and not lib.GUIDData_flags[srcGUID] then
+ SaveGUIDInfo(srcGUID, srcName, srcFlags)
+ end
+ if dstGUID and not lib.GUIDData_flags[dstGUID] then
+ SaveGUIDInfo(dstGUID, dstName, dstFlags)
+ end
+
+ if self[eventType] then
+ self[eventType](self, eventType, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, ...)
+ end
+end
+
+do
+ local data
+ -- Remove expired auras from a GUID
+ function lib:RemoveExpiredAuras(dstGUID)
+ if self.GUIDAuras[dstGUID] then
+ for filter in pairs(self.GUIDAuras[dstGUID]) do
+ for i = #self.GUIDAuras[dstGUID][filter], 1, -1 do
+ data = self.GUIDAuras[dstGUID][filter][i]
+ if GetTime() > data.expirationTime then
+ tremove(self.GUIDAuras[dstGUID][filter], i)
+ end
+ end
+ end
+ end
+ end
+end
+
+do
+ local duration
+ -- Add a auraID to our GUID list
+ function lib:AddAuraToGUID(dstGUID, name, texture, spellID, srcGUID, filter)
+ duration = self:GetDuration(spellID, srcGUID, dstGUID)
+
+ self.GUIDAuras[dstGUID] = self.GUIDAuras[dstGUID] or {}
+ self.GUIDAuras[dstGUID][filter] = self.GUIDAuras[dstGUID][filter] or {}
+
+ --[[
+ I didn't want to use tables this way when I started the project but due to multiple instnces of a spellID being on a GUID I couldn't do a hash table lookup.
+ I wanted do something like
+ GUIDAuras_Duration[dstGUID..spellID..srcGUID] = 30
+ but because UnitAura() sometimes doesn't return a unitID to get srcGUID, I had to do a index table. meh
+
+ ]]
+
+ tinsert(self.GUIDAuras[dstGUID][filter], #self.GUIDAuras[dstGUID][filter] + 1, {
+ name = name,
+ texture = texture,
+ debuffType = self:GetDebuffType(spellID),
+ duration = duration,
+ expirationTime = duration == 0 and 0 or GetTime() + duration,
+ spellID = spellID,
+ srcGUID = srcGUID,
+ isDebuff = filter
+ })
+
+ --~ table.sort(self.GUIDAuras[dstGUID], function(a,b)
+ --~ return a.expirationTime < b.expirationTime
+ --~ end)
+ end
+end
+
+do
+ local data
+ -- Increase stack count of a aura
+ function lib:AddAuraDose(dstGUID, spellID, srcGUID, filter)
+ if self.GUIDAuras[dstGUID] and self.GUIDAuras[dstGUID][filter] then
+ if srcGUID then
+ for i = 1, #self.GUIDAuras[dstGUID][filter] do
+ data = self.GUIDAuras[dstGUID][filter][i]
+ if data.spellID == spellID and data.srcGUID == srcGUID then
+ data.stackCount = (data.stackCount or 1) + 1
+ data.expirationTime = data.duration + GetTime()
+
+ return true, data.stackCount, data.expirationTime
+ end
+ end
+ end
+
+ for i = 1, #self.GUIDAuras[dstGUID][filter] do
+ data = self.GUIDAuras[dstGUID][filter][i]
+ if data.spellID == spellID then
+ data.stackCount = (data.stackCount or 1) + 1
+ data.expirationTime = data.duration + GetTime()
+
+ return true, data.stackCount, data.expirationTime
+ end
+ end
+ end
+
+ return false
+ end
+end
+
+do
+ local data
+ -- Remove 1 stack from a aura
+ function lib:RemoveAuraDose(dstGUID, spellID, srcGUID, filter)
+ if self.GUIDAuras[dstGUID] and self.GUIDAuras[dstGUID][filter] then
+ if srcGUID then
+ for i = 1, #self.GUIDAuras[dstGUID][filter] do
+ data = self.GUIDAuras[dstGUID][filter][i]
+ if data.spellID == spellID and data.srcGUID == srcGUID then
+ data.stackCount = (data.stackCount or 1) - 1
+ -- data.expirationTime = data.duration + GetTime()
+
+ return true, data.stackCount, data.expirationTime
+ end
+ end
+ end
+
+ for i = 1, #self.GUIDAuras[dstGUID][filter] do
+ data = self.GUIDAuras[dstGUID][filter][i]
+ if data.spellID == spellID then
+ data.stackCount = (data.stackCount or 1) - 1
+ -- data.expirationTime = data.duration + GetTime()
+
+ return true, data.stackCount, data.expirationTime
+ end
+ end
+ end
+
+ return false
+ end
+end
+
+do
+ local data
+ -- Refresh the start and expiration time of a aura
+ function lib:RefreshAura(dstGUID, spellID, srcGUID, filter)
+ if self.GUIDAuras[dstGUID] and self.GUIDAuras[dstGUID][filter] then
+ if srcGUID then
+ for i = 1, #self.GUIDAuras[dstGUID][filter] do
+ data = self.GUIDAuras[dstGUID][filter][i]
+ if data.spellID == spellID and data.srcGUID == srcGUID then
+ data.expirationTime = data.duration + GetTime()
+
+ return true, data.expirationTime
+ end
+ end
+ end
+
+ for i = 1, #self.GUIDAuras[dstGUID][filter] do
+ data = self.GUIDAuras[dstGUID][filter][i]
+ if data.spellID == spellID then
+ data.expirationTime = data.duration + GetTime()
+
+ return true, data.expirationTime
+ end
+ end
+ end
+
+ return false
+ end
+end
+
+do
+ local data
+ -- Remove a aura from a GUID
+ function lib:RemoveAuraFromGUID(dstGUID, spellID, srcGUID, filter)
+ if lib.GUIDAuras[dstGUID] and lib.GUIDAuras[dstGUID][filter] then
+ if srcGUID then
+ for i = #lib.GUIDAuras[dstGUID][filter],1, -1 do
+ data = lib.GUIDAuras[dstGUID][filter][i]
+ if data.spellID == spellID and srcGUID == data.srcGUID then
+ tremove(lib.GUIDAuras[dstGUID][filter], i)
+ lib.callbacks:Fire("RemoveAuraFromGUID", dstGUID)
+ return
+ end
+ end
+ end
+
+ for i = #lib.GUIDAuras[dstGUID][filter],1, -1 do
+ data = lib.GUIDAuras[dstGUID][filter][i]
+ if data.spellID == spellID then
+ tremove(lib.GUIDAuras[dstGUID][filter], i)
+ lib.callbacks:Fire("RemoveAuraFromGUID", dstGUID)
+ return
+ end
+ end
+
+ end
+ end
+end
+
+-- Remove all auras on a GUID. They must have died
+function lib:RemoveAllAurasFromGUID(dstGUID)
+ if self.GUIDAuras[dstGUID] then
+ for filter in pairs(self.GUIDAuras[dstGUID]) do
+ for i=#self.GUIDAuras[dstGUID][filter], 1, -1 do
+ tremove(self.GUIDAuras[dstGUID][filter], i)
+ end
+ end
+ end
+end
+
+function lib.frame:SPELL_AURA_REMOVED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
+ lib:RemoveAuraFromGUID(dstGUID, spellID, srcGUID, auraType == "DEBUFF" and "HARMFUL" or "HELPFUL")
+
+ if lib.drSpells[spellID] then
+ lib:GUIDRemovedDRAura(dstGUID, spellID, lib:FlagIsPlayer(dstFlags))
+ end
+ lib.callbacks:Fire("LibAuraInfo_AURA_REMOVED", dstGUID, spellID, srcGUID)
+end
+
+function lib.frame:SPELL_AURA_APPLIED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
+ if lib.drSpells[spellID] then
+ lib:GUIDGainedDRAura(dstGUID, spellID, lib:FlagIsPlayer(dstFlags))
+ end
+
+ if lib.spellDuration[spellID] then
+ lib:RemoveExpiredAuras(dstGUID)
+ lib:AddAuraToGUID(dstGUID, spellName, lib:GetSpellTexture(spellID), spellID, srcGUID, auraType == "DEBUFF" and "HARMFUL" or "HELPFUL")
+ lib.callbacks:Fire("LibAuraInfo_AURA_APPLIED", dstGUID, spellID, srcGUID, auraType)
+ end
+end
+
+do
+ local refreshed
+ function lib.frame:SPELL_AURA_REFRESH(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
+ if lib.drSpells[spellID] then
+ lib:GUIDRemovedDRAura(dstGUID, spellID, lib:FlagIsPlayer(dstFlags))
+ lib:GUIDGainedDRAura(dstGUID, spellID, lib:FlagIsPlayer(dstFlags))
+ end
+
+ refreshed = lib:RefreshAura(dstGUID, spellID, srcGUID, auraType == "DEBUFF" and "HARMFUL" or "HELPFUL")
+ if refreshed then
+ lib.callbacks:Fire("LibAuraInfo_AURA_REFRESH", dstGUID, spellID, srcGUID, spellSchool, auraType)
+ return
+ end
+
+ self:SPELL_AURA_APPLIED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
+ end
+end
+
+do
+ local dosed, stackCount, expirationTime
+ --DOSE = spell stacking
+ function lib.frame:SPELL_AURA_APPLIED_DOSE(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
+ dosed, stackCount, expirationTime = lib:AddAuraDose(dstGUID, spellID, srcGUID, auraType == "DEBUFF" and "HARMFUL" or "HELPFUL")
+ if dosed then
+ lib.callbacks:Fire("LibAuraInfo_AURA_APPLIED_DOSE", dstGUID, spellID, srcGUID, spellSchool, auraType, stackCount, expirationTime)
+ return
+ end
+
+ --Spell isn't in our list, let's add it.
+ --Note this event could have fired on the 5th stack but our spell frame will only show it applied once.
+ self:SPELL_AURA_APPLIED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
+ end
+end
+
+do
+ local dosed, stackCount, expirationTime
+ function lib.frame:SPELL_AURA_APPLIED_REMOVED_DOSE(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, spellID, spellName, spellSchool, auraType)
+ dosed, stackCount, expirationTime = lib:RemoveAuraDose(dstGUID, spellID, srcGUID, auraType == "DEBUFF" and "HARMFUL" or "HELPFUL")
+ if dosed then
+ lib.callbacks:Fire("LibAuraInfo_AURA_APPLIED_DOSE", dstGUID, spellID, srcGUID, spellSchool, auraType, stackCount, expirationTime)
+ return
+ end
+ end
+end
+
+function lib.frame:SPELL_AURA_BROKEN_SPELL(...)
+ self:SPELL_AURA_REMOVED(...)
+end
+
+function lib.frame:SPELL_AURA_BROKEN(...)
+ self:SPELL_AURA_REMOVED(...)
+end
+
+function lib.frame:UNIT_DIED(event, timestamp, eventType, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags, ...)
+ if lib.GUIDAuras[dstGUID] then
+ lib:RemoveAllAurasFromGUID(dstGUID)
+ lib.callbacks:Fire("LibAuraInfo_AURA_CLEAR", dstGUID)
+ end
+end
+
+function lib.frame:UNIT_DESTROYED(...)
+ self:UNIT_DIED(...)
+end
+
+function lib.frame:UNIT_DISSIPATES(...)
+ self:UNIT_DIED(...)
+end
+
+function lib.frame:PARTY_KILL(...)
+ self:UNIT_DIED(...)
+end
+
+function lib:FlagIsPlayer(flags)
+ if band(flags, COMBATLOG_OBJECT_TYPE_PLAYER) == COMBATLOG_OBJECT_TYPE_PLAYER then
+ return true
+ end
+end
+
+--------------------------------------------------------------
+--~ API
+--------------------------------------------------------------
+local GUIDIsPlayer
+do
+ local B, maskedB
+ function GUIDIsPlayer(guid)
+ B = tonumber(sub(guid, 5, 5), 16);
+ maskedB = B % 8; -- x % 8 has the same effect as x & 0x7 on numbers <= 0xf
+ -- local knownTypes = {[0]="player", [3]="NPC", [4]="pet", [5]="vehicle"};
+ -- print("Your target is a " .. (knownTypes[maskedB] or " unknown entity!"));
+ return maskedB == 0
+ end
+end
+
+do
+ local duration, dur
+ --Return the duration of a spell.
+ function lib:GetDuration(spellID, srcGUID, dstGUID, dstIsPlayer)
+ dstIsPlayer = dstIsPlayer or dstGUID and GUIDIsPlayer(dstGUID) or false
+ if dstIsPlayer and lib.auraInfoPvP[spellID] then
+ --Receiver is a player and the spell has a PvP duration. Return the pvp duration.
+ duration = lib.auraInfoPvP[spellID]
+ if dstGUID and duration then
+ --Check if there's dimminshing returns on the spell.
+ duration = self:GetDRDuration(dstGUID, spellID, duration)
+ end
+
+ return tonumber(duration or 0)
+ elseif self.spellDuration[spellID] then
+ --Check caster GUID was given.
+ if srcGUID then
+ --Check if we've seen that caster cast a spell with a duration that doesn't match our own (spec/glphed into something?)
+ if self.GUIDDurations[srcGUID.."-"..spellID] then
+ dur = self.GUIDDurations[srcGUID.."-"..spellID]
+ --Check if receiver GUID was given.
+ if dstGUID then
+ --Check if there's dimminshing returns on the spell.
+ dur = self:GetDRDuration(dstGUID, spellID, dur)
+ end
+ return dur
+ end
+ end
+
+ return self.spellDuration[spellID]
+ end
+ end
+end
+
+do
+ local debuffType
+ --Return the debuff type of a spell.
+ function lib:GetDebuffType(spellID)
+ if self.spellDuration[spellID] then
+ debuffType = self.spellDebuffType[spellID]
+ if debuffType then
+ return self.debuffTypes[debuffType] or "unknown"
+ end
+ return "none"--Lowercase because DebuffTypeColor["none"] is lowercase.
+ end
+ end
+end
+
+function lib:GetNumGUIDAuras(dstGUID)
+ self:RemoveExpiredAuras(dstGUID)
+
+ if self.GUIDAuras[dstGUID] then
+ local i = 0
+ for filter in pairs(self.GUIDAuras[dstGUID]) do
+ i = i + #self.GUIDAuras[dstGUID][filter]
+ end
+ return i
+ end
+
+ return 0
+end
+
+do
+ local data
+ function lib:GUIDAura(dstGUID, i, filter)
+ if self.GUIDAuras[dstGUID] and self.GUIDAuras[dstGUID][filter] and self.GUIDAuras[dstGUID][filter][i] then
+ data = self.GUIDAuras[dstGUID][filter][i]
+ return true, data.name, data.texture, data.stackCount or 0, data.debuffType, data.duration, data.expirationTime, data.srcGUID, data.spellID
+ end
+ return false
+ end
+end
+
+do
+ local data
+ function lib:GUIDAuraID(dstGUID, spellID, srcGUID, filter)
+ if self.GUIDAuras[dstGUID] and self.GUIDAuras[dstGUID][filter] then
+ if srcGUID then
+ for i = 1, #self.GUIDAuras[dstGUID][filter] do
+ data = self.GUIDAuras[dstGUID][filter][i]
+ if data.spellID == spellID and data.srcGUID == srcGUID then
+ return true, data.stackCount or 0, data.debuffType, data.duration, data.expirationTime, data.isDebuff, data.srcGUID
+ end
+ end
+ end
+ for i = 1, #self.GUIDAuras[dstGUID][filter] do
+ data = self.GUIDAuras[dstGUID][filter][i]
+ if data.spellID == spellID then
+ return true, data.stackCount or 0, data.debuffType, data.duration, data.expirationTime, data.isDebuff, data.srcGUID
+ end
+ end
+ end
+ return false
+ end
+end
+
+do
+ local drType, key, reset
+ function lib:HasDREffect(dstGUID, spellID)
+ drType = self.drSpells[spellID]
+ if drType then
+ key = dstGUID..drType
+ reset = self.GUIDDrEffects_reset[key]
+ if reset and GetTime() < reset then
+ return true, (self.GUIDDrEffects_diminished[key] or 1)
+ end
+ end
+ return false
+ end
+end
+
+function lib:GetGUIDInfo(GUID)
+ return self.GUIDData_name[GUID], self.GUIDData_flags[GUID]
+end
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibAuraInfo-1.0/lib.xml b/ElvUI/Libraries/LibAuraInfo-1.0/lib.xml
new file mode 100644
index 0000000..d989b57
--- /dev/null
+++ b/ElvUI/Libraries/LibAuraInfo-1.0/lib.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibAuraInfo-1.0/spellIdData.lua b/ElvUI/Libraries/LibAuraInfo-1.0/spellIdData.lua
new file mode 100644
index 0000000..86f229d
--- /dev/null
+++ b/ElvUI/Libraries/LibAuraInfo-1.0/spellIdData.lua
@@ -0,0 +1,3332 @@
+--[[
+ This file keeps track of aura duration and debuff type.
+
+ lib.spellDuration: [spellID] = duration
+
+ lib.spellDebuffType: [spellID] = debuffType
+ debuffTypes: Magic = 1, Disease = 2, Poison = 3, Curse = 4, Enrage = 5, Invisibility = 6
+]]
+
+local lib = LibStub("LibAuraInfo-1.0-ElvUI")
+if not lib then error("spellIdData.lua for LibAuraInfo needs library loaded.") return end
+if lib.spellDuration then return end
+
+lib.spellDuration = {
+ [10] = 8, -- Blizzard
+ [17] = 30, -- Power Word: Shield
+ [66] = 3, -- Invisibility
+ [67] = 10, -- Vindication (Rank 1)
+ [71] = 0, -- Defensive Stance
+ [99] = 30, -- Demoralizing Roar (Rank 1)
+ [113] = 15, -- Chains of Ice (Rank 1)
+ [116] = 8, -- Frostbolt (Rank 1)
+ [118] = 50, -- Polymorph (Rank 1)
+ [120] = 8, -- Cone of Cold (Rank 1)
+ [122] = 8, -- Frost Nova (Rank 1)
+ [126] = 45, -- Eye of Kilrogg (Summon)
+ [130] = 30, -- Slow Fall
+ [131] = 600, -- Water Breathing
+ [132] = 600, -- Detect Invisibility
+ [133] = 4, -- Fireball (Rank 1)
+ [136] = 10, -- Mend Pet
+ [139] = 15, -- Renew (Rank 1)
+ [168] = 1800, -- Frost Armor (Rank 1)
+ [172] = 12, -- Corruption (Rank 1)
+ [324] = 600, -- Lightning Shield (Rank 1)
+ [325] = 600, -- Lightning Shield (Rank 2)
+ [339] = 27, -- Entangling Roots (Rank 1)
+ [348] = 15, -- Immolate (Rank 1)
+ [355] = 3, -- Taunt
+ [408] = 1, -- Kidney Shot (Rank 1)
+ [430] = 18, -- Drink
+ [431] = 21, -- Drink
+ [432] = 24, -- Drink
+ [434] = 21, -- Food
+ [435] = 24, -- Food
+ [453] = 15, -- Mind Soothe
+ [465] = 0, -- Devotion Aura (Rank 1)
+ [467] = 600, -- Thorns (Rank 1)
+ [469] = 120, -- Commanding Shout (Rank 1)
+ [498] = 12, -- Divine Protection
+ [543] = 30, -- Fire Ward (Rank 1)
+ [546] = 600, -- Water Walking
+ [552] = 12, -- Abolish Disease
+ [580] = 0, -- Timber Wolf
+ [586] = 10, -- Fade
+ [588] = 1800, -- Inner Fire (Rank 1)
+ [589] = 18, -- Shadow Word: Pain (Rank 1)
+ [592] = 30, -- Power Word: Shield (Rank 2)
+ [594] = 18, -- Shadow Word: Pain (Rank 2)
+ [600] = 30, -- Power Word: Shield (Rank 3)
+ [602] = 1800, -- Inner Fire (Rank 3)
+ [603] = 60, -- Bane of Doom
+ [604] = 600, -- Dampen Magic (Rank 1)
+ [605] = 60, -- Mind Control
+ [642] = 12, -- Divine Shield
+ [643] = 0, -- Devotion Aura (Rank 3)
+ [673] = 3600, -- Lesser Armor
+ [676] = 10, -- Disarm
+ [687] = 1800, -- Demon Skin (Rank 1)
+ [689] = 5, -- Drain Life (Rank 1)
+ [694] = 6, -- Mocking Blow
+ [696] = 1800, -- Demon Skin (Rank 2)
+ [699] = 5, -- Drain Life (Rank 2)
+ [700] = 20, -- Sleep (Rank 1)
+ [702] = 120, -- Curse of Weakness (Rank 1)
+ [703] = 18, -- Garrote (Rank 1)
+ [706] = 1800, -- Demon Armor (Rank 1)
+ [707] = 15, -- Immolate (Rank 2)
+ [709] = 5, -- Drain Life (Rank 3)
+ [710] = 20, -- Banish (Rank 1)
+ [740] = 8, -- Tranquility (Rank 1)
+ [744] = 30, -- Poison
+ [745] = 5, -- Web
+ [746] = 6, -- First Aid
+ [755] = 10, -- Health Funnel (Rank 1)
+ [768] = 0, -- Cat Form (Shapeshift)
+ [770] = 300, -- Faerie Fire
+ [774] = 15, -- Rejuvenation (Rank 1)
+ [782] = 600, -- Thorns (Rank 2)
+ [783] = 0, -- Travel Form (Shapeshift)
+ [837] = 6, -- Frostbolt (Rank 3)
+ [853] = 3, -- Hammer of Justice (Rank 1)
+ [865] = 8, -- Frost Nova (Rank 2)
+ [871] = 12, -- Shield Wall
+ [879] = 6, -- Exorcism
+ [905] = 600, -- Lightning Shield (Rank 3)
+ [945] = 600, -- Lightning Shield (Rank 4)
+ [970] = 18, -- Shadow Word: Pain (Rank 3)
+ [974] = 600, -- Earth Shield
+ [976] = 600, -- Shadow Protection (Rank 1)
+ [980] = 24, -- Curse of Agony (Rank 1)
+ [982] = 3, -- Revive Pet
+ [992] = 18, -- Shadow Word: Pain (Rank 4)
+ [1002] = 60, -- Eyes of the Beast
+ [1006] = 1800, -- Inner Fire (Rank 4)
+ [1008] = 600, -- Amplify Magic (Rank 1)
+ [1014] = 24, -- Curse of Agony (Rank 2)
+ [1022] = 10, -- Hand of Protection
+ [1032] = 0, -- Devotion Aura (Rank 5)
+ [1038] = 10, -- Hand of Salvation
+ [1044] = 6, -- Hand of Freedom
+ [1062] = 15, -- Entangling Roots (Rank 2)
+ [1066] = 0, -- Aquatic Form (Shapeshift)
+ [1075] = 600, -- Thorns (Rank 3)
+ [1079] = 12, -- Rip (Rank 1)
+ [1086] = 1800, -- Demon Armor (Rank 2)
+ [1094] = 15, -- Immolate (Rank 3)
+ [1108] = 120, -- Curse of Weakness (Rank 2)
+ [1120] = 15, -- Drain Soul (Rank 1)
+ [1126] = 1800, -- Mark of the Wild (Rank 1)
+ [1127] = 27, -- Food
+ [1129] = 30, -- Food
+ [1130] = 300, -- Hunter's Mark (Rank 1)
+ [1133] = 27, -- Drink
+ [1134] = 15, -- Inner Rage
+ [1135] = 30, -- Drink
+ [1137] = 30, -- Drink
+ [1159] = 6, -- First Aid (Rank 2)
+ [1160] = 30, -- Demoralizing Shout (Rank 1)
+ [1161] = 6, -- Challenging Shout
+ [1243] = 1800, -- Power Word: Fortitude (Rank 1)
+ [1244] = 1800, -- Power Word: Fortitude (Rank 2)
+ [1245] = 1800, -- Power Word: Fortitude (Rank 3)
+ [1330] = 3, -- Garrote - Silence
+ [1430] = 15, -- Rejuvenation (Rank 3)
+ [1459] = 1800, -- Arcane Intellect (Rank 1)
+ [1460] = 1800, -- Arcane Intellect (Rank 2)
+ [1461] = 1800, -- Arcane Intellect (Rank 3)
+ [1463] = 60, -- Mana Shield (Rank 1)
+ [1490] = 300, -- Curse of the Elements (Rank 1)
+ [1513] = 20, -- Scare Beast (Rank 1)
+ [1539] = 10, -- Feed Pet
+ [1543] = 0, -- Flare
+ [1604] = 4, -- Dazed
+ [1706] = 120, -- Levitate
+ [1714] = 30, -- Curse of Tongues
+ [1715] = 15, -- Hamstring
+ [1719] = 12, -- Recklessness
+ [1735] = 30, -- Demoralizing Roar (Rank 2)
+ [1742] = 6, -- Cower
+ [1776] = 4, -- Gouge
+ [1784] = 0, -- Stealth
+ [1822] = 9, -- Rake (Rank 1)
+ [1823] = 9, -- Rake (Rank 2)
+ [1833] = 4, -- Cheap Shot
+ [1850] = 15, -- Dash (Rank 1)
+ [1943] = 16, -- Rupture (Rank 1)
+ [1949] = 15, -- Hellfire
+ [1953] = 1, -- Blink
+ [1978] = 15, -- Serpent Sting
+ [2048] = 240, -- Battle Shout (Rank 8)
+ [2070] = 35, -- Sap (Rank 2)
+ [2090] = 15, -- Rejuvenation (Rank 4)
+ [2091] = 15, -- Rejuvenation (Rank 5)
+ [2094] = 10, -- Blind
+ [2367] = 3600, -- Lesser Strength
+ [2374] = 3600, -- Lesser Agility
+ [2378] = 3600, -- Health
+ [2457] = 0, -- Battle Stance
+ [2458] = 0, -- Berserker Stance
+ [2479] = 30, -- Honorless Target
+ [2565] = 10, -- Shield Block
+ [2584] = 0, -- Waiting to Resurrect
+ [2601] = 30, -- Fire Shield III
+ [2602] = 15, -- Fire Shield IV
+ [2645] = 0, -- Ghost Wolf
+ [2767] = 18, -- Shadow Word: Pain (Rank 5)
+ [2791] = 1800, -- Power Word: Fortitude (Rank 4)
+ [2812] = 3, -- Holy Wrath
+ [2818] = 12, -- Deadly Poison (Rank 1)
+ [2819] = 12, -- Deadly Poison II (Rank 2)
+ [2825] = 40, -- Bloodlust
+ [2893] = 12, -- Abolish Poison
+ [2895] = 0, -- Wrath of Air Totem
+ [2941] = 15, -- Immolate (Rank 4)
+ [2944] = 24, -- Devouring Plague (Rank 1)
+ [2947] = 180, -- Fire Shield (Rank 1)
+ [2974] = 10, -- Wing Clip
+ [2983] = 15, -- Sprint (Rank 1)
+ [3034] = 8, -- Viper Sting
+ [3043] = 20, -- Scorpid Sting
+ [3045] = 15, -- Rapid Fire
+ [3140] = 8, -- Fireball (Rank 4)
+ [3166] = 3600, -- Lesser Intellect
+ [3219] = 3600, -- Weak Troll's Blood Elixir
+ [3220] = 3600, -- Armor
+ [3222] = 7200, -- Strong Troll's Blood Elixir
+ [3248] = 6, -- Improved Blocking
+ [3256] = 240, -- Plague Cloud
+ [3267] = 7, -- First Aid (Rank 3)
+ [3355] = 20, -- Freezing Trap Effect (Rank 1)
+ [3356] = 45, -- Flame Lash
+ [3409] = 12, -- Crippling Poison
+ [3419] = 6, -- Improved Blocking
+ [3427] = 30, -- Infected Wound
+ [3436] = 300, -- Wandering Plague
+ [3439] = 300, -- Wandering Plague
+ [3583] = 60, -- Deadly Poison
+ [3593] = 3600, -- Elixir of Fortitude
+ [3600] = 5, -- Earthbind
+ [3603] = 15, -- Distracting Pain
+ [3604] = 8, -- Tendon Rip
+ [3627] = 15, -- Rejuvenation (Rank 6)
+ [3639] = 6, -- Improved Blocking
+ [3661] = 15, -- Mend Pet (Rank 3)
+ [3662] = 15, -- Mend Pet (Rank 4)
+ [3674] = 15, -- Black Arrow
+ [3698] = 10, -- Health Funnel (Rank 2)
+ [3699] = 7, -- Health Funnel (Rank 3)
+ [3700] = 10, -- Health Funnel (Rank 4)
+ [3714] = 600, -- Path of Frost
+ [3742] = 15, -- Static Electricity
+ [3747] = 30, -- Power Word: Shield (Rank 4)
+ [3815] = 45, -- Poison Cloud
+ [4167] = 4, -- Web (Rank 1)
+ [4318] = 1800, -- Guile of the Raptor
+ [4511] = 0, -- Phase Shift
+ [5005] = 21, -- Food
+ [5115] = 6, -- Battle Command
+ [5116] = 4, -- Concussive Shot
+ [5118] = 0, -- Aspect of the Cheetah
+ [5137] = 60, -- Call of the Grave
+ [5138] = 5, -- Drain Mana
+ [5159] = 20, -- Melt Ore
+ [5171] = 12, -- Slice and Dice (Rank 1)
+ [5195] = 18, -- Entangling Roots (Rank 3)
+ [5196] = 21, -- Entangling Roots (Rank 4)
+ [5209] = 6, -- Challenging Roar
+ [5211] = 2, -- Bash (Rank 1)
+ [5213] = 15, -- Molten Metal
+ [5215] = 0, -- Prowl
+ [5217] = 6, -- Tiger's Fury (Rank 1)
+ [5225] = 0, -- Track Humanoids
+ [5229] = 10, -- Enrage
+ [5232] = 1800, -- Mark of the Wild (Rank 2)
+ [5234] = 1800, -- Mark of the Wild (Rank 4)
+ [5242] = 120, -- Battle Shout (Rank 2)
+ [5246] = 8, -- Intimidating Shout
+ [5262] = 10, -- Fanatic Blade
+ [5277] = 15, -- Evasion (Rank 1)
+ [5280] = 45, -- Razor Mane (Rank 1)
+ [5384] = 360, -- Feign Death
+ [5403] = 6, -- Crash of Waves
+ [5413] = 120, -- Noxious Catalyst
+ [5484] = 6, -- Howl of Terror (Rank 1)
+ [5487] = 0, -- Bear Form (Shapeshift)
+ [5570] = 12, -- Insect Swarm
+ [5588] = 4, -- Hammer of Justice (Rank 2)
+ [5589] = 5, -- Hammer of Justice (Rank 3)
+ [5599] = 8, -- Hand of Protection (Rank 2)
+ [5677] = 0, -- Mana Spring (Rank 1)
+ [5697] = 600, -- Unending Breath
+ [5740] = 8, -- Rain of Fire
+ [5760] = 10, -- Mind-numbing Poison
+ [5782] = 10, -- Fear (Rank 1)
+ [5784] = 0, -- Felsteed (Summon)
+ [5916] = 0, -- Shadowstalker Stealth
+ [6016] = 20, -- Pierce Armor
+ [6065] = 30, -- Power Word: Shield (Rank 5)
+ [6066] = 30, -- Power Word: Shield (Rank 6)
+ [6074] = 15, -- Renew (Rank 2)
+ [6075] = 15, -- Renew (Rank 3)
+ [6076] = 15, -- Renew (Rank 4)
+ [6077] = 12, -- Renew (Rank 5)
+ [6078] = 15, -- Renew (Rank 6)
+ [6114] = 300, -- Raptor Punch
+ [6117] = 1800, -- Mage Armor (Rank 1)
+ [6131] = 8, -- Frost Nova (Rank 3)
+ [6136] = 5, -- Chilled (Rank 1)
+ [6143] = 30, -- Frost Ward (Rank 1)
+ [6146] = 15, -- Slow (Rank 2)
+ [6150] = 12, -- Quick Shots
+ [6190] = 30, -- Demoralizing Shout (Rank 2)
+ [6192] = 120, -- Battle Shout (Rank 3)
+ [6196] = 0, -- Far Sight
+ [6205] = 120, -- Curse of Weakness (Rank 3)
+ [6213] = 15, -- Fear (Rank 2)
+ [6215] = 20, -- Fear (Rank 3)
+ [6217] = 24, -- Curse of Agony (Rank 3)
+ [6222] = 15, -- Corruption (Rank 2)
+ [6223] = 18, -- Corruption (Rank 3)
+ [6229] = 30, -- Shadow Ward
+ [6253] = 2, -- Backhand
+ [6268] = 3, -- Rushing Charge (Rank 1)
+ [6278] = 60, -- Creeping Mold
+ [6306] = 30, -- Acid Splash
+ [6307] = 0, -- Blood Pact (Rank 1)
+ [6343] = 10, -- Thunder Clap (Rank 1)
+ [6346] = 180, -- Fear Ward
+ [6358] = 15, -- Seduction
+ [6432] = 10, -- Smite Stomp
+ [6466] = 3, -- Axe Toss
+ [6524] = 2, -- Ground Tremor
+ [6533] = 2, -- Net
+ [6546] = 15, -- Rend (Rank 2)
+ [6547] = 15, -- Rend (Rank 3)
+ [6548] = 15, -- Rend (Rank 4)
+ [6562] = 0, -- Heroic Presence (Racial Passive)
+ [6653] = 0, -- Dire Wolf
+ [6673] = 120, -- Battle Shout (Rank 1)
+ [6713] = 5, -- Disarm
+ [6726] = 5, -- Silence
+ [6728] = 10, -- Enveloping Winds (Rank 1)
+ [6742] = 30, -- Bloodlust
+ [6756] = 1800, -- Mark of the Wild (Rank 3)
+ [6770] = 60, -- Sap (Rank 1)
+ [6774] = 6, -- Slice and Dice (Rank 2)
+ [6788] = 15, -- Weakened Soul
+ [6789] = 3, -- Death Coil (Rank 1)
+ [6793] = 6, -- Tiger's Fury (Rank 2)
+ [6795] = 3, -- Growl
+ [6940] = 12, -- Hand of Sacrifice
+ [6950] = 60, -- Faerie Fire
+ [7038] = 60, -- Forsaken Skill: Swords
+ [7039] = 60, -- Forsaken Skill: Axes
+ [7040] = 60, -- Forsaken Skill: Daggers
+ [7041] = 60, -- Forsaken Skill: Maces
+ [7042] = 60, -- Forsaken Skill: Staves
+ [7044] = 60, -- Forsaken Skill: Guns
+ [7045] = 60, -- Forsaken Skill: 2H Axes
+ [7046] = 60, -- Forsaken Skill: 2H Maces
+ [7047] = 60, -- Forsaken Skill: 2H Swords
+ [7049] = 60, -- Forsaken Skill: Fire
+ [7051] = 60, -- Forsaken Skill: Holy
+ [7053] = 60, -- Forsaken Skill: Shadow
+ [7054] = 300, -- Forsaken Skills
+ [7057] = 300, -- Haunting Spirits
+ [7068] = 15, -- Veil of Shadow
+ [7072] = 60, -- Wild Rage
+ [7074] = 5, -- Screams of the Past
+ [7121] = 10, -- Anti-Magic Shield
+ [7124] = 300, -- Arugal's Gift
+ [7125] = 120, -- Toxic Saliva
+ [7127] = 60, -- Wavering Will
+ [7128] = 1800, -- Inner Fire (Rank 2)
+ [7140] = 5, -- Expose Weakness
+ [7178] = 1800, -- Water Breathing (Rank 1)
+ [7294] = 0, -- Retribution Aura (Rank 1)
+ [7295] = 10, -- Soul Drain
+ [7300] = 1800, -- Frost Armor (Rank 2)
+ [7301] = 1800, -- Frost Armor (Rank 3)
+ [7302] = 1800, -- Ice Armor (Rank 1)
+ [7320] = 1800, -- Ice Armor (Rank 2)
+ [7321] = 5, -- Chilled (Rank 1)
+ [7322] = 7, -- Frostbolt (Rank 4)
+ [7353] = 60, -- Cozy Fire
+ [7389] = 15, -- Attack
+ [7399] = 4, -- Terrify
+ [7481] = 300, -- Howling Rage
+ [7483] = 300, -- Howling Rage
+ [7484] = 300, -- Howling Rage
+ [7621] = 10, -- Arugal's Curse
+ [7648] = 18, -- Corruption (Rank 4)
+ [7651] = 5, -- Drain Life (Rank 4)
+ [7739] = 10, -- Inferno Shell
+ [7744] = 0, -- Will of the Forsaken (Racial)
+ [7804] = 0, -- Blood Pact (Rank 2)
+ [7805] = 0, -- Blood Pact (Rank 3)
+ [7812] = 30, -- Sacrifice (Rank 1)
+ [7844] = 3600, -- Fire Power
+ [7870] = 300, -- Lesser Invisibility
+ [7922] = 2, -- Charge Stun (1.5 seconds)
+ [7947] = 60, -- Localized Toxin
+ [7948] = 20, -- Wild Regeneration
+ [7964] = 4, -- Smoke Bomb
+ [7966] = 60, -- Thorns Aura
+ [7992] = 24, -- Slowing Poison
+ [8034] = 8, -- Frostbrand Attack
+ [8040] = 15, -- Druid's Slumber
+ [8041] = 10, -- Serpent Form (Shapeshift)
+ [8042] = 8, -- Earth Shock (Rank 1)
+ [8045] = 8, -- Earth Shock (Rank 3)
+ [8046] = 8, -- Earth Shock (Rank 4)
+ [8050] = 18, -- Flame Shock (Rank 1)
+ [8052] = 18, -- Flame Shock (Rank 2)
+ [8053] = 18, -- Flame Shock (Rank 3)
+ [8056] = 8, -- Frost Shock (Rank 1)
+ [8058] = 8, -- Frost Shock (Rank 2)
+ [8066] = 120, -- Shrink
+ [8068] = 1800, -- Healthy Spirit
+ [8076] = 0, -- Strength of Earth (Rank 1)
+ [8078] = 10, -- Thunderclap
+ [8096] = 1800, -- Intellect (Rank 1)
+ [8101] = 1800, -- Stamina (Level 3)
+ [8112] = 1800, -- Spirit (Rank 1)
+ [8117] = 1800, -- Agility (Rank 3)
+ [8119] = 1800, -- Strength (Rank 2)
+ [8122] = 8, -- Psychic Scream
+ [8134] = 600, -- Lightning Shield (Rank 5)
+ [8140] = 15, -- Befuddlement (Rank 1)
+ [8148] = 0, -- Thorns Aura
+ [8153] = 0, -- Owl Form (Shapeshift)
+ [8156] = 0, -- Stoneskin (Rank 2)
+ [8157] = 0, -- Stoneskin (Rank 3)
+ [8162] = 0, -- Strength of Earth (Rank 2)
+ [8163] = 0, -- Strength of Earth (Rank 3)
+ [8178] = 0, -- Grounding Totem Effect (Rank 1)
+ [8185] = 0, -- Elemental Resistance
+ [8198] = 14, -- Thunder Clap (Rank 2)
+ [8202] = 1200, -- Sapta Sight
+ [8204] = 18, -- Thunder Clap (Rank 3)
+ [8205] = 22, -- Thunder Clap (Rank 4)
+ [8212] = 1200, -- Enlarge
+ [8219] = 3600, -- Flip Out
+ [8220] = 3600, -- Flip Out
+ [8221] = 3600, -- Yaaarrrr
+ [8222] = 3600, -- Yaaarrrr
+ [8242] = 2, -- Shield Slam
+ [8258] = 240, -- Devotion Aura
+ [8263] = 0, -- Elemental Protection Totem Aura (Rank 1)
+ [8267] = 600, -- Cursed Blood
+ [8269] = 120, -- Frenzy
+ [8272] = 600, -- Mind Tremor
+ [8275] = 75, -- Poisoned Shot
+ [8281] = 6, -- Sonic Burst
+ [8282] = 120, -- Curse of Blood
+ [8285] = 3, -- Rampage
+ [8288] = 15, -- Drain Soul (Rank 2)
+ [8289] = 15, -- Drain Soul (Rank 3)
+ [8314] = 3600, -- Rock Skin
+ [8316] = 180, -- Fire Shield (Rank 2)
+ [8317] = 180, -- Fire Shield (Rank 3)
+ [8326] = 0, -- Ghost
+ [8362] = 20, -- Renew
+ [8365] = 10, -- Enlarge
+ [8377] = 4, -- Earthgrab
+ [8379] = 10, -- Disarm
+ [8382] = 45, -- Leech Poison
+ [8385] = 3600, -- Swift Wind
+ [8391] = 3, -- Ravage
+ [8395] = 0, -- Emerald Raptor
+ [8398] = 8, -- Frostbolt Volley
+ [8399] = 10, -- Sleep
+ [8402] = 8, -- Fireball (Rank 7)
+ [8406] = 7, -- Frostbolt (Rank 5)
+ [8407] = 8, -- Frostbolt (Rank 6)
+ [8408] = 8, -- Frostbolt (Rank 7)
+ [8450] = 600, -- Dampen Magic (Rank 2)
+ [8451] = 600, -- Dampen Magic (Rank 3)
+ [8455] = 600, -- Amplify Magic (Rank 2)
+ [8492] = 8, -- Cone of Cold (Rank 2)
+ [8495] = 60, -- Mana Shield (Rank 3)
+ [8515] = 0, -- Windfury Totem (Rank 1)
+ [8599] = 120, -- Enrage
+ [8600] = 180, -- Fevered Plague
+ [8632] = 18, -- Garrote (Rank 3)
+ [8633] = 18, -- Garrote (Rank 4)
+ [8639] = 16, -- Rupture (Rank 2)
+ [8640] = 6, -- Rupture (Rank 3)
+ [8643] = 6, -- Kidney Shot (Rank 2)
+ [8647] = 6, -- Expose Armor
+ [8696] = 15, -- Sprint (Rank 2)
+ [8733] = 3600, -- Blessing of Blackfathom
+ [8788] = 600, -- Lightning Shield (Rank 4)
+ [8898] = 1200, -- Sapta Sight
+ [8907] = 1800, -- Mark of the Wild (Rank 5)
+ [8910] = 15, -- Rejuvenation (Rank 7)
+ [8914] = 600, -- Thorns (Rank 4)
+ [8921] = 12, -- Moonfire
+ [8925] = 12, -- Moonfire (Rank 3)
+ [8926] = 12, -- Moonfire (Rank 4)
+ [8927] = 12, -- Moonfire (Rank 5)
+ [8928] = 12, -- Moonfire (Rank 6)
+ [8929] = 12, -- Moonfire (Rank 7)
+ [8936] = 21, -- Regrowth (Rank 1)
+ [8938] = 21, -- Regrowth (Rank 2)
+ [8939] = 21, -- Regrowth (Rank 3)
+ [8940] = 21, -- Regrowth (Rank 4)
+ [8941] = 21, -- Regrowth (Rank 5)
+ [8983] = 4, -- Bash (Rank 3)
+ [8988] = 10, -- Silence (Rank 1)
+ [8990] = 0, -- Retribution Aura (Rank 1)
+ [9005] = 3, -- Pounce
+ [9007] = 18, -- Pounce Bleed (Rank 1)
+ [9034] = 21, -- Immolate
+ [9080] = 10, -- Hamstring
+ [9128] = 120, -- Battle Shout
+ [9256] = 10, -- Deep Sleep
+ [9275] = 21, -- Immolate
+ [9438] = 8, -- Arcane Bubble
+ [9459] = 60, -- Corrosive Ooze
+ [9482] = 30, -- Amplify Flames
+ [9484] = 30, -- Shackle Undead (Rank 1)
+ [9485] = 40, -- Shackle Undead (Rank 2)
+ [9490] = 30, -- Demoralizing Roar (Rank 3)
+ [9492] = 12, -- Rip (Rank 2)
+ [9493] = 12, -- Rip (Rank 3)
+ [9634] = 0, -- Dire Bear Form (Shapeshift)
+ [9672] = 4, -- Frostbolt
+ [9747] = 30, -- Demoralizing Roar (Rank 4)
+ [9750] = 21, -- Regrowth (Rank 6)
+ [9756] = 600, -- Thorns (Rank 5)
+ [9775] = 60, -- Irradiated
+ [9798] = 0, -- Radiation
+ [9821] = 15, -- Dash (Rank 2)
+ [9833] = 12, -- Moonfire (Rank 8)
+ [9839] = 15, -- Rejuvenation (Rank 8)
+ [9840] = 15, -- Rejuvenation (Rank 9)
+ [9856] = 21, -- Regrowth (Rank 7)
+ [9884] = 1800, -- Mark of the Wild (Rank 6)
+ [9885] = 1800, -- Mark of the Wild (Rank 7)
+ [9896] = 16, -- Rip (Rank 6)
+ [9904] = 9, -- Rake (Rank 4)
+ [9906] = 5, -- Reflection
+ [9910] = 600, -- Thorns (Rank 6)
+ [10060] = 15, -- Power Infusion
+ [10093] = 1, -- Harsh Winds
+ [10156] = 1800, -- Arcane Intellect (Rank 4)
+ [10157] = 1800, -- Arcane Intellect (Rank 5)
+ [10159] = 11, -- Cone of Cold (Rank 3)
+ [10160] = 8, -- Cone of Cold (Rank 4)
+ [10170] = 600, -- Amplify Magic (Rank 4)
+ [10173] = 600, -- Dampen Magic (Rank 4)
+ [10174] = 600, -- Dampen Magic (Rank 5)
+ [10179] = 9, -- Frostbolt (Rank 8)
+ [10180] = 9, -- Frostbolt (Rank 9)
+ [10219] = 1800, -- Ice Armor (Rank 3)
+ [10220] = 1800, -- Ice Armor (Rank 4)
+ [10278] = 10, -- Hand of Protection (Rank 3)
+ [10290] = 0, -- Devotion Aura (Rank 2)
+ [10291] = 0, -- Devotion Aura (Rank 4)
+ [10292] = 0, -- Devotion Aura (Rank 6)
+ [10293] = 0, -- Devotion Aura (Rank 7)
+ [10298] = 0, -- Retribution Aura (Rank 2)
+ [10299] = 0, -- Retribution Aura (Rank 3)
+ [10300] = 0, -- Retribution Aura (Rank 4)
+ [10301] = 0, -- Retribution Aura (Rank 5)
+ [10308] = 6, -- Hammer of Justice (Rank 4)
+ [10326] = 20, -- Turn Evil
+ [10348] = 20, -- Tune Up
+ [10403] = 0, -- Stoneskin (Rank 4)
+ [10404] = 0, -- Stoneskin (Rank 5)
+ [10405] = 0, -- Stoneskin (Rank 6)
+ [10412] = 8, -- Earth Shock (Rank 5)
+ [10413] = 8, -- Earth Shock (Rank 6)
+ [10431] = 600, -- Lightning Shield (Rank 6)
+ [10432] = 600, -- Lightning Shield (Rank 7)
+ [10452] = 20, -- Flame Buffet
+ [10458] = 8, -- Frostbrand Attack (Rank 3)
+ [10491] = 0, -- Mana Spring (Rank 2)
+ [10493] = 0, -- Mana Spring (Rank 3)
+ [10494] = 0, -- Mana Spring (Rank 4)
+ [10596] = 0, -- Nature Resistance (Rank 1)
+ [10598] = 0, -- Nature Resistance (Rank 2)
+ [10668] = 3600, -- Spirit of Boar
+ [10730] = 10, -- Pacify
+ [10732] = 10, -- Supercharge
+ [10734] = 3, -- Hail Storm
+ [10796] = 0, -- Turquoise Raptor
+ [10799] = 0, -- Violet Raptor
+ [10831] = 5, -- Reflection Field
+ [10838] = 8, -- First Aid (Rank 7)
+ [10890] = 8, -- Psychic Scream (Rank 4)
+ [10892] = 18, -- Shadow Word: Pain (Rank 6)
+ [10894] = 18, -- Shadow Word: Pain (Rank 8)
+ [10898] = 30, -- Power Word: Shield (Rank 7)
+ [10899] = 30, -- Power Word: Shield (Rank 8)
+ [10901] = 30, -- Power Word: Shield (Rank 10)
+ [10909] = 60, -- Mind Vision (Rank 2)
+ [10927] = 15, -- Renew (Rank 7)
+ [10937] = 1800, -- Power Word: Fortitude (Rank 5)
+ [10938] = 1800, -- Power Word: Fortitude (Rank 6)
+ [10951] = 1800, -- Inner Fire (Rank 5)
+ [10952] = 1800, -- Inner Fire (Rank 6)
+ [10955] = 50, -- Shackle Undead (Rank 3)
+ [10957] = 1200, -- Shadow Protection (Rank 2)
+ [10958] = 600, -- Shadow Protection (Rank 3)
+ [11020] = 8, -- Petrify
+ [11113] = 6, -- Blast Wave (Rank 1)
+ [11131] = 10, -- Icicle
+ [11196] = 60, -- Recently Bandaged
+ [11264] = 10, -- Ice Blast
+ [11273] = 10, -- Rupture (Rank 4)
+ [11305] = 15, -- Sprint (Rank 3)
+ [11327] = 10, -- Vanish (Rank 1)
+ [11328] = 3600, -- Agility
+ [11329] = 10, -- Vanish (Rank 2)
+ [11334] = 3600, -- Greater Agility
+ [11348] = 3600, -- Greater Armor
+ [11349] = 3600, -- Armor
+ [11366] = 12, -- Pyroblast (Rank 1)
+ [11390] = 3600, -- Arcane Elixir
+ [11396] = 3600, -- Greater Intellect
+ [11397] = 300, -- Diseased Shot
+ [11426] = 60, -- Ice Barrier (Rank 1)
+ [11436] = 10, -- Slow
+ [11442] = 180, -- Withered Touch
+ [11443] = 15, -- Cripple
+ [11445] = 60, -- Bone Armor
+ [11538] = 4, -- Frostbolt
+ [11549] = 120, -- Battle Shout (Rank 4)
+ [11550] = 120, -- Battle Shout (Rank 5)
+ [11551] = 240, -- Battle Shout (Rank 6)
+ [11554] = 30, -- Demoralizing Shout (Rank 3)
+ [11555] = 30, -- Demoralizing Shout (Rank 4)
+ [11572] = 15, -- Rend (Rank 5)
+ [11573] = 15, -- Rend (Rank 6)
+ [11580] = 26, -- Thunder Clap (Rank 5)
+ [11639] = 18, -- Shadow Word: Pain
+ [11640] = 15, -- Renew
+ [11641] = 10, -- Hex
+ [11647] = 30, -- Power Word: Shield
+ [11665] = 15, -- Immolate (Rank 5)
+ [11671] = 18, -- Corruption (Rank 5)
+ [11699] = 5, -- Drain Life (Rank 5)
+ [11707] = 120, -- Curse of Weakness (Rank 5)
+ [11711] = 24, -- Curse of Agony (Rank 4)
+ [11712] = 24, -- Curse of Agony (Rank 5)
+ [11719] = 12, -- Curse of Tongues (Rank 2)
+ [11733] = 1800, -- Demon Armor (Rank 3)
+ [11734] = 1800, -- Demon Armor (Rank 4)
+ [11735] = 1800, -- Demon Armor (Rank 5)
+ [11766] = 0, -- Blood Pact (Rank 4)
+ [11767] = 0, -- Blood Pact (Rank 5)
+ [11770] = 180, -- Fire Shield (Rank 4)
+ [11820] = 6, -- Electrified Net
+ [11841] = 600, -- Static Barrier
+ [11876] = 3, -- War Stomp
+ [11922] = 15, -- Entangling Roots
+ [11962] = 15, -- Immolate
+ [11971] = 30, -- Sunder Armor
+ [11974] = 30, -- Power Word: Shield
+ [11977] = 15, -- Rend
+ [11980] = 120, -- Curse of Weakness
+ [12024] = 5, -- Net
+ [12040] = 30, -- Shadow Shield
+ [12042] = 15, -- Arcane Power
+ [12043] = 0, -- Presence of Mind
+ [12051] = 8, -- Evocation
+ [12096] = 8, -- Fear
+ [12097] = 20, -- Pierce Armor
+ [12098] = 20, -- Sleep
+ [12169] = 5, -- Shield Block
+ [12178] = 1800, -- Stamina (Level 4)
+ [12245] = 300, -- Infected Spine
+ [12248] = 10, -- Amplify Damage
+ [12251] = 30, -- Virulent Poison
+ [12255] = 900, -- Curse of Tuten'kash
+ [12292] = 30, -- Death Wish
+ [12294] = 10, -- Mortal Strike (Rank 1)
+ [12323] = 6, -- Piercing Howl
+ [12328] = 30, -- Sweeping Strikes
+ [12355] = 2, -- Impact
+ [12421] = 2, -- Mithril Frag Bomb
+ [12461] = 2, -- Backhand
+ [12472] = 20, -- Icy Veins
+ [12479] = 10, -- Hex of Jammal'an
+ [12484] = 2, -- Chilled (Rank 1)
+ [12486] = 2, -- Chilled (Rank 3)
+ [12493] = 120, -- Curse of Weakness
+ [12494] = 5, -- Frostbite
+ [12523] = 12, -- Pyroblast (Rank 4)
+ [12528] = 10, -- Silence
+ [12530] = 60, -- Frailty
+ [12531] = 8, -- Chilling Touch
+ [12536] = 15, -- Clearcasting
+ [12540] = 4, -- Gouge
+ [12541] = 600, -- Ghoul Rot
+ [12544] = 1800, -- Frost Armor
+ [12548] = 8, -- Frost Shock
+ [12579] = 15, -- Winter's Chill
+ [12611] = 8, -- Cone of Cold
+ [12627] = 0, -- Disease Cloud
+ [12654] = 4, -- Ignite
+ [12721] = 6, -- Deep Wounds
+ [12741] = 120, -- Curse of Weakness
+ [12795] = 120, -- Frenzy
+ [12809] = 5, -- Concussion Blow
+ [12824] = 30, -- Polymorph (Rank 2)
+ [12826] = 10, -- Polymorph (Rank 4)
+ [12884] = 45, -- Acid Breath
+ [12890] = 15, -- Deep Slumber
+ [12891] = 45, -- Acid Breath
+ [12946] = 10, -- Putrid Stench
+ [12968] = 15, -- Flurry
+ [12970] = 15, -- Flurry (Rank 5)
+ [12976] = 20, -- Last Stand
+ [13159] = 0, -- Aspect of the Pack
+ [13161] = 0, -- Aspect of the Beast
+ [13163] = 0, -- Aspect of the Monkey
+ [13165] = 0, -- Aspect of the Hawk (Rank 1)
+ [13218] = 15, -- Wound Poison (Rank 1)
+ [13222] = 15, -- Wound Poison II (Rank 2)
+ [13298] = 30, -- Poison
+ [13326] = 1800, -- Arcane Intellect
+ [13439] = 5, -- Frostbolt
+ [13443] = 15, -- Rend
+ [13445] = 15, -- Rend
+ [13526] = 30, -- Corrosive Poison
+ [13532] = 10, -- Thunder Clap (Rank 1)
+ [13542] = 15, -- Mend Pet (Rank 5)
+ [13549] = 15, -- Serpent Sting (Rank 2)
+ [13550] = 15, -- Serpent Sting (Rank 3)
+ [13551] = 21, -- Serpent Sting (Rank 4)
+ [13552] = 15, -- Serpent Sting (Rank 5)
+ [13553] = 15, -- Serpent Sting (Rank 6)
+ [13555] = 15, -- Serpent Sting (Rank 8)
+ [13704] = 6, -- Psychic Scream
+ [13730] = 30, -- Demoralizing Shout
+ [13750] = 15, -- Adrenaline Rush
+ [13797] = 15, -- Immolation Trap (Rank 1)
+ [13810] = 0, -- Frost Trap Aura
+ [13812] = 0, -- Explosive Trap Effect (Rank 1)
+ [13864] = 1800, -- Power Word: Fortitude
+ [13877] = 15, -- Blade Flurry
+ [14030] = 6, -- Hooked Net
+ [14032] = 18, -- Shadow Word: Pain
+ [14143] = 20, -- Remorseless (Rank 1)
+ [14149] = 20, -- Remorseless (Rank 2)
+ [14177] = 0, -- Cold Blood
+ [14183] = 20, -- Premeditation
+ [14201] = 12, -- Enrage (Rank 2)
+ [14202] = 9, -- Enrage
+ [14203] = 12, -- Enrage (Rank 4)
+ [14251] = 30, -- Riposte
+ [14267] = 0, -- Horde Flag
+ [14268] = 0, -- Alliance Flag
+ [14278] = 7, -- Ghostly Strike
+ [14298] = 15, -- Immolation Trap (Rank 2)
+ [14308] = 20, -- Freezing Trap Effect (Rank 2)
+ [14309] = 20, -- Freezing Trap Effect (Rank 3)
+ [14314] = 0, -- Explosive Trap Effect (Rank 2)
+ [14318] = 0, -- Aspect of the Hawk (Rank 2)
+ [14319] = 0, -- Aspect of the Hawk (Rank 3)
+ [14320] = 0, -- Aspect of the Hawk (Rank 4)
+ [14321] = 0, -- Aspect of the Hawk (Rank 5)
+ [14322] = 0, -- Aspect of the Hawk (Rank 6)
+ [14323] = 300, -- Hunter's Mark (Rank 2)
+ [14324] = 300, -- Hunter's Mark (Rank 3)
+ [14325] = 120, -- Hunter's Mark (Rank 4)
+ [14515] = 15, -- Dominate Mind
+ [14517] = 30, -- Crusader Strike
+ [14518] = 30, -- Crusader Strike
+ [14751] = 0, -- Inner Focus
+ [14752] = 1800, -- Divine Spirit (Rank 1)
+ [14818] = 1800, -- Divine Spirit (Rank 2)
+ [14819] = 1800, -- Divine Spirit (Rank 3)
+ [14893] = 15, -- Inspiration (Rank 1)
+ [14914] = 7, -- Holy Fire (Rank 1)
+ [15007] = 600, -- Resurrection Sickness (assuming level 20+)
+ [15039] = 12, -- Flame Shock
+ [15087] = 15, -- Evasion
+ [15258] = 15, -- Shadow Weaving (Rank 1)
+ [15262] = 7, -- Holy Fire (Rank 2)
+ [15263] = 7, -- Holy Fire (Rank 3)
+ [15265] = 7, -- Holy Fire (Rank 5)
+ [15266] = 7, -- Holy Fire (Rank 6)
+ [15271] = 15, -- Spirit Tap (Rank 1)
+ [15286] = 1800, -- Vampiric Embrace
+ [15357] = 15, -- Inspiration (Rank 2)
+ [15359] = 15, -- Inspiration (Rank 3)
+ [15407] = 3, -- Mind Flay (Rank 1)
+ [15473] = 0, -- Shadowform
+ [15487] = 5, -- Silence
+ [15531] = 8, -- Frost Nova
+ [15532] = 8, -- Frost Nova
+ [15548] = 10, -- Thunderclap
+ [15571] = 4, -- Dazed
+ [15572] = 30, -- Sunder Armor
+ [15588] = 0, -- Thunderclap
+ [15708] = 0, -- Mortal Strike
+ [15971] = 30, -- Demoralizing Roar
+ [15976] = 10, -- Puncture
+ [16166] = 30, -- Elemental Mastery
+ [16177] = 15, -- Ancestral Fortitude (Rank 1)
+ [16188] = 0, -- Nature's Swiftness
+ [16191] = 0, -- Mana Tide
+ [16236] = 15, -- Ancestral Fortitude (Rank 2)
+ [16237] = 15, -- Ancestral Fortitude (Rank 3)
+ [16244] = 30, -- Demoralizing Shout
+ [16246] = 15, -- Clearcasting
+ [16277] = 15, -- Flurry (Rank 2)
+ [16278] = 15, -- Flurry
+ [16280] = 15, -- Flurry (Rank 5)
+ [16468] = 0, -- Mother's Milk
+ [16488] = 6, -- Blood Craze
+ [16490] = 6, -- Blood Craze
+ [16491] = 6, -- Blood Craze
+ [16509] = 15, -- Rend
+ [16511] = 15, -- Hemorrhage (Rank 1)
+ [16567] = 600, -- Tainted Mind
+ [16591] = 600, -- Noggenfogger Elixir
+ [16593] = 15, -- Noggenfogger Elixir
+ [16595] = 600, -- Noggenfogger Elixir
+ [16609] = 3600, -- Warchief's Blessing
+ [16689] = 45, -- Nature's Grasp (Rank 1)
+ [16711] = 300, -- Grow
+ [16739] = 300, -- Orb of Deception
+ [16810] = 45, -- Nature's Grasp (Rank 2)
+ [16811] = 45, -- Nature's Grasp (Rank 3)
+ [16812] = 45, -- Nature's Grasp (Rank 4)
+ [16857] = 300, -- Faerie Fire (Feral)
+ [16870] = 15, -- Clearcasting
+ [16886] = 3, -- Nature's Grace
+ [16914] = 0, -- Hurricane (Rank 1)
+ [17038] = 1200, -- Winterfall Firewater
+ [17057] = 6, -- Furor
+ [17116] = 0, -- Nature's Swiftness
+ [17154] = 30, -- The Green Tower (Rank 1)
+ [17229] = 0, -- Winterspring Frostsaber
+ [17311] = 3, -- Mind Flay (Rank 2)
+ [17312] = 3, -- Mind Flay (Rank 3)
+ [17347] = 15, -- Hemorrhage (Rank 2)
+ [17364] = 12, -- Stormstrike
+ [17462] = 0, -- Red Skeletal Horse
+ [17463] = 0, -- Blue Skeletal Horse
+ [17464] = 0, -- Brown Skeletal Horse
+ [17465] = 0, -- Green Skeletal Warhorse
+ [17481] = 0, -- Rivendare's Deathcharger
+ [17535] = 7200, -- Elixir of the Sages
+ [17537] = 3600, -- Elixir of Brute Force
+ [17539] = 7200, -- Greater Arcane Elixir
+ [17619] = 0, -- Alchemist's Stone
+ [17627] = 3600, -- Distilled Wisdom
+ [17628] = 7200, -- Supreme Power
+ [17670] = 0, -- Argent Dawn Commission
+ [17735] = 5, -- Suffering
+ [17767] = 6, -- Consume Shadows
+ [17800] = 30, -- Shadow Mastery
+ [17928] = 8, -- Howl of Terror (Rank 2)
+ [17941] = 10, -- Shadow Trance
+ [17962] = 6, -- Conflagrate
+ [18070] = 30, -- Earthborer Acid
+ [18093] = 10, -- Pyroclasm
+ [18118] = 5, -- Aftermath
+ [18223] = 12, -- Curse of Exhaustion
+ [18266] = 15, -- Curse of Agony
+ [18267] = 30, -- Curse of Weakness
+ [18381] = 30, -- Cripple (Rank 1)
+ [18400] = 0, -- Piccolo of the Flaming Fire
+ [18425] = 2, -- Silenced - Improved Kick
+ [18469] = 2, -- Silenced - Improved Counterspell (Rank 1)
+ [18498] = 3, -- Silenced - Gag Order
+ [18499] = 10, -- Berserker Rage
+ [18610] = 8, -- First Aid (Rank 10)
+ [18647] = 30, -- Banish (Rank 2)
+ [18657] = 40, -- Hibernate (Rank 2)
+ [18658] = 10, -- Hibernate (Rank 3)
+ [18708] = 15, -- Fel Domination
+ [18972] = 20, -- Slow
+ [18989] = 0, -- Gray Kodo
+ [18990] = 0, -- Brown Kodo
+ [19136] = 0, -- Stormbolt
+ [19263] = 5, -- Deterrence
+ [19276] = 24, -- Devouring Plague (Rank 2)
+ [19277] = 24, -- Devouring Plague (Rank 3)
+ [19278] = 24, -- Devouring Plague (Rank 4)
+ [19306] = 5, -- Counterattack
+ [19386] = 6, -- Wyvern Sting (Rank 1)
+ [19434] = 10, -- Aimed Shot (Rank 1)
+ [19440] = 30, -- Sacrifice (Rank 3)
+ [19503] = 4, -- Scatter Shot
+ [19506] = 0, -- Trueshot Aura
+ [19574] = 10, -- Bestial Wrath
+ [19577] = 15, -- Intimidation
+ [19579] = 0, -- Spirit Bond (Rank 1)
+ [19615] = 8, -- Frenzy Effect (Rank 1)
+ [19683] = 900, -- Tame Armored Scorpid
+ [19705] = 900, -- Well Fed
+ [19706] = 900, -- Well Fed
+ [19709] = 900, -- Well Fed
+ [19710] = 900, -- Well Fed
+ [19740] = 600, -- Blessing of Might (Rank 1)
+ [19742] = 600, -- Blessing of Wisdom (Rank 1)
+ [19746] = 0, -- Concentration Aura
+ [19821] = 5, -- Arcane Bomb
+ [19834] = 600, -- Blessing of Might (Rank 2)
+ [19835] = 600, -- Blessing of Might (Rank 3)
+ [19836] = 600, -- Blessing of Might (Rank 4)
+ [19837] = 600, -- Blessing of Might (Rank 5)
+ [19838] = 1800, -- Blessing of Might (Rank 6)
+ [19850] = 600, -- Blessing of Wisdom (Rank 2)
+ [19852] = 600, -- Blessing of Wisdom (Rank 3)
+ [19853] = 600, -- Blessing of Wisdom (Rank 4)
+ [19854] = 600, -- Blessing of Wisdom (Rank 5)
+ [19876] = 0, -- Shadow Resistance Aura (Rank 1)
+ [19883] = 0, -- Track Humanoids
+ [19891] = 0, -- Fire Resistance Aura (Rank 1)
+ [19895] = 0, -- Shadow Resistance Aura (Rank 2)
+ [19897] = 0, -- Frost Resistance Aura (Rank 2)
+ [19899] = 0, -- Fire Resistance Aura (Rank 2)
+ [19972] = 21, -- Entangling Roots (Rank 4)
+ [19973] = 18, -- Entangling Roots (Rank 3)
+ [19974] = 15, -- Entangling Roots (Rank 2)
+ [19975] = 27, -- Entangling Roots
+ [20005] = 5, -- Chilled
+ [20006] = 12, -- Unholy Curse
+ [20007] = 15, -- Holy Strength
+ [20043] = 0, -- Aspect of the Wild (Rank 1)
+ [20050] = 15, -- Conviction
+ [20052] = 15, -- Conviction
+ [20053] = 30, -- Vengeance
+ [20066] = 60, -- Repentance
+ [20132] = 10, -- Redoubt
+ [20154] = 1800, -- Seal of Righteousness
+ [20164] = 1800, -- Seal of Justice
+ [20165] = 1800, -- Seal of Light
+ [20166] = 1800, -- Seal of Wisdom
+ [20170] = 2, -- Stun
+ [20178] = 8, -- Reckoning
+ [20184] = 20, -- Judgement of Justice
+ [20185] = 20, -- Judgement of Light (Rank 1)
+ [20186] = 20, -- Judgement of Wisdom (Rank 1)
+ [20216] = 0, -- Divine Favor
+ [20217] = 600, -- Blessing of Kings
+ [20230] = 12, -- Retaliation
+ [20236] = 15, -- Lay on Hands (Rank 2)
+ [20253] = 3, -- Intercept (Rank 1)
+ [20375] = 1800, -- Seal of Command
+ [20511] = 8, -- Intimidating Shout
+ [20549] = 2, -- War Stomp (Racial)
+ [20572] = 15, -- Blood Fury (Racial)
+ [20578] = 10, -- Cannibalize
+ [20615] = 3, -- Intercept (Rank 3)
+ [20707] = 900, -- Soulstone Resurrection
+ [20736] = 6, -- Distracting Shot
+ [20762] = 900, -- Soulstone Resurrection
+ [20763] = 900, -- Soulstone Resurrection
+ [20765] = 900, -- Soulstone Resurrection
+ [20798] = 1800, -- Demon Skin
+ [20800] = 21, -- Immolate
+ [20875] = 900, -- Rumsey Rum
+ [20901] = 10, -- Aimed Shot (Rank 3)
+ [20902] = 10, -- Aimed Shot (Rank 4)
+ [20903] = 10, -- Aimed Shot (Rank 5)
+ [20911] = 600, -- Blessing of Sanctuary
+ [20925] = 10, -- Holy Shield (Rank 1)
+ [20927] = 10, -- Holy Shield (Rank 2)
+ [21007] = 120, -- Curse of Weakness
+ [21049] = 30, -- Bloodlust
+ [21062] = 30, -- Putrid Breath
+ [21067] = 10, -- Poison Bolt
+ [21068] = 24, -- Corruption
+ [21069] = 6, -- Larva Goo
+ [21084] = 1800, -- Seal of Righteousness
+ [21163] = 1800, -- Polished Armor (Rank 1)
+ [21183] = 20, -- Heart of the Crusader (Rank 1)
+ [21331] = 15, -- Entangling Roots
+ [21337] = 600, -- Thorns
+ [21547] = 5, -- Spore Cloud
+ [21553] = 10, -- Mortal Strike (Rank 4)
+ [21562] = 3600, -- Prayer of Fortitude (Rank 1)
+ [21564] = 3600, -- Prayer of Fortitude (Rank 2)
+ [21655] = 1, -- Blink
+ [21687] = 15, -- Toxic Volley
+ [21749] = 2, -- Thorn Volley
+ [21787] = 120, -- Deadly Poison
+ [21849] = 3600, -- Gift of the Wild (Rank 1)
+ [21850] = 3600, -- Gift of the Wild (Rank 2)
+ [21909] = 8, -- Dust Field
+ [22570] = 0, -- Maim
+ [22717] = 0, -- Black War Steed
+ [22718] = 0, -- Black War Kodo
+ [22719] = 0, -- Black Battlestrider
+ [22720] = 0, -- Black War Ram
+ [22721] = 0, -- Black War Raptor
+ [22722] = 0, -- Red Skeletal Warhorse
+ [22723] = 0, -- Black War Tiger
+ [22724] = 0, -- Black War Wolf
+ [22766] = 0, -- Sneak (Rank 1)
+ [22782] = 1800, -- Mage Armor (Rank 2)
+ [22783] = 1800, -- Mage Armor (Rank 3)
+ [22812] = 12, -- Barkskin
+ [22842] = 10, -- Frenzied Regeneration
+ [22888] = 7200, -- Rallying Cry of the Dragonslayer
+ [22911] = 0, -- Charge
+ [22959] = 30, -- Improved Scorch
+ [23028] = 3600, -- Arcane Brilliance (Rank 1)
+ [23033] = 0, -- Battle Standard
+ [23036] = 0, -- Battle Standard
+ [23145] = 16, -- Dive
+ [23161] = 0, -- Dreadsteed (Summon)
+ [23214] = 0, -- Charger (Summon)
+ [23219] = 0, -- Swift Mistsaber
+ [23221] = 0, -- Swift Frostsaber
+ [23223] = 0, -- Swift White Mechanostrider
+ [23225] = 0, -- Swift Green Mechanostrider
+ [23227] = 0, -- Swift Palomino
+ [23228] = 0, -- Swift White Steed
+ [23229] = 0, -- Swift Brown Steed
+ [23238] = 0, -- Swift Brown Ram
+ [23239] = 0, -- Swift Gray Ram
+ [23240] = 0, -- Swift White Ram
+ [23241] = 0, -- Swift Blue Raptor
+ [23242] = 0, -- Swift Olive Raptor
+ [23243] = 0, -- Swift Orange Raptor
+ [23246] = 0, -- Purple Skeletal Warhorse
+ [23247] = 0, -- Great White Kodo
+ [23248] = 0, -- Great Gray Kodo
+ [23249] = 0, -- Great Brown Kodo
+ [23250] = 0, -- Swift Brown Wolf
+ [23251] = 0, -- Swift Timber Wolf
+ [23252] = 0, -- Swift Gray Wolf
+ [23333] = 0, -- Warsong Flag
+ [23335] = 0, -- Silverwing Flag
+ [23338] = 0, -- Swift Stormsaber
+ [23451] = 10, -- Speed
+ [23493] = 10, -- Restoration
+ [23509] = 0, -- Frostwolf Howler
+ [23510] = 0, -- Stormpike Battle Charger
+ [23511] = 0, -- Demoralizing Shout
+ [23600] = 6, -- Piercing Howl
+ [23693] = 120, -- Stormpike's Salvation
+ [23694] = 5, -- Improved Hamstring
+ [23759] = 0, -- Master Demonologist
+ [23760] = 0, -- Master Demonologist
+ [23767] = 7200, -- Sayge's Dark Fortune of Armor
+ [23768] = 7200, -- Sayge's Dark Fortune of Damage
+ [23829] = 0, -- Master Demonologist
+ [23844] = 0, -- Master Demonologist
+ [23885] = 8, -- Bloodthirst
+ [23920] = 5, -- Spell Reflection
+ [23978] = 10, -- Speed
+ [24131] = 6, -- Wyvern Sting
+ [24242] = 0, -- Swift Razzashi Raptor
+ [24252] = 0, -- Swift Zulian Tiger
+ [24259] = 3, -- Spell Lock
+ [24378] = 60, -- Berserking
+ [24379] = 10, -- Restoration
+ [24394] = 2, -- Intimidation
+ [24398] = 600, -- Water Shield (Rank 7)
+ [24425] = 7200, -- Spirit of Zandalar
+ [24450] = 0, -- Prowl (Rank 1)
+ [24452] = 0, -- Prowl (Rank 2)
+ [24453] = 0, -- Prowl (Rank 3)
+ [24529] = 0, -- Spirit Bond (Rank 2)
+ [24586] = 10, -- Scorpid Poison (Rank 3)
+ [24709] = 3600, -- Pirate Costume
+ [24711] = 3600, -- Ninja Costume
+ [24712] = 3600, -- Leper Gnome Costume
+ [24735] = 3600, -- Ghost Costume
+ [24844] = 45, -- Lightning Breath
+ [24858] = 0, -- Moonkin Form (Shapeshift)
+ [24870] = 900, -- Well Fed
+ [24907] = 0, -- Moonkin Aura
+ [24932] = 0, -- Leader of the Pack
+ [24974] = 14, -- Insect Swarm (Rank 2)
+ [25040] = 900, -- Mark of Nature
+ [25046] = 2, -- Arcane Torrent (Racial)
+ [25058] = 15, -- Renew
+ [25163] = 0, -- Oozeling's Disgusting Aura
+ [25207] = 1800, -- Amulet of the Moon
+ [25217] = 30, -- Power Word: Shield (Rank 11)
+ [25218] = 30, -- Power Word: Shield (Rank 12)
+ [25221] = 15, -- Renew (Rank 11)
+ [25222] = 15, -- Renew (Rank 12)
+ [25228] = 0, -- Soul Link
+ [25289] = 120, -- Battle Shout (Rank 7)
+ [25290] = 600, -- Blessing of Wisdom (Rank 6)
+ [25291] = 600, -- Blessing of Might (Rank 7)
+ [25295] = 15, -- Serpent Sting (Rank 9)
+ [25296] = 0, -- Aspect of the Hawk (Rank 7)
+ [25312] = 1800, -- Divine Spirit (Rank 5)
+ [25368] = 18, -- Shadow Word: Pain (Rank 10)
+ [25387] = 3, -- Mind Flay (Rank 7)
+ [25389] = 1800, -- Power Word: Fortitude (Rank 7)
+ [25392] = 3600, -- Prayer of Fortitude (Rank 3)
+ [25431] = 1800, -- Inner Fire (Rank 7)
+ [25433] = 600, -- Shadow Protection (Rank 4)
+ [25454] = 8, -- Earth Shock (Rank 8)
+ [25467] = 23, -- Devouring Plague (Rank 7)
+ [25469] = 600, -- Lightning Shield (Rank 8)
+ [25472] = 600, -- Lightning Shield (Rank 9)
+ [25527] = 0, -- Strength of Earth (Rank 6)
+ [25569] = 0, -- Mana Spring (Rank 5)
+ [25606] = 1800, -- Pendant of the Agate Shield
+ [25694] = 900, -- Well Fed
+ [25702] = 21, -- Food
+ [25746] = 15, -- Damage Absorb
+ [25747] = 15, -- Damage Absorb
+ [25771] = 120, -- Forbearance
+ [25780] = 120, -- Righteous Fury
+ [25804] = 900, -- Rumsey Rum Black Label
+ [25809] = 12, -- Crippling Poison (Rank 1)
+ [25810] = 12, -- Mind-numbing Poison
+ [25859] = 0, -- Reindeer
+ [25894] = 1800, -- Greater Blessing of Wisdom (Rank 1)
+ [25898] = 1800, -- Greater Blessing of Kings
+ [25899] = 1800, -- Greater Blessing of Sanctuary
+ [25916] = 1800, -- Greater Blessing of Might (Rank 2)
+ [25918] = 1800, -- Greater Blessing of Wisdom (Rank 2)
+ [25941] = 900, -- Well Fed
+ [26004] = 1800, -- Mistletoe
+ [26008] = 1800, -- Toast
+ [26013] = 900, -- Deserter
+ [26017] = 10, -- Vindication (Rank 2)
+ [26276] = 7200, -- Greater Firepower
+ [26297] = 10, -- Berserking (Racial)
+ [26522] = 1800, -- Lunar Fortune
+ [26573] = 10, -- Consecration
+ [26669] = 15, -- Evasion (Rank 2)
+ [26679] = 6, -- Deadly Throw
+ [26864] = 15, -- Hemorrhage (Rank 4)
+ [26867] = 14, -- Rupture (Rank 7)
+ [26884] = 18, -- Garrote (Rank 8)
+ [26888] = 10, -- Vanish (Rank 3)
+ [26968] = 12, -- Deadly Poison VI (Rank 6)
+ [26990] = 1800, -- Mark of the Wild (Rank 8)
+ [26991] = 3600, -- Gift of the Wild (Rank 3)
+ [26992] = 600, -- Thorns (Rank 7)
+ [27009] = 45, -- Nature's Grasp (Rank 7)
+ [27044] = 0, -- Aspect of the Hawk (Rank 8)
+ [27046] = 15, -- Mend Pet (Rank 8)
+ [27065] = 10, -- Aimed Shot (Rank 7)
+ [27089] = 30, -- Drink
+ [27124] = 1800, -- Ice Armor (Rank 5)
+ [27125] = 1800, -- Mage Armor (Rank 4)
+ [27126] = 1800, -- Arcane Intellect (Rank 6)
+ [27127] = 3600, -- Arcane Brilliance (Rank 2)
+ [27140] = 1800, -- Blessing of Might (Rank 8)
+ [27142] = 600, -- Blessing of Wisdom (Rank 7)
+ [27143] = 1800, -- Greater Blessing of Wisdom (Rank 3)
+ [27149] = 0, -- Devotion Aura (Rank 8)
+ [27150] = 0, -- Retribution Aura (Rank 6)
+ [27151] = 0, -- Shadow Resistance Aura (Rank 4)
+ [27152] = 0, -- Frost Resistance Aura (Rank 4)
+ [27153] = 0, -- Fire Resistance Aura (Rank 4)
+ [27187] = 12, -- Deadly Poison VII (Rank 7)
+ [27243] = 18, -- Seed of Corruption
+ [27260] = 1800, -- Demon Armor (Rank 6)
+ [27268] = 0, -- Blood Pact (Rank 6)
+ [27681] = 3600, -- Prayer of Spirit (Rank 1)
+ [27683] = 1200, -- Prayer of Shadow Protection (Rank 1)
+ [27813] = 6, -- Blessed Recovery (Rank 1)
+ [27817] = 6, -- Blessed Recovery (Rank 2)
+ [27818] = 6, -- Blessed Recovery (Rank 3)
+ [27827] = 15, -- Spirit of Redemption
+ [27828] = 6, -- Focused Casting (Rank 2)
+ [27841] = 1800, -- Divine Spirit (Rank 4)
+ [27863] = 600, -- The Baron's Ultimatum
+ [28093] = 15, -- Lightning Speed
+ [28176] = 1800, -- Fel Armor (Rank 1)
+ [28189] = 1800, -- Fel Armor (Rank 2)
+ [28271] = 50, -- Polymorph (turtle)
+ [28272] = 50, -- Polymorph (pig)
+ [28273] = 600, -- Bloodthistle
+ [28274] = 1200, -- Bloodthistle Withdrawal
+ [28489] = 3600, -- Camouflage
+ [28491] = 3600, -- Healing Power
+ [28497] = 3600, -- Mighty Agility
+ [28509] = 3600, -- Greater Mana Regeneration
+ [28518] = 3600, -- Flask of Fortification
+ [28520] = 7200, -- Flask of Relentless Assault
+ [28521] = 3600, -- Flask of Blinding Light
+ [28682] = 0, -- Combustion
+ [28694] = 900, -- Dreaming Glory
+ [28703] = 900, -- Netherbloom Pollen
+ [28730] = 2, -- Arcane Torrent (Racial)
+ [28747] = 600, -- Frenzy
+ [28878] = 0, -- Heroic Presence (Racial Passive)
+ [29073] = 30, -- Food
+ [29131] = 10, -- Bloodrage
+ [29166] = 10, -- Innervate
+ [29175] = 3600, -- Ribbon Dance [This duration changed based on how long you've used the ribbon poll]
+ [29177] = 10, -- Elemental Devastation (Rank 2)
+ [29178] = 10, -- Elemental Devastation (Rank 3)
+ [29228] = 18, -- Flame Shock (Rank 6)
+ [29235] = 3600, -- Fire Festival Fortitude
+ [29332] = 3600, -- Fire-toasted Bun
+ [29333] = 3600, -- Midsummer Sausage
+ [29334] = 3600, -- Toasted Smorc
+ [29335] = 3600, -- Elderberry Pie
+ [29341] = 5, -- Shadowburn
+ [29348] = 3600, -- Goldenmist Special Brew
+ [29544] = 6, -- Frightening Shout
+ [29674] = 0, -- Lesser Shielding
+ [29703] = 6, -- Dazed
+ [29801] = 0, -- Rampage (Passive)
+ [29842] = 10, -- Second Wind (Rank 2)
+ [29882] = 0, -- Loose Mana
+ [30070] = 0, -- Blood Frenzy (Rank 2)
+ [30108] = 15, -- Unstable Affliction
+ [30151] = 6, -- Pursuit
+ [30213] = 6, -- Legion Strike
+ [30283] = 3, -- Shadowfury
+ [30482] = 1800, -- Molten Armor (Rank 1)
+ [30708] = 0, -- Totem of Wrath
+ [30802] = 0, -- Unleashed Rage (Rank 1)
+ [30808] = 0, -- Unleashed Rage (Rank 2)
+ [30809] = 0, -- Unleashed Rage (Rank 3)
+ [30823] = 15, -- Shamanistic Rage
+ [30910] = 60, -- Curse of Doom (Rank 2)
+ [30931] = 20, -- Battle Shout
+ [30991] = 0, -- Stealth
+ [31117] = 5, -- Unstable Affliction
+ [31125] = 4, -- Blade Twisting
+ [31224] = 5, -- Cloak of Shadows
+ [31403] = 120, -- Battle Shout
+ [31462] = 3600, -- Moonwell Restoration
+ [31579] = 0, -- Arcane Empowerment (Rank 1)
+ [31583] = 0, -- Arcane Empowerment (Rank 3)
+ [31589] = 15, -- Slow
+ [31616] = 10, -- Nature's Guardian
+ [31643] = 8, -- Blazing Speed
+ [31661] = 5, -- Dragon's Breath (Rank 1)
+ [31665] = 6, -- Master of Subtlety
+ [31790] = 3, -- Righteous Defense
+ [31801] = 1800, -- Seal of Vengeance
+ [31803] = 15, -- Holy Vengeance (Rank 1)
+ [31821] = 6, -- Aura Mastery
+ [31834] = 15, -- Light's Grace
+ [31842] = 15, -- Divine Illumination
+ [31850] = 10, -- Ardent Defender
+ [31884] = 20, -- Avenging Wrath
+ [31930] = 10, -- Judgements of the Wise
+ [31935] = 3, -- Avenger's Shield
+ [32182] = 40, -- Heroism
+ [32216] = 20, -- Victorious
+ [32223] = 0, -- Crusader Aura
+ [32240] = 0, -- Snowy Gryphon
+ [32243] = 0, -- Tawny Wind Rider
+ [32244] = 0, -- Blue Wind Rider
+ [32245] = 0, -- Green Wind Rider
+ [32246] = 0, -- Swift Red Wind Rider
+ [32289] = 0, -- Swift Red Gryphon
+ [32292] = 0, -- Swift Purple Gryphon
+ [32295] = 0, -- Swift Green Wind Rider
+ [32296] = 0, -- Swift Yellow Wind Rider
+ [32297] = 0, -- Swift Purple Wind Rider
+ [32386] = 12, -- Shadow Embrace
+ [32388] = 12, -- Shadow Embrace
+ [32389] = 12, -- Shadow Embrace
+ [32390] = 12, -- Shadow Embrace
+ [32391] = 12, -- Shadow Embrace
+ [32409] = 1, -- Shadow Word: Death
+ [32593] = 600, -- Earth Shield (Rank 2)
+ [32594] = 600, -- Earth Shield (Rank 3)
+ [32600] = 10, -- Avoidance
+ [32612] = 0, -- Invisibility
+ [32645] = 1, -- Envenom
+ [32727] = 0, -- Arena Preparation
+ [32736] = 5, -- Mortal Strike
+ [32752] = 5, -- Summoning Disorientation
+ [32851] = 10, -- Demonic Frenzy
+ [32999] = 3600, -- Prayer of Spirit (Rank 2)
+ [33041] = 5, -- Dragon's Breath (Rank 2)
+ [33042] = 5, -- Dragon's Breath (Rank 3)
+ [33043] = 5, -- Dragon's Breath (Rank 4)
+ [33053] = 7200, -- Mr Pinchy's Blessing
+ [33082] = 1800, -- Strength (Rank 5)
+ [33151] = 10, -- Surge of Light (Rank 1)
+ [33197] = 24, -- Misery (Rank 2)
+ [33198] = 24, -- Misery (Rank 3)
+ [33206] = 8, -- Pain Suppression
+ [33254] = 1800, -- Well Fed
+ [33256] = 1800, -- Well Fed
+ [33257] = 1800, -- Well Fed
+ [33259] = 1800, -- Well Fed
+ [33263] = 1800, -- Well Fed
+ [33268] = 1800, -- Well Fed
+ [33280] = 0, -- Corporal
+ [33357] = 15, -- Dash (Rank 3)
+ [33395] = 2, -- Freeze
+ [33660] = 0, -- Swift Pink Hawkstrider
+ [33697] = 15, -- Blood Fury (Racial)
+ [33702] = 15, -- Blood Fury (Racial)
+ [33720] = 7200, -- Onslaught Elixir
+ [33721] = 3600, -- Spellpower Elixir
+ [33726] = 3600, -- Elixir of Mastery
+ [33736] = 600, -- Water Shield (Rank 8)
+ [33745] = 15, -- Lacerate
+ [33763] = 7, -- Lifebloom (Rank 1)
+ [33786] = 6, -- Cyclone
+ [33876] = 60, -- Mangle
+ [33878] = 60, -- Mangle
+ [33891] = 0, -- Tree of Life (Shapeshift)
+ [33943] = 0, -- Flight Form (Shapeshift)
+ [33944] = 600, -- Dampen Magic (Rank 6)
+ [33946] = 600, -- Amplify Magic (Rank 6)
+ [34027] = 30, -- Kill Command (Rank 1)
+ [34074] = 0, -- Aspect of the Viper
+ [34123] = 0, -- Tree of Life (Passive)
+ [34321] = 10, -- Call of the Nexus
+ [34410] = 3600, -- Hellscream's Warsong
+ [34471] = 10, -- The Beast Within
+ [34477] = 30, -- Misdirection
+ [34490] = 3, -- Silencing Shot
+ [34501] = 7, -- Expose Weakness
+ [34655] = 8, -- Deadly Poison
+ [34709] = 15, -- Shadow Sight
+ [34767] = 0, -- Summon Charger (Summon)
+ [34769] = 0, -- Summon Warhorse (Summon)
+ [34790] = 0, -- Dark War Talbuk
+ [34795] = 0, -- Red Hawkstrider
+ [34837] = 8, -- Master Tactician (Rank 5)
+ [34896] = 0, -- Cobalt War Talbuk
+ [34897] = 0, -- White War Talbuk
+ [34898] = 0, -- Silver War Talbuk
+ [34899] = 0, -- Tan War Talbuk
+ [34914] = 15, -- Vampiric Touch
+ [34917] = 15, -- Vampiric Touch (Rank 3)
+ [34936] = 8, -- Backlash
+ [34976] = 0, -- Netherstorm Flag
+ [35018] = 0, -- Purple Hawkstrider
+ [35020] = 0, -- Blue Hawkstrider
+ [35022] = 0, -- Black Hawkstrider
+ [35025] = 0, -- Swift Green Hawkstrider
+ [35027] = 0, -- Swift Purple Hawkstrider
+ [35028] = 0, -- Swift Warstrider
+ [35079] = 4, -- Misdirection
+ [35098] = 20, -- Rapid Killing (Rank 1)
+ [35099] = 20, -- Rapid Killing (Rank 2)
+ [35101] = 4, -- Concussive Barrage
+ [35696] = 0, -- Demonic Knowledge
+ [35706] = 0, -- Master Demonologist
+ [35712] = 0, -- Great Green Elekk
+ [35713] = 0, -- Great Blue Elekk
+ [35714] = 0, -- Great Purple Elekk
+ [35944] = 30, -- Power Word: Shield
+ [36032] = 6, -- Arcane Blast
+ [36444] = 0, -- Wintergrasp Water
+ [36554] = 3, -- Shadowstep
+ [36563] = 10, -- Shadowstep
+ [36702] = 0, -- Fiery Warhorse
+ [36893] = 3600, -- Transporter Malfunction
+ [36895] = 3600, -- Transporter Malfunction
+ [36897] = 3600, -- Transporter Malfunction
+ [36899] = 3600, -- Transporter Malfunction
+ [37548] = 3, -- Taunt
+ [37578] = 5, -- Debilitating Strike
+ [37795] = 0, -- Recruit
+ [38232] = 20, -- Battle Shout
+ [38254] = 1800, -- Festering Wound
+ [38384] = 8, -- Cone of Cold
+ [39171] = 5, -- Mortal Strike
+ [39315] = 0, -- Cobalt Riding Talbuk
+ [39316] = 0, -- Dark Riding Talbuk
+ [39317] = 0, -- Silver Riding Talbuk
+ [39318] = 0, -- Tan Riding Talbuk
+ [39319] = 0, -- White Riding Talbuk
+ [39374] = 1200, -- Prayer of Shadow Protection (Rank 2)
+ [39439] = 10, -- Aura of the Crusader
+ [39627] = 3600, -- Elixir of Draenic Wisdom
+ [39628] = 3600, -- Elixir of Ironskin
+ [39796] = 3, -- Stoneclaw Stun
+ [39800] = 0, -- Red Riding Nether Ray
+ [39802] = 0, -- Silver Riding Nether Ray
+ [40120] = 0, -- Swift Flight Form (Shapeshift)
+ [40192] = 0, -- Ashes of Al'ar
+ [40623] = 3600, -- Apexis Vibrations
+ [40625] = 5400, -- Apexis Emanations
+ [41252] = 0, -- Raven Lord
+ [41425] = 30, -- Hypothermia
+ [41513] = 0, -- Onyx Netherwing Drake
+ [41514] = 0, -- Azure Netherwing Drake
+ [41516] = 0, -- Purple Netherwing Drake
+ [41635] = 30, -- Prayer of Mending (Rank 1)
+ [42138] = 7200, -- Brewfest Enthusiast
+ [42292] = 0, -- PvP Trinket
+ [42650] = 4, -- Army of the Dead
+ [42702] = 10, -- Decrepify
+ [42705] = 60, -- Enrage
+ [42723] = 2, -- Dark Smash
+ [42728] = 60, -- Dreadful Roar
+ [42740] = 8, -- Njord's Rune of Protection
+ [42777] = 0, -- Swift Spectral Tiger
+ [42792] = 3, -- Recently Dropped Flag
+ [42833] = 8, -- Fireball (Rank 16)
+ [42842] = 9, -- Frostbolt (Rank 16)
+ [42891] = 0, -- Pyroblast (Rank 12)
+ [42917] = 8, -- Frost Nova (Rank 6)
+ [42931] = 11, -- Cone of Cold (Rank 8)
+ [42949] = 5, -- Dragon's Breath (Rank 5)
+ [42950] = 5, -- Dragon's Breath (Rank 6)
+ [42995] = 1800, -- Arcane Intellect (Rank 7)
+ [43002] = 3600, -- Arcane Brilliance (Rank 3)
+ [43008] = 1800, -- Ice Armor (Rank 6)
+ [43010] = 30, -- Fire Ward (Rank 7)
+ [43012] = 30, -- Frost Ward (Rank 7)
+ [43015] = 600, -- Dampen Magic (Rank 7)
+ [43017] = 600, -- Amplify Magic (Rank 7)
+ [43019] = 60, -- Mana Shield (Rank 8)
+ [43020] = 60, -- Mana Shield (Rank 9)
+ [43023] = 1800, -- Mage Armor (Rank 5)
+ [43024] = 1800, -- Mage Armor (Rank 6)
+ [43038] = 60, -- Ice Barrier (Rank 7)
+ [43039] = 60, -- Ice Barrier (Rank 8)
+ [43045] = 1800, -- Molten Armor (Rank 2)
+ [43046] = 1800, -- Molten Armor (Rank 3)
+ [43180] = 30, -- Food
+ [43182] = 30, -- Drink
+ [43183] = 30, -- Drink
+ [43195] = 1800, -- Intellect (Rank 6)
+ [43196] = 1800, -- Armor (Rank 6)
+ [43197] = 1800, -- Spirit (Rank 6)
+ [43265] = 0, -- Death and Decay (Rank 1)
+ [43664] = 15, -- Unholy Rage
+ [43680] = 60, -- Idle
+ [43681] = 60, -- Inactive
+ [43688] = 0, -- Amani War Bear
+ [43751] = 10, -- Energized
+ [43771] = 3600, -- Well Fed
+ [43900] = 0, -- Swift Brewfest Ram
+ [43927] = 0, -- Cenarion War Hippogryph
+ [43931] = 15, -- Rend
+ [44151] = 0, -- Turbo-Charged Flying Machine
+ [44153] = 0, -- Flying Machine
+ [44212] = 3600, -- Jack-o'-Lanterned!
+ [44401] = 15, -- Missile Barrage
+ [44413] = 10, -- Incanter's Absorption
+ [44415] = 3, -- Blackout (Rank 1)
+ [44457] = 12, -- Living Bomb
+ [44521] = 0, -- Preparation
+ [44535] = 6, -- Spirit Heal
+ [44544] = 15, -- Fingers of Frost
+ [44572] = 5, -- Deep Freeze
+ [44614] = 9, -- Frostfire Bolt (Rank 1)
+ [44795] = 0, -- Parachute
+ [44825] = 0, -- Flying Reindeer
+ [45062] = 0, -- Holy Energy
+ [45123] = 0, -- Romantic Picnic
+ [45182] = 3, -- Cheating Death
+ [45241] = 8, -- Focused Will (Rank 2)
+ [45242] = 8, -- Focused Will (Rank 3)
+ [45245] = 1800, -- Well Fed
+ [45282] = 8, -- Natural Perfection (Rank 2)
+ [45283] = 8, -- Natural Perfection (Rank 3)
+ [45334] = 4, -- Feral Charge Effect
+ [45373] = 7200, -- Bloodberry
+ [45438] = 10, -- Ice Block
+ [45444] = 0, -- Bonfire's Blessing
+ [45472] = 60, -- Parachute
+ [45524] = 10, -- Chains of Ice
+ [45529] = 20, -- Blood Tap
+ [45544] = 8, -- First Aid (Rank 15)
+ [45548] = 30, -- Food
+ [45693] = 0, -- Torches Caught
+ [45694] = 180, -- Captain Rumsey's Lager
+ [45699] = 5, -- Flames of Failure
+ [45716] = 40, -- Torch Tossing Training
+ [45724] = 0, -- Braziers Hit!
+ [46168] = 0, -- Pet Biscuit
+ [46199] = 0, -- X-51 Nether-Rocket X-TREME
+ [46202] = 10, -- Pierce Armor
+ [46221] = 180, -- Animal Blood
+ [46352] = 3600, -- Fire Festival Fury
+ [46355] = 300, -- Blood Elf Illusion
+ [46356] = 300, -- Blood Elf Illusion
+ [46604] = 4, -- Ice Block
+ [46628] = 0, -- Swift White Hawkstrider
+ [46630] = 90, -- Torch Tossing Practice
+ [46833] = 15, -- Wrath of Elune
+ [46857] = 60, -- Trauma (Rank 2)
+ [46899] = 900, -- Well Fed
+ [46916] = 5, -- Slam!
+ [46924] = 6, -- Bladestorm
+ [46968] = 4, -- Shockwave
+ [46987] = 4, -- Frostbolt
+ [46989] = 4, -- Improved Blink
+ [47057] = 180, -- Fiery Seduction
+ [47241] = 30, -- Metamorphosis
+ [47283] = 8, -- Empowered Imp
+ [47436] = 120, -- Battle Shout (Rank 9)
+ [47437] = 30, -- Demoralizing Shout (Rank 8)
+ [47439] = 360, -- Commanding Shout (Rank 2)
+ [47440] = 120, -- Commanding Shout (Rank 3)
+ [47465] = 15, -- Rend (Rank 10)
+ [47476] = 5, -- Strangulate
+ [47481] = 3, -- Gnaw
+ [47486] = 10, -- Mortal Strike (Rank 8)
+ [47501] = 30, -- Thunder Clap (Rank 8)
+ [47502] = 30, -- Thunder Clap (Rank 9)
+ [47543] = 0, -- Frozen Prison
+ [47585] = 6, -- Dispersion
+ [47610] = 12, -- Frostfire Bolt (Rank 2)
+ [47699] = 300, -- Crystal Bark
+ [47747] = 45, -- Charge Rifts
+ [47748] = 45, -- Rift Shield
+ [47753] = 12, -- Divine Aegis (Rank 1)
+ [47774] = 120, -- Frenzy
+ [47779] = 4, -- Arcane Torrent
+ [47781] = 6, -- Spellbreaker
+ [47791] = 5, -- Arcane Haste
+ [47811] = 15, -- Immolate (Rank 11)
+ [47813] = 18, -- Corruption (Rank 10)
+ [47823] = 15, -- Hellfire (Rank 5)
+ [47836] = 18, -- Seed of Corruption (Rank 3)
+ [47843] = 15, -- Unstable Affliction (Rank 5)
+ [47847] = 3, -- Shadowfury (Rank 5)
+ [47854] = 0, -- Frozen Prison
+ [47855] = 15, -- Drain Soul (Rank 6)
+ [47856] = 9, -- Health Funnel (Rank 9)
+ [47857] = 5, -- Drain Life (Rank 9)
+ [47860] = 3, -- Death Coil (Rank 6)
+ [47864] = 24, -- Curse of Agony (Rank 9)
+ [47865] = 300, -- Curse of the Elements (Rank 5)
+ [47867] = 60, -- Curse of Doom (Rank 3)
+ [47883] = 900, -- Soulstone Resurrection
+ [47889] = 1800, -- Demon Armor (Rank 8)
+ [47891] = 30, -- Shadow Ward (Rank 6)
+ [47892] = 1800, -- Fel Armor (Rank 3)
+ [47893] = 1800, -- Fel Armor (Rank 4)
+ [47930] = 15, -- Grace
+ [47960] = 6, -- Shadowflame
+ [47981] = 15, -- Spell Reflection
+ [47982] = 0, -- Blood Pact (Rank 7)
+ [47983] = 180, -- Fire Shield (Rank 7)
+ [47986] = 30, -- Sacrifice (Rank 9)
+ [47988] = 6, -- Consume Shadows (Rank 9)
+ [47990] = 15, -- Suffering (Rank 8)
+ [47995] = 3, -- Intercept (Rank 4)
+ [48018] = 360, -- Demonic Circle: Summon
+ [48020] = 1, -- Demonic Circle: Teleport
+ [48024] = 0, -- Headless Horseman's Mount
+ [48025] = 0, -- Headless Horseman's Mount
+ [48027] = 0, -- Black War Elekk
+ [48040] = 1800, -- Inner Fire (Rank 8)
+ [48058] = 30, -- Crystal Bloom
+ [48065] = 30, -- Power Word: Shield (Rank 13)
+ [48066] = 30, -- Power Word: Shield (Rank 14)
+ [48068] = 15, -- Renew (Rank 14)
+ [48073] = 1800, -- Divine Spirit (Rank 6)
+ [48074] = 3600, -- Prayer of Spirit (Rank 3)
+ [48090] = 45, -- Demonic Pact
+ [48095] = 0, -- Intense Cold
+ [48100] = 1800, -- Intellect (Rank 7)
+ [48101] = 1800, -- Stamina (Level 6)
+ [48102] = 1800, -- Stamina (Level 6)
+ [48103] = 1800, -- Spirit (Rank 7)
+ [48108] = 10, -- Hot Streak
+ [48111] = 30, -- Prayer of Mending (Rank 3)
+ [48125] = 18, -- Shadow Word: Pain (Rank 12)
+ [48135] = 7, -- Holy Fire (Rank 11)
+ [48155] = 3, -- Mind Flay (Rank 8)
+ [48156] = 3, -- Mind Flay (Rank 9)
+ [48160] = 15, -- Vampiric Touch (Rank 5)
+ [48161] = 1800, -- Power Word: Fortitude (Rank 8)
+ [48162] = 3600, -- Prayer of Fortitude (Rank 4)
+ [48168] = 1800, -- Inner Fire (Rank 9)
+ [48169] = 600, -- Shadow Protection (Rank 5)
+ [48170] = 1200, -- Prayer of Shadow Protection (Rank 3)
+ [48181] = 12, -- Haunt
+ [48263] = 0, -- Frost Presence
+ [48265] = 0, -- Unholy Presence
+ [48266] = 0, -- Blood Presence
+ [48299] = 24, -- Devouring Plague (Rank 8)
+ [48300] = 24, -- Devouring Plague (Rank 9)
+ [48301] = 10, -- Mind Trauma
+ [48333] = 300, -- Going Ape
+ [48391] = 10, -- Owlkin Frenzy
+ [48400] = 20, -- Frost Tomb
+ [48418] = 0, -- Master Shapeshifter
+ [48420] = 0, -- Master Shapeshifter
+ [48421] = 0, -- Master Shapeshifter
+ [48422] = 0, -- Master Shapeshifter
+ [48438] = 7, -- Wild Growth
+ [48440] = 15, -- Rejuvenation (Rank 14)
+ [48441] = 15, -- Rejuvenation (Rank 15)
+ [48442] = 21, -- Regrowth (Rank 11)
+ [48443] = 21, -- Regrowth (Rank 12)
+ [48446] = 0, -- Tranquility (Rank 6)
+ [48447] = 7, -- Tranquility (Rank 7)
+ [48450] = 7, -- Lifebloom (Rank 2)
+ [48451] = 7, -- Lifebloom (Rank 3)
+ [48463] = 12, -- Moonfire (Rank 14)
+ [48467] = 0, -- Hurricane (Rank 5)
+ [48468] = 14, -- Insect Swarm (Rank 7)
+ [48469] = 1800, -- Mark of the Wild (Rank 9)
+ [48470] = 3600, -- Gift of the Wild (Rank 4)
+ [48504] = 15, -- Living Seed
+ [48505] = 10, -- Starfall
+ [48517] = 15, -- Eclipse (Solar)
+ [48518] = 15, -- Eclipse (Lunar)
+ [48560] = 30, -- Demoralizing Roar (Rank 8)
+ [48564] = 60, -- Mangle (Bear) (Rank 5)
+ [48565] = 60, -- Mangle (Cat) (Rank 4)
+ [48566] = 60, -- Mangle (Cat) (Rank 5)
+ [48568] = 15, -- Lacerate (Rank 3)
+ [48574] = 9, -- Rake (Rank 7)
+ [48660] = 15, -- Hemorrhage (Rank 5)
+ [48671] = 14, -- Rupture (Rank 8)
+ [48672] = 16, -- Rupture (Rank 9)
+ [48674] = 6, -- Deadly Throw (Rank 3)
+ [48675] = 18, -- Garrote (Rank 9)
+ [48676] = 18, -- Garrote (Rank 10)
+ [48707] = 5, -- Anti-Magic Shell
+ [48719] = 600, -- Water Breathing
+ [48778] = 0, -- Acherus Deathcharger (Summon)
+ [48792] = 12, -- Icebound Fortitude
+ [48817] = 3, -- Holy Wrath (Rank 5)
+ [48827] = 10, -- Avenger's Shield (Rank 5)
+ [48836] = 5, -- Vengeful Justice
+ [48838] = 10, -- Elemental Tenacity
+ [48846] = 20, -- Runic Infusion
+ [48931] = 1800, -- Blessing of Might (Rank 9)
+ [48932] = 600, -- Blessing of Might (Rank 10)
+ [48933] = 1800, -- Greater Blessing of Might (Rank 4)
+ [48934] = 1800, -- Greater Blessing of Might (Rank 5)
+ [48935] = 600, -- Blessing of Wisdom (Rank 8)
+ [48936] = 600, -- Blessing of Wisdom (Rank 9)
+ [48937] = 1800, -- Greater Blessing of Wisdom (Rank 4)
+ [48938] = 1800, -- Greater Blessing of Wisdom (Rank 5)
+ [48941] = 0, -- Devotion Aura (Rank 9)
+ [48942] = 0, -- Devotion Aura (Rank 10)
+ [48943] = 0, -- Shadow Resistance Aura (Rank 5)
+ [48945] = 0, -- Frost Resistance Aura (Rank 5)
+ [48947] = 0, -- Fire Resistance Aura (Rank 5)
+ [48952] = 10, -- Holy Shield (Rank 6)
+ [48989] = 15, -- Mend Pet (Rank 9)
+ [48990] = 15, -- Mend Pet (Rank 10)
+ [49000] = 21, -- Serpent Sting (Rank 11)
+ [49001] = 15, -- Serpent Sting (Rank 12)
+ [49005] = 20, -- Mark of Blood
+ [49010] = 30, -- Wyvern Sting (Rank 6)
+ [49012] = 30, -- Wyvern Sting (Rank 6)
+ [49016] = 30, -- Hysteria
+ [49028] = 12, -- Dancing Rune Weapon
+ [49039] = 10, -- Lichborne
+ [49050] = 10, -- Aimed Shot (Rank 9)
+ [49054] = 15, -- Immolation Trap (Rank 8)
+ [49065] = 0, -- Explosive Trap Effect (Rank 6)
+ [49071] = 0, -- Aspect of the Wild (Rank 4)
+ [49203] = 10, -- Hungering Cold (Rank 1)
+ [49206] = 0, -- Summon Gargoyle
+ [49222] = 300, -- Bone Shield
+ [49231] = 8, -- Earth Shock (Rank 10)
+ [49232] = 18, -- Flame Shock (Rank 8)
+ [49233] = 18, -- Flame Shock (Rank 9)
+ [49236] = 8, -- Frost Shock (Rank 7)
+ [49280] = 600, -- Lightning Shield (Rank 10)
+ [49281] = 600, -- Lightning Shield (Rank 11)
+ [49284] = 600, -- Earth Shield (Rank 5)
+ [49322] = 0, -- Swift Zhevra
+ [49379] = 0, -- Great Brewfest Kodo
+ [49560] = 3, -- Death Grip
+ [49623] = 15, -- Effervescence
+ [49759] = 0, -- Teleport
+ [49800] = 12, -- Rip (Rank 9)
+ [49802] = 6, -- Maim (Rank 2)
+ [49803] = 4, -- Pounce (Rank 5)
+ [49804] = 18, -- Pounce Bleed (Rank 5)
+ [49868] = 0, -- Mind Quickening
+ [49938] = 0, -- Death and Decay (Rank 4)
+ [49962] = 17, -- Jungle Madness!
+ [50131] = 10, -- Draw Magic
+ [50213] = 6, -- Tiger's Fury (Rank 6)
+ [50227] = 5, -- Sword and Board
+ [50259] = 3, -- Dazed
+ [50263] = 20, -- Quickness of the Sailor
+ [50334] = 15, -- Berserk
+ [50411] = 3, -- Dazed
+ [50421] = 20, -- Scent of Blood
+ [50434] = 10, -- Icy Clutch
+ [50435] = 10, -- Chilblains
+ [50436] = 10, -- Icy Clutch
+ [50448] = 30, -- Bloody Vengeance
+ [50449] = 30, -- Bloody Vengeance
+ [50461] = 0, -- Anti-Magic Zone
+ [50486] = 18, -- Acclimation
+ [50510] = 0, -- Crypt Fever
+ [50511] = 120, -- Curse of Weakness (Rank 9)
+ [50518] = 2, -- Ravage (Rank 1)
+ [50519] = 2, -- Sonic Blast (Rank 1)
+ [50536] = 10, -- Unholy Blight
+ [50589] = 13, -- Immolation Aura (Demon)
+ [50613] = 2, -- Arcane Torrent (Racial)
+ [50720] = 1800, -- Vigilance
+ [50872] = 30, -- Savagery
+ [50882] = 20, -- Icy Talons
+ [50989] = 3, -- Flame Breath
+ [51124] = 30, -- Killing Machine
+ [51185] = 0, -- King of the Jungle
+ [51209] = 10, -- Hungering Cold (Rank 1)
+ [51271] = 20, -- Unbreakable Armor
+ [51399] = 2, -- Death Grip
+ [51460] = 3, -- Runic Corruption
+ [51466] = 0, -- Elemental Oath (Rank 1)
+ [51470] = 0, -- Elemental Oath (Rank 2)
+ [51514] = 30, -- Hex
+ [51585] = 8, -- Blade Twisting
+ [51690] = 2, -- Killing Spree
+ [51693] = 8, -- Waylay
+ [51698] = 0, -- Honor Among Thieves
+ [51700] = 0, -- Honor Among Thieves
+ [51701] = 0, -- Honor Among Thieves
+ [51713] = 6, -- Shadow Dance
+ [51714] = 20, -- Frost Vulnerability
+ [51722] = 10, -- Dismantle
+ [51724] = 60, -- Sap (Rank 4)
+ [51726] = 0, -- Ebon Plague
+ [51735] = 15, -- Ebon Plague
+ [51755] = 60, -- Camouflage
+ [51789] = 10, -- Blade Barrier
+ [51911] = 2, -- Spell Deflection
+ [51945] = 12, -- Earthliving (Rank 1)
+ [51987] = 20, -- Arcane Infusion
+ [51990] = 12, -- Earthliving (Rank 2)
+ [51999] = 12, -- Earthliving (Rank 5)
+ [52000] = 12, -- Earthliving (Rank 6)
+ [52109] = 0, -- Flametongue Totem (Rank 1)
+ [52110] = 0, -- Flametongue Totem (Rank 2)
+ [52111] = 0, -- Flametongue Totem (Rank 3)
+ [52113] = 0, -- Flametongue Totem (Rank 5)
+ [52127] = 600, -- Water Shield (Rank 1)
+ [52129] = 600, -- Water Shield (Rank 2)
+ [52131] = 600, -- Water Shield (Rank 3)
+ [52134] = 600, -- Water Shield (Rank 4)
+ [52136] = 600, -- Water Shield (Rank 5)
+ [52138] = 600, -- Water Shield (Rank 6)
+ [52179] = 0, -- Astral Shift
+ [52418] = 0, -- Carrying Seaforium
+ [52419] = 10, -- Deflection
+ [52437] = 10, -- Sudden Death
+ [52446] = 10, -- Acid Splash
+ [52459] = 10, -- End of Round
+ [52470] = 8, -- Enrage
+ [52493] = 10, -- Poison Spray
+ [52537] = 10, -- Fixate
+ [52610] = 34, -- Savage Roar (Rank 1) (note this duration changes by combo points, 14, 19, 24, 29, 34)
+ [52909] = 1800, -- Water Breathing
+ [52910] = 8, -- Turn the Tables
+ [53023] = 5, -- Mind Sear (Rank 2)
+ [53030] = 10, -- Leech Poison
+ [53137] = 0, -- Abomination's Might (Rank 1)
+ [53138] = 0, -- Abomination's Might (Rank 2)
+ [53148] = 1, -- Charge
+ [53200] = 0, -- Starfall (Rank 3)
+ [53201] = 10, -- Starfall (Rank 4)
+ [53220] = 12, -- Improved Steady Shot
+ [53227] = 6, -- Typhoon (Rank 5)
+ [53251] = 7, -- Wild Growth (Rank 4)
+ [53257] = 10, -- Cobra Strikes
+ [53283] = 30, -- Food
+ [53284] = 1800, -- Well Fed
+ [53290] = 0, -- Hunting Party
+ [53301] = 2, -- Explosive Shot (Rank 1)
+ [53307] = 600, -- Thorns (Rank 8)
+ [53308] = 27, -- Entangling Roots (Rank 8)
+ [53312] = 45, -- Nature's Grasp (Rank 8)
+ [53313] = 27, -- Entangling Roots (Rank 8)
+ [53317] = 15, -- Rend
+ [53322] = 6, -- Crushing Webs
+ [53330] = 20, -- Infected Wound
+ [53334] = 9, -- Animate Bones
+ [53338] = 300, -- Hunter's Mark (Rank 5)
+ [53365] = 15, -- Unholy Strength
+ [53386] = 30, -- Cinderglacier
+ [53390] = 15, -- Tidal Waves
+ [53401] = 20, -- Rabid
+ [53403] = 0, -- Rabid Power
+ [53426] = 5, -- Lick Your Wounds
+ [53434] = 20, -- Call of the Wild
+ [53467] = 15, -- Leeching Swarm
+ [53468] = 0, -- Leeching Swarm
+ [53477] = 3, -- Taunt
+ [53480] = 12, -- Roar of Sacrifice
+ [53515] = 8, -- Owl's Focus
+ [53517] = 9, -- Roar of Recovery
+ [53520] = 4, -- Carrion Beetles
+ [53547] = 4, -- Pin (Rank 5)
+ [53548] = 4, -- Pin (Rank 6)
+ [53563] = 60, -- Beacon of Light
+ [53572] = 6, -- Tendon Rip (Rank 3)
+ [53578] = 15, -- Savage Rend (Rank 2)
+ [53579] = 15, -- Savage Rend (Rank 3)
+ [53601] = 30, -- Sacred Shield (Rank 1)
+ [53602] = 12, -- Dart
+ [53646] = 0, -- Demonic Pact
+ [53657] = 60, -- Judgements of the Pure (Rank 3)
+ [53659] = 10, -- Sacred Cleansing
+ [53736] = 1800, -- Seal of Corruption
+ [53742] = 15, -- Blood Corruption (Rank 1)
+ [53746] = 3600, -- Wrath Elixir
+ [53747] = 3600, -- Elixir of Spirit
+ [53748] = 3600, -- Mighty Strength
+ [53749] = 3600, -- Guru's Elixir
+ [53751] = 3600, -- Elixir of Mighty Fortitude
+ [53752] = 3600, -- Lesser Flask of Toughness
+ [53755] = 3600, -- Flask of the Frost Wyrm
+ [53758] = 3600, -- Flask of Stoneblood
+ [53760] = 3600, -- Flask of Endless Rage
+ [53764] = 3600, -- Mighty Mana Regeneration
+ [53768] = 0, -- Haunted
+ [53801] = 600, -- Frenzy
+ [53805] = 600, -- Pygmy Oil
+ [53806] = 600, -- Pygmy Oil
+ [53817] = 30, -- Maelstrom Weapon
+ [53908] = 15, -- Speed
+ [53909] = 15, -- Wild Magic
+ [54043] = 0, -- Retribution Aura (Rank 7)
+ [54131] = 5, -- Bloodthirsty
+ [54149] = 15, -- Infusion of Light (Rank 2)
+ [54152] = 60, -- Judgements of the Pure (Rank 4)
+ [54153] = 60, -- Judgements of the Pure (Rank 5)
+ [54203] = 12, -- Sheath of Light
+ [54212] = 3600, -- Flask of Pure Mojo
+ [54216] = 4, -- Master's Call
+ [54277] = 15, -- Backdraft
+ [54309] = 10, -- Mark of Darkness
+ [54314] = 30, -- Drain Power
+ [54315] = 30, -- Drain Power
+ [54370] = 8, -- Nether Protection
+ [54371] = 8, -- Nether Protection
+ [54372] = 8, -- Nether Protection
+ [54373] = 8, -- Nether Protection
+ [54374] = 8, -- Nether Protection
+ [54375] = 8, -- Nether Protection
+ [54424] = 0, -- Fel Intelligence (Rank 1)
+ [54428] = 15, -- Divine Plea
+ [54443] = 20, -- Demonic Empowerment
+ [54452] = 3600, -- Adept's Elixir
+ [54494] = 3600, -- Major Agility
+ [54497] = 3600, -- Lesser Armor
+ [54499] = 20, -- Heart of the Crusader (Rank 3)
+ [54501] = 6, -- Consume Shadows
+ [54508] = 15, -- Demonic Empowerment
+ [54643] = 20, -- Teleport
+ [54646] = 1800, -- Focus Magic
+ [54648] = 10, -- Focus Magic
+ [54681] = 12, -- Monstrous Strength
+ [54706] = 5, -- Venom Web Spray
+ [54726] = 0, -- Winged Steed of the Ebon Blade
+ [54727] = 0, -- Winged Steed of the Ebon Blade
+ [54729] = 0, -- Winged Steed of the Ebon Blade
+ [54753] = 0, -- White Polar Bear
+ [54758] = 12, -- Hyperspeed Acceleration
+ [54786] = 2, -- Demon Leap
+ [54833] = 10, -- Glyph of Innervate
+ [54839] = 10, -- Purified Spirit
+ [54842] = 0, -- Thunder Charge
+ [54861] = 5, -- Nitro Boosts
+ [54955] = 0, -- Ticking Bomb
+ [54965] = 8, -- Bolthorn's Rune of Flame
+ [55001] = 30, -- Parachute
+ [55012] = 0, -- Lok'lira's Bargain
+ [55018] = 10, -- Sonic Awareness
+ [55021] = 4, -- Silenced - Improved Counterspell (Rank 2)
+ [55077] = 5, -- Pounce
+ [55078] = 15, -- Blood Plague
+ [55080] = 8, -- Shattered Barrier
+ [55095] = 15, -- Frost Fever
+ [55166] = 20, -- Tidal Force
+ [55233] = 10, -- Vampiric Blood
+ [55277] = 15, -- Stoneclaw Totem
+ [55328] = 15, -- Stoneclaw Totem
+ [55342] = 30, -- Mirror Image
+ [55360] = 12, -- Living Bomb (Rank 3)
+ [55428] = 5, -- Lifeblood (Rank 1)
+ [55480] = 5, -- Lifeblood (Rank 2)
+ [55502] = 5, -- Lifeblood (Rank 5)
+ [55503] = 5, -- Lifeblood (Rank 6)
+ [55531] = 0, -- Mechano-hog
+ [55610] = 0, -- Improved Icy Talons
+ [55629] = 0, -- First Lieutenant
+ [55637] = 15, -- Lightweave
+ [55694] = 10, -- Enraged Regeneration
+ [55711] = 600, -- Weakened Heart
+ [55741] = 0, -- Desecration
+ [55753] = 30, -- Acid Spit (Rank 5)
+ [55775] = 15, -- Swordguard Embroidery
+ [55817] = 3600, -- Eck Residue
+ [56112] = 10, -- Furious Attacks
+ [56161] = 6, -- Glyph of Prayer of Healing
+ [56222] = 3, -- Dark Command
+ [56352] = 12, -- Storm Punch
+ [56453] = 12, -- Lock and Load
+ [56520] = 600, -- Blessing of Might (Rank 10)
+ [56521] = 1800, -- Blessing of Wisdom
+ [56525] = 1800, -- Blessing of Kings
+ [56654] = 0, -- Rapid Recuperation
+ [56778] = 60, -- Mana Shield
+ [56827] = 60, -- Aura of Arcane Haste
+ [56969] = 8, -- Arcane Blast
+ [57054] = 10, -- Tranquility
+ [57056] = 0, -- Aura of Regeneration
+ [57063] = 10, -- Arcane Attraction
+ [57073] = 30, -- Drink
+ [57079] = 3600, -- Well Fed
+ [57086] = 0, -- Frenzy
+ [57097] = 3600, -- Well Fed
+ [57100] = 3600, -- Well Fed
+ [57102] = 3600, -- Well Fed
+ [57107] = 3600, -- Well Fed
+ [57111] = 3600, -- Well Fed
+ [57139] = 3600, -- Well Fed
+ [57286] = 3600, -- Well Fed
+ [57288] = 3600, -- Well Fed
+ [57291] = 3600, -- Well Fed
+ [57294] = 3600, -- Well Fed
+ [57325] = 3600, -- Well Fed
+ [57327] = 3600, -- Well Fed
+ [57329] = 3600, -- Well Fed
+ [57330] = 120, -- Horn of Winter (Rank 1)
+ [57332] = 3600, -- Well Fed
+ [57334] = 3600, -- Well Fed
+ [57348] = 0, -- Carrying an RP-GG
+ [57350] = 6, -- Illusionary Barrier
+ [57356] = 3600, -- Well Fed
+ [57358] = 3600, -- Well Fed
+ [57360] = 3600, -- Well Fed
+ [57363] = 3600, -- Well Fed
+ [57365] = 3600, -- Well Fed
+ [57367] = 3600, -- Well Fed
+ [57371] = 3600, -- Well Fed
+ [57399] = 3600, -- Well Fed
+ [57447] = 0, -- Kindred Spirits
+ [57452] = 0, -- Kindred Spirits
+ [57453] = 0, -- Kindred Spirits
+ [57457] = 0, -- Kindred Spirits
+ [57458] = 0, -- Kindred Spirits
+ [57475] = 0, -- Kindred Spirits
+ [57482] = 0, -- Kindred Spirits
+ [57483] = 0, -- Kindred Spirits
+ [57484] = 0, -- Kindred Spirits
+ [57485] = 0, -- Kindred Spirits
+ [57514] = 12, -- Enrage (Rank 1)
+ [57516] = 12, -- Enrage (Rank 2)
+ [57519] = 12, -- Enrage
+ [57522] = 12, -- Enrage (Rank 5)
+ [57524] = 120, -- Metanoia
+ [57529] = 0, -- Arcane Potency
+ [57531] = 0, -- Arcane Potency
+ [57564] = 0, -- Fel Intelligence (Rank 2)
+ [57565] = 0, -- Fel Intelligence (Rank 3)
+ [57566] = 0, -- Fel Intelligence (Rank 4)
+ [57567] = 0, -- Fel Intelligence (Rank 5)
+ [57580] = 5, -- Lightning Infusion
+ [57621] = 0, -- Strength of Earth (Rank 7)
+ [57623] = 120, -- Horn of Winter (Rank 2)
+ [57660] = 0, -- Totem of Wrath
+ [57662] = 0, -- Totem of Wrath
+ [57663] = 0, -- Totem of Wrath
+ [57669] = 15, -- Replenishment
+ [57723] = 600, -- Exhaustion
+ [57724] = 600, -- Sated
+ [57761] = 15, -- Fireball!
+ [57819] = 0, -- Argent Champion
+ [57820] = 0, -- Ebon Champion
+ [57821] = 0, -- Champion of the Kirin Tor
+ [57822] = 0, -- Wyrmrest Champion
+ [57833] = 4, -- Frost Spit
+ [57933] = 6, -- Tricks of the Trade
+ [57934] = 30, -- Tricks of the Trade
+ [57940] = 0, -- Essence of Wintergrasp
+ [57960] = 600, -- Water Shield (Rank 9)
+ [57969] = 12, -- Deadly Poison VIII (Rank 8)
+ [57970] = 12, -- Deadly Poison IX (Rank 9)
+ [57974] = 10, -- Wound Poison VI (Rank 6)
+ [57975] = 15, -- Wound Poison VII (Rank 7)
+ [57993] = 6, -- Envenom (Rank 4)
+ [58045] = 0, -- Essence of Wintergrasp
+ [58179] = 12, -- Infected Wounds
+ [58180] = 12, -- Infected Wounds
+ [58181] = 12, -- Infected Wounds
+ [58269] = 0, -- Iceskin Stoneform
+ [58363] = 10, -- Glyph of Revenge
+ [58371] = 180, -- Recently Slain
+ [58374] = 10, -- Glyph of Blocking
+ [58427] = 20, -- Overkill
+ [58448] = 1800, -- Strength (Rank 7)
+ [58449] = 1800, -- Strength (Rank 8)
+ [58450] = 1800, -- Agility (Rank 7)
+ [58451] = 1800, -- Agility (Rank 8)
+ [58452] = 1800, -- Armor (Rank 7)
+ [58468] = 3600, -- Hugely Well Fed
+ [58479] = 3600, -- Nearly Well Fed
+ [58493] = 3600, -- Mohawked!
+ [58496] = 7200, -- Sad
+ [58499] = 7200, -- Happy
+ [58500] = 7200, -- Angry
+ [58501] = 600, -- Iron Boot Flask
+ [58502] = 7200, -- Scared
+ [58511] = 45, -- Rotten Apple Aroma
+ [58514] = 45, -- Rotten Banana Aroma
+ [58519] = 45, -- Spit
+ [58549] = 0, -- Tenacity
+ [58555] = 0, -- Great Honor
+ [58556] = 0, -- Greater Honor
+ [58557] = 0, -- Greatest Honor
+ [58567] = 30, -- Sunder Armor (Rank 1)
+ [58578] = 20, -- Icy Talons
+ [58591] = 15, -- Stoneclaw Totem
+ [58597] = 6, -- Sacred Shield (Rank 1)
+ [58600] = 10, -- Restricted Flight Area
+ [58610] = 10, -- Lava Breath (Rank 5)
+ [58611] = 10, -- Lava Breath (Rank 6)
+ [58617] = 10, -- Glyph of Heart Strike
+ [58646] = 0, -- Strength of Earth (Rank 8)
+ [58651] = 0, -- Flametongue Totem (Rank 6)
+ [58655] = 0, -- Flametongue Totem (Rank 8)
+ [58683] = 0, -- Savage Combat (Rank 2)
+ [58729] = 0, -- Spiritual Immunity
+ [58730] = 9, -- Restricted Flight Area
+ [58740] = 0, -- Fire Resistance (Rank 6)
+ [58744] = 0, -- Frost Resistance (Rank 6)
+ [58750] = 0, -- Nature Resistance (Rank 6)
+ [58752] = 0, -- Stoneskin (Rank 9)
+ [58754] = 0, -- Stoneskin (Rank 10)
+ [58775] = 0, -- Mana Spring (Rank 6)
+ [58776] = 0, -- Mana Spring (Rank 7)
+ [58777] = 0, -- Mana Spring (Rank 8)
+ [58799] = 8, -- Frostbrand Attack (Rank 9)
+ [58861] = 2, -- Bash (Rank 1)
+ [58875] = 15, -- Spirit Walk
+ [58882] = 6, -- Rapid Recuperation
+ [58891] = 45, -- Wild Magic
+ [58914] = 30, -- Kill Command (Rank 1)
+ [58984] = 0, -- Shadowmeld (Racial)
+ [58999] = 0, -- Big Blizzard Bear
+ [59000] = 8, -- Improved Spirit Tap (Rank 2)
+ [59052] = 0, -- Freezing Fog
+ [59125] = 120, -- Lucky
+ [59164] = 12, -- Haunt (Rank 4)
+ [59230] = 3600, -- Well Fed
+ [59542] = 15, -- Gift of the Naaru (Racial)
+ [59547] = 15, -- Gift of the Naaru (Racial)
+ [59548] = 15, -- Gift of the Naaru (Racial)
+ [59568] = 0, -- Blue Drake
+ [59569] = 0, -- Bronze Drake
+ [59570] = 0, -- Red Drake
+ [59578] = 15, -- The Art of War (Rank 2)
+ [59620] = 15, -- Berserk
+ [59626] = 10, -- Black Magic
+ [59628] = 6, -- Tricks of the Trade
+ [59638] = 4, -- Frostbolt
+ [59650] = 0, -- Black Drake
+ [59658] = 15, -- Argent Heroism
+ [59671] = 6, -- Challenging Howl (Demon)
+ [59674] = 1800, -- Moonshroud Residue
+ [59675] = 1800, -- Nexus Residue
+ [59676] = 1800, -- Residue of Darkness
+ [59725] = 5, -- Spell Reflection
+ [59752] = 0, -- Every Man for Himself (Racial)
+ [59785] = 0, -- Black War Mammoth
+ [59788] = 0, -- Black War Mammoth
+ [59793] = 0, -- Wooly Mammoth
+ [59797] = 0, -- Ice Mammoth
+ [59843] = 600, -- Underbelly Elixir
+ [59882] = 9, -- Rake (Rank 2)
+ [59883] = 9, -- Rake (Rank 3)
+ [59884] = 9, -- Rake (Rank 4)
+ [59885] = 9, -- Rake (Rank 5)
+ [59886] = 9, -- Rake (Rank 6)
+ [59888] = 6, -- Borrowed Time
+ [59889] = 6, -- Borrowed Time
+ [59891] = 6, -- Borrowed Time
+ [59911] = 0, -- Tenacity
+ [59961] = 0, -- Red Proto-Drake
+ [59996] = 0, -- Blue Proto-Drake
+ [60002] = 0, -- Time-Lost Proto-Drake
+ [60024] = 0, -- Violet Proto-Drake
+ [60025] = 0, -- Albino Drake
+ [60053] = 2, -- Explosive Shot (Rank 4)
+ [60062] = 10, -- Essence of Life
+ [60064] = 10, -- Now is the time!
+ [60065] = 10, -- Reflection of Torment
+ [60097] = 10, -- Feeding Frenzy (Rank 2)
+ [60106] = 300, -- Old Spices
+ [60114] = 0, -- Armored Brown Bear
+ [60116] = 0, -- Armored Brown Bear
+ [60118] = 0, -- Black War Bear
+ [60119] = 0, -- Black War Bear
+ [60122] = 30, -- Baby Spice
+ [60196] = 12, -- Berserker!
+ [60210] = 10, -- Freezing Arrow Effect (Rank 1) (PvP duration)
+ [60214] = 0, -- Seal of the Pantheon
+ [60215] = 0, -- Lavanthor's Talisman
+ [60218] = 0, -- Essence of Gossamer
+ [60229] = 15, -- Greatness
+ [60233] = 15, -- Greatness
+ [60234] = 15, -- Greatness
+ [60299] = 20, -- Incisor Fragment
+ [60302] = 10, -- Meteorite Whetstone
+ [60305] = 20, -- Heart of a Dragon
+ [60314] = 10, -- Fury of the Five Flights
+ [60318] = 13, -- Edward's Insight
+ [60340] = 3600, -- Accuracy
+ [60341] = 3600, -- Deadly Strikes
+ [60343] = 3600, -- Mighty Defense
+ [60344] = 3600, -- Expertise
+ [60345] = 3600, -- Armor Piercing
+ [60346] = 3600, -- Lightning Speed
+ [60347] = 3600, -- Mighty Thoughts
+ [60424] = 0, -- Mekgineer's Chopper
+ [60433] = 12, -- Earth and Moon
+ [60437] = 10, -- Grim Toll
+ [60479] = 10, -- Forge Ember
+ [60486] = 10, -- Illustration of the Dragon Soul
+ [60494] = 10, -- Dying Curse
+ [60503] = 9, -- Taste for Blood
+ [60512] = 15, -- Healing Trance
+ [60517] = 20, -- Talisman of Troll Divinity
+ [60518] = 10, -- Touched by a Troll
+ [60520] = 15, -- Spark of Life
+ [60525] = 10, -- Majestic Dragon Figurine
+ [60530] = 12, -- Forethought Talisman
+ [60549] = 10, -- Deadly Aggression
+ [60551] = 10, -- Furious Gladiator's Libram of Fortitude
+ [60553] = 10, -- Relentless Aggression
+ [60568] = 10, -- Furious Gladiator's Idol of Steadfastness
+ [60569] = 10, -- Relentless Survival
+ [60819] = 10, -- Libram of Reciprocation
+ [60946] = 4, -- Nightmare
+ [60947] = 5, -- Nightmare
+ [60956] = 0, -- Improved Health Funnel
+ [60970] = 0.1, -- Heroic Fury
+ [61024] = 1800, -- Dalaran Intellect (Rank 7)
+ [61044] = 15, -- Demoralizing Shout
+ [61198] = 6, -- Spirit Strike (Rank 6)
+ [61258] = 5, -- Runic Return (Rank 2)
+ [61291] = 8, -- Shadowflame
+ [61294] = 0, -- Green Proto-Drake
+ [61295] = 15, -- Riptide
+ [61299] = 15, -- Riptide (Rank 2)
+ [61301] = 15, -- Riptide (Rank 4)
+ [61305] = 50, -- Polymorph (cat)
+ [61309] = 0, -- Magnificent Flying Carpet
+ [61316] = 3600, -- Dalaran Brilliance (Rank 3)
+ [61336] = 20, -- Survival Instincts
+ [61391] = 6, -- Typhoon
+ [61394] = 4, -- Glyph of Freezing Trap
+ [61425] = 0, -- Traveler's Tundra Mammoth
+ [61427] = 20, -- Infinite Speed
+ [61447] = 0, -- Traveler's Tundra Mammoth
+ [61451] = 0, -- Flying Carpet
+ [61465] = 0, -- Grand Black War Mammoth
+ [61467] = 0, -- Grand Black War Mammoth
+ [61469] = 0, -- Grand Ice Mammoth
+ [61470] = 0, -- Grand Ice Mammoth
+ [61485] = 60, -- Dreadful Roar
+ [61573] = 0, -- Banner of the Alliance
+ [61619] = 10, -- Tentacles
+ [61669] = 0, -- Aspect of the Beast
+ [61671] = 10, -- Crusader's Glory
+ [61684] = 16, -- Dash
+ [61685] = 4, -- Charge
+ [61721] = 50, -- Polymorph (Rabbit)
+ [61792] = 10, -- Shadowy Insight
+ [61840] = 8, -- Righteous Vengeance
+ [61846] = 0, -- Aspect of the Dragonhawk (Rank 1)
+ [61847] = 0, -- Aspect of the Dragonhawk (Rank 2)
+ [61858] = 0, -- Plague Slime
+ [61882] = 8, -- Earthquake
+ [62061] = 3600, -- Festive Holiday Mount
+ [62064] = 0, -- Tower Control
+ [62124] = 3, -- Hand of Reckoning
+ [62146] = 30, -- Unflinching Valor
+ [62305] = 4, -- Master's Call
+ [62380] = 7200, -- Lesser Flask of Resistance
+ [62408] = 300, -- Ethereal Oil
+ [62552] = 0, -- Defend
+ [62574] = 0, -- Warts-B-Gone Lip Balm
+ [62606] = 10, -- Savage Defense
+ [63058] = 20, -- Glyph of Amberskin Protection
+ [63087] = 5, -- Raptor Strike
+ [63167] = 10, -- Decimation
+ [63232] = 0, -- Stormwind Steed
+ [63243] = 10, -- Pyroclasm
+ [63244] = 10, -- Pyroclasm
+ [63250] = 10, -- Jouster's Fury
+ [63283] = 300, -- Totem of Wrath
+ [63311] = 8, -- Glyph of Shadowflame
+ [63321] = 40, -- Life Tap
+ [63433] = 0, -- Orgrimmar Champion's Pennant
+ [63438] = 0, -- Silvermoon Champion's Pennant
+ [63468] = 8, -- Piercing Shots
+ [63500] = 0, -- Argent Crusade Valiant's Pennant
+ [63529] = 3, -- Silenced - Shield of the Templar
+ [63560] = 30, -- Dark Transformation
+ [63619] = 5, -- Shadowcrawl
+ [63635] = 0, -- Darkspear Raptor
+ [63637] = 0, -- Darnassian Nightsaber
+ [63640] = 0, -- Orgrimmar Wolf
+ [63641] = 0, -- Thunder Bluff Kodo
+ [63643] = 0, -- Forsaken Warhorse
+ [63665] = 0, -- Charge
+ [63668] = 15, -- Black Arrow (Rank 2)
+ [63672] = 15, -- Black Arrow (Rank 6)
+ [63685] = 5, -- Freeze
+ [63725] = 8, -- Holy Concentration
+ [63729] = 3600, -- Elixir of Minor Accuracy
+ [63734] = 20, -- Serendipity
+ [63735] = 20, -- Serendipity
+ [63844] = 0, -- Argent Hippogryph
+ [63848] = 60, -- Hunger For Blood
+ [63896] = 12, -- Bullheaded
+ [63944] = 60, -- Renewed Hope
+ [63956] = 0, -- Ironbound Proto-Drake
+ [63963] = 0, -- Rusted Proto-Drake
+ [64044] = 3, -- Psychic Horror
+ [64057] = 3600, -- Well Fed
+ [64058] = 10, -- Psychic Horror
+ [64128] = 4, -- Body and Soul
+ [64205] = 10, -- Divine Sacrifice
+ [64343] = 10, -- Impact (Rank 1)
+ [64368] = 10, -- Eradication
+ [64370] = 10, -- Eradication
+ [64371] = 10, -- Eradication
+ [64373] = 0, -- Armistice
+ [64382] = 10, -- Shattering Throw
+ [64419] = 15, -- Sniper Training (Rank 3)
+ [64420] = 15, -- Sniper Training (Rank 3)
+ [64440] = 10, -- Blade Warding
+ [64491] = 20, -- Furious Howl (Rank 2)
+ [64492] = 20, -- Furious Howl (Rank 3)
+ [64493] = 20, -- Furious Howl (Rank 4)
+ [64494] = 0, -- Furious Howl (Rank 5)
+ [64495] = 20, -- Furious Howl (Rank 6)
+ [64524] = 20, -- Platinum Disks of Battle
+ [64568] = 20, -- Blood Reserve
+ [64657] = 0, -- White Kodo
+ [64658] = 0, -- Black Wolf
+ [64659] = 0, -- Venomhide Ravasaur
+ [64695] = 5, -- Earthgrab
+ [64701] = 15, -- Elemental Mastery
+ [64731] = 0, -- Sea Turtle
+ [64803] = 4, -- Entrapment
+ [64804] = 4, -- Entrapment
+ [64810] = 0, -- Bested Ironforge
+ [64843] = 5, -- Divine Hymn (Rank 1)
+ [64844] = 8, -- Divine Hymn
+ [64850] = 6, -- Unrelenting Assault
+ [64855] = 10, -- Blade Barrier (Rank 2)
+ [64856] = 10, -- Blade Barrier (Rank 3)
+ [64859] = 10, -- Blade Barrier (Rank 5)
+ [64861] = 15, -- Precision Shots
+ [64901] = 8, -- Hymn of Hope
+ [64904] = 8, -- Hymn of Hope
+ [64937] = 5, -- Heightened Reflexes
+ [64951] = 12, -- Primal Wrath (Rank 5)
+ [64977] = 0, -- Black Skeletal Horse
+ [65006] = 10, -- Eye of the Broodmother
+ [65014] = 10, -- Pyrite Infusion
+ [65019] = 10, -- Mjolnir Runestone
+ [65081] = 4, -- Body and Soul
+ [65142] = 21, -- Ebon Plague
+ [65156] = 10, -- Juggernaut
+ [65247] = 3514, -- Well Fed
+ [65264] = 6, -- Lava Flows
+ [65637] = 0, -- Great Red Elekk
+ [65638] = 0, -- Swift Moonsaber
+ [65639] = 0, -- Swift Red Hawkstrider
+ [65640] = 0, -- Swift Gray Steed
+ [65641] = 0, -- Great Golden Kodo
+ [65642] = 0, -- Turbostrider
+ [65644] = 0, -- Swift Purple Raptor
+ [65645] = 0, -- White Skeletal Warhorse
+ [65646] = 0, -- Swift Burgundy Wolf
+ [65745] = 300, -- Path of Cenarius
+ [65780] = 300, -- Pink Gumball
+ [66088] = 0, -- Sunreaver Dragonhawk
+ [66090] = 0, -- Quel'dorei Steed
+ [66091] = 0, -- Sunreaver Hawkstrider
+ [66122] = 0, -- Magic Rooster
+ [66157] = 0, -- Honorable Defender
+ [66233] = 120, -- Ardent Defender
+ [66251] = 8, -- Launch
+ [66550] = 20, -- Teleport
+ [66684] = 0, -- Flaming Cinder
+ [66721] = 0, -- Burning Fury
+ [66725] = 15, -- Meteor Fists
+ [66776] = 0, -- Rage
+ [66803] = 20, -- Desolation
+ [66808] = 15, -- Meteor Fists
+ [66846] = 0, -- Ochre Skeletal Warhorse
+ [66906] = 0, -- Argent Charger (Summon)
+ [66922] = 12, -- Flash of Light
+ [67016] = 3600, -- Flask of the North
+ [67017] = 3600, -- Flask of the North
+ [67018] = 3600, -- Flask of the North
+ [67117] = 15, -- Unholy Might
+ [67332] = 0, -- Flaming Cinder
+ [67354] = 9, -- Evasion (Rank 5)
+ [67355] = 16, -- Agile
+ [67358] = 9, -- Rejuvenating
+ [67360] = 12, -- Blessing of the Moon Goddess
+ [67364] = 15, -- Holy Judgement
+ [67371] = 16, -- Holy Strength
+ [67378] = 18, -- Evasion (Rank 1)
+ [67380] = 20, -- Evasion (Rank 1)
+ [67383] = 20, -- Unholy Force (Rank 1)
+ [67385] = 12, -- Energized
+ [67388] = 15, -- Spiritual Trance
+ [67391] = 18, -- Volcanic Fury
+ [67466] = 0, -- Argent Warhorse
+ [67596] = 15, -- Tremendous Fortitude
+ [67631] = 10, -- Aegis
+ [67669] = 10, -- Elusive Power
+ [67671] = 10, -- Fury
+ [67683] = 20, -- Celerity
+ [67684] = 20, -- Hospitality
+ [67694] = 20, -- Defensive Tactics
+ [67695] = 20, -- Rage
+ [67696] = 10, -- Energized
+ [67703] = 15, -- Paragon
+ [67708] = 15, -- Paragon
+ [67713] = 0, -- Mote of Flame
+ [67735] = 0, -- Volatility
+ [67736] = 20, -- Volatile Power
+ [67737] = 0, -- Risen Fury
+ [67738] = 20, -- Rising Fury
+ [67811] = 12, -- Dagger Throw
+ [67890] = 3, -- Cobalt Frag Bomb
+ [68054] = 600, -- Pressing Engagement
+ [68055] = 20, -- Judgements of the Just (Rank 1)
+ [68056] = 0, -- Swift Horde Wolf
+ [68057] = 0, -- Swift Alliance Steed
+ [68160] = 15, -- Meteor Fists
+ [68161] = 15, -- Meteor Fists
+ [68188] = 0, -- Crusader's Black Warhorse
+ [68269] = 0, -- The Brewmaiden's Blessing (Rank 6)
+ [68298] = 5, -- Parachute
+ [68377] = 0, -- Carrying Huge Seaforium
+ [68652] = 0, -- Honorable Defender
+ [68719] = 0, -- Oil Refinery
+ [68720] = 0, -- Quarry
+ [68722] = 0, -- Oil Refinery
+ [68766] = 0, -- Desecration
+ [69180] = 30, -- Gutgore Ripper
+ [69369] = 8, -- Predator's Swiftness
+ [70013] = 0, -- Quel'Delar's Compulsion
+ [70029] = 0, -- The Beast Within
+ [70244] = 3600, -- \"Wizardry\" Cologne
+ [70639] = 8, -- Call of Sylvanas
+ [70657] = 15, -- Advantage (Rank 5)
+ [70691] = 15, -- Rejuvenation
+ [70721] = 6, -- Omen of Doom
+ [70725] = 10, -- Enraged Defense
+ [70728] = 10, -- Exploit Weakness
+ [70747] = 30, -- Quad Core
+ [70753] = 5, -- Pushing the Limit
+ [70757] = 10, -- Holiness (Rank 5)
+ [70760] = 10, -- Deliverance
+ [70772] = 9, -- Blessed Healing
+ [70806] = 10, -- Rapid Currents
+ [70840] = 10, -- Devious Minds
+ [70845] = 10, -- Stoicism
+ [70855] = 10, -- Blood Drinker
+ [70893] = 10, -- Culling the Herd
+ [70940] = 6, -- Divine Guardian
+ [71007] = 10, -- Stinger
+ [71041] = 1800, -- Dungeon Deserter
+ [71165] = 15, -- Molten Core
+ [71175] = 15, -- Agile
+ [71177] = 15, -- Vicious
+ [71184] = 15, -- Soothing
+ [71187] = 15, -- Formidable
+ [71192] = 15, -- Blessed
+ [71197] = 15, -- Evasive
+ [71199] = 30, -- Furious
+ [71216] = 15, -- Enraged
+ [71220] = 15, -- Energized
+ [71227] = 15, -- Indomitable
+ [71345] = 0, -- Big Love Rocket
+ [71396] = 10, -- Rage of the Fallen
+ [71401] = 15, -- Icy Rage
+ [71403] = 10, -- Fatal Flaws
+ [71432] = 0, -- Mote of Anger
+ [71484] = 30, -- Strength of the Taunka
+ [71485] = 30, -- Agility of the Vrykul
+ [71486] = 30, -- Power of the Taunka
+ [71491] = 30, -- Aim of the Iron Dwarves
+ [71492] = 30, -- Speed of the Vrykul
+ [71560] = 30, -- Speed of the Vrykul
+ [71564] = 20, -- Deadly Precision
+ [71568] = 20, -- Urgency
+ [71570] = 10, -- Cultivated Power
+ [71572] = 10, -- Cultivated Power
+ [71579] = 20, -- Elusive Power
+ [71584] = 15, -- Revitalized
+ [71586] = 10, -- Hardened Skin
+ [71600] = 0, -- Surging Power
+ [71601] = 20, -- Surge of Power
+ [71633] = 10, -- Thick Skin
+ [71824] = 6, -- Lava Burst
+ [71864] = 0, -- Fountain of Light
+ [71866] = 6, -- Fountain of Light
+ [71870] = 10, -- Blessing of Light
+ [71875] = 10, -- Necrotic Touch
+ [71877] = 10, -- Necrotic Touch
+ [71882] = 10, -- Invigoration
+ [71993] = 0, -- Frozen Mallet
+ [72004] = 20, -- Frostbite
+ [72034] = 0, -- Whiteout
+ [72081] = 0, -- Frozen Orb
+ [72096] = 0, -- Whiteout
+ [72098] = 20, -- Frostbite
+ [72104] = 5, -- Freezing Ground
+ [72121] = 10, -- Frostbite
+ [72122] = 0, -- Frozen Mallet
+ [72221] = 0, -- Luck of the Draw
+ [72282] = 0, -- Invincible
+ [72412] = 10, -- Frostforged Champion
+ [72414] = 10, -- Frostforged Defender
+ [72416] = 10, -- Frostforged Sage
+ [72418] = 10, -- Chilling Knowledge
+ [72586] = 1800, -- Blessing of Forgotten Kings
+ [72588] = 3600, -- Gift of the Wild
+ [72590] = 3600, -- Fortitude
+ [72808] = 0, -- Bloodbathed Frostbrood Vanquisher
+ [72968] = 0, -- Precious's Ribbon
+ [73313] = 0, -- Crimson Deathcharger (Summon)
+ [73320] = 600, -- Frostborn Illusion
+ [73413] = 1800, -- Inner Will
+ [73651] = 0, -- Recuperate
+ [73681] = 12, -- Unleash Wind
+ [73682] = 5, -- Unleash Frost
+ [73683] = 8, -- Unleash Flame
+ [73685] = 8, -- Unleash Life
+ [73975] = 15, -- Necrotic Strike
+ [74001] = 30, -- Combat Readiness
+ [74002] = 6, -- Combat Insight
+ [74347] = 3, -- Silenced - Gag Order
+ [74396] = 15, -- Fingers of Frost
+ [74434] = 15, -- Soulburn
+ [74855] = 0, -- Blazing Hippogryph
+ [74960] = 10, -- Infrigidate
+ [75446] = 0, -- Ferocious Inspiration
+ [75447] = 0, -- Ferocious Inspiration
+ [75458] = 15, -- Piercing Twilight
+ [75593] = 0, -- Ferocious Inspiration
+ [75596] = 0, -- Frosty Flying Carpet
+ [75617] = 0, -- Celestial Steed
+ [75618] = 0, -- Celestial Steed
+ [75619] = 0, -- Celestial Steed
+ [75620] = 0, -- Celestial Steed
+ [75731] = 0, -- Instant Statue
+ [75957] = 0, -- X-53 Touring Rocket
+ [75972] = 0, -- X-53 Touring Rocket
+}
+
+lib.spellDebuffType = {
+ [17] = 1, -- Power Word: Shield
+ [66] = 6, -- Invisibility
+ [67] = 1, -- Vindication (Rank 1)
+ [113] = 1, -- Chains of Ice (Rank 1)
+ [116] = 1, -- Frostbolt (Rank 1)
+ [118] = 1, -- Polymorph (Rank 1)
+ [120] = 1, -- Cone of Cold (Rank 1)
+ [122] = 1, -- Frost Nova (Rank 1)
+ [130] = 1, -- Slow Fall
+ [132] = 1, -- Detect Invisibility
+ [136] = 1, -- Mend Pet
+ [139] = 1, -- Renew (Rank 1)
+ [172] = 1, -- Corruption (Rank 1)
+ [324] = 1, -- Lightning Shield (Rank 1)
+ [325] = 1, -- Lightning Shield (Rank 2)
+ [339] = 1, -- Entangling Roots (Rank 1)
+ [348] = 1, -- Immolate (Rank 1)
+ [467] = 1, -- Thorns (Rank 1)
+ [498] = 1, -- Divine Protection
+ [543] = 1, -- Fire Ward (Rank 1)
+ [552] = 1, -- Abolish Disease
+ [589] = 1, -- Shadow Word: Pain (Rank 1)
+ [592] = 1, -- Power Word: Shield (Rank 2)
+ [594] = 1, -- Shadow Word: Pain (Rank 2)
+ [600] = 1, -- Power Word: Shield (Rank 3)
+ [603] = 4, -- Bane of Doom
+ [604] = 1, -- Dampen Magic (Rank 1)
+ [605] = 1, -- Mind Control
+ [642] = 1, -- Divine Shield
+ [689] = 1, -- Drain Life (Rank 1)
+ [699] = 1, -- Drain Life (Rank 2)
+ [700] = 1, -- Sleep (Rank 1)
+ [702] = 4, -- Curse of Weakness (Rank 1)
+ [707] = 1, -- Immolate (Rank 2)
+ [709] = 1, -- Drain Life (Rank 3)
+ [710] = 1, -- Banish (Rank 1)
+ [744] = 3, -- Poison
+ [770] = 1, -- Faerie Fire
+ [774] = 1, -- Rejuvenation (Rank 1)
+ [782] = 1, -- Thorns (Rank 2)
+ [837] = 1, -- Frostbolt (Rank 3)
+ [853] = 1, -- Hammer of Justice (Rank 1)
+ [865] = 1, -- Frost Nova (Rank 2)
+ [905] = 1, -- Lightning Shield (Rank 3)
+ [945] = 1, -- Lightning Shield (Rank 4)
+ [970] = 1, -- Shadow Word: Pain (Rank 3)
+ [974] = 1, -- Earth Shield
+ [976] = 1, -- Shadow Protection (Rank 1)
+ [980] = 4, -- Curse of Agony (Rank 1)
+ [992] = 1, -- Shadow Word: Pain (Rank 4)
+ [1008] = 1, -- Amplify Magic (Rank 1)
+ [1014] = 4, -- Curse of Agony (Rank 2)
+ [1022] = 1, -- Hand of Protection
+ [1038] = 1, -- Hand of Salvation
+ [1044] = 1, -- Hand of Freedom
+ [1062] = 1, -- Entangling Roots (Rank 2)
+ [1075] = 1, -- Thorns (Rank 3)
+ [1094] = 1, -- Immolate (Rank 3)
+ [1108] = 4, -- Curse of Weakness (Rank 2)
+ [1126] = 1, -- Mark of the Wild (Rank 1)
+ [1130] = 1, -- Hunter's Mark (Rank 1)
+ [1243] = 1, -- Power Word: Fortitude (Rank 1)
+ [1244] = 1, -- Power Word: Fortitude (Rank 2)
+ [1245] = 1, -- Power Word: Fortitude (Rank 3)
+ [1430] = 1, -- Rejuvenation (Rank 3)
+ [1459] = 1, -- Arcane Intellect (Rank 1)
+ [1460] = 1, -- Arcane Intellect (Rank 2)
+ [1461] = 1, -- Arcane Intellect (Rank 3)
+ [1463] = 1, -- Mana Shield (Rank 1)
+ [1490] = 4, -- Curse of the Elements (Rank 1)
+ [1513] = 1, -- Scare Beast (Rank 1)
+ [1706] = 1, -- Levitate
+ [1714] = 4, -- Curse of Tongues
+ [1978] = 3, -- Serpent Sting
+ [2090] = 1, -- Rejuvenation (Rank 4)
+ [2091] = 1, -- Rejuvenation (Rank 5)
+ [2601] = 1, -- Fire Shield III
+ [2602] = 1, -- Fire Shield IV
+ [2645] = 1, -- Ghost Wolf
+ [2767] = 1, -- Shadow Word: Pain (Rank 5)
+ [2791] = 1, -- Power Word: Fortitude (Rank 4)
+ [2812] = 1, -- Holy Wrath
+ [2818] = 3, -- Deadly Poison (Rank 1)
+ [2819] = 3, -- Deadly Poison II (Rank 2)
+ [2825] = 1, -- Bloodlust
+ [2893] = 1, -- Abolish Poison
+ [2941] = 1, -- Immolate (Rank 4)
+ [2944] = 2, -- Devouring Plague (Rank 1)
+ [2947] = 1, -- Fire Shield (Rank 1)
+ [3034] = 3, -- Viper Sting
+ [3043] = 3, -- Scorpid Sting
+ [3256] = 2, -- Plague Cloud
+ [3355] = 1, -- Freezing Trap Effect (Rank 1)
+ [3356] = 1, -- Flame Lash
+ [3409] = 3, -- Crippling Poison
+ [3427] = 2, -- Infected Wound
+ [3436] = 2, -- Wandering Plague
+ [3439] = 2, -- Wandering Plague
+ [3583] = 3, -- Deadly Poison
+ [3600] = 1, -- Earthbind
+ [3627] = 1, -- Rejuvenation (Rank 6)
+ [3661] = 1, -- Mend Pet (Rank 3)
+ [3662] = 1, -- Mend Pet (Rank 4)
+ [3674] = 1, -- Black Arrow
+ [3747] = 1, -- Power Word: Shield (Rank 4)
+ [3815] = 3, -- Poison Cloud
+ [4167] = 1, -- Web (Rank 1)
+ [4318] = 1, -- Guile of the Raptor
+ [5115] = 1, -- Battle Command
+ [5137] = 4, -- Call of the Grave
+ [5138] = 1, -- Drain Mana
+ [5195] = 1, -- Entangling Roots (Rank 3)
+ [5196] = 1, -- Entangling Roots (Rank 4)
+ [5232] = 1, -- Mark of the Wild (Rank 2)
+ [5234] = 1, -- Mark of the Wild (Rank 4)
+ [5262] = 1, -- Fanatic Blade
+ [5403] = 1, -- Crash of Waves
+ [5413] = 2, -- Noxious Catalyst
+ [5484] = 1, -- Howl of Terror (Rank 1)
+ [5570] = 1, -- Insect Swarm
+ [5588] = 1, -- Hammer of Justice (Rank 2)
+ [5589] = 1, -- Hammer of Justice (Rank 3)
+ [5599] = 1, -- Hand of Protection (Rank 2)
+ [5760] = 3, -- Mind-numbing Poison
+ [5782] = 1, -- Fear (Rank 1)
+ [6065] = 1, -- Power Word: Shield (Rank 5)
+ [6066] = 1, -- Power Word: Shield (Rank 6)
+ [6074] = 1, -- Renew (Rank 2)
+ [6075] = 1, -- Renew (Rank 3)
+ [6076] = 1, -- Renew (Rank 4)
+ [6077] = 1, -- Renew (Rank 5)
+ [6078] = 1, -- Renew (Rank 6)
+ [6131] = 1, -- Frost Nova (Rank 3)
+ [6136] = 1, -- Chilled (Rank 1)
+ [6143] = 1, -- Frost Ward (Rank 1)
+ [6146] = 1, -- Slow (Rank 2)
+ [6205] = 4, -- Curse of Weakness (Rank 3)
+ [6213] = 1, -- Fear (Rank 2)
+ [6215] = 1, -- Fear (Rank 3)
+ [6217] = 4, -- Curse of Agony (Rank 3)
+ [6222] = 1, -- Corruption (Rank 2)
+ [6223] = 1, -- Corruption (Rank 3)
+ [6229] = 1, -- Shadow Ward
+ [6278] = 2, -- Creeping Mold
+ [6306] = 3, -- Acid Splash
+ [6346] = 1, -- Fear Ward
+ [6358] = 1, -- Seduction
+ [6726] = 1, -- Silence
+ [6728] = 1, -- Enveloping Winds (Rank 1)
+ [6742] = 1, -- Bloodlust
+ [6756] = 1, -- Mark of the Wild (Rank 3)
+ [6789] = 1, -- Death Coil (Rank 1)
+ [6940] = 1, -- Hand of Sacrifice
+ [6950] = 1, -- Faerie Fire
+ [7038] = 4, -- Forsaken Skill: Swords
+ [7039] = 4, -- Forsaken Skill: Axes
+ [7040] = 4, -- Forsaken Skill: Daggers
+ [7041] = 4, -- Forsaken Skill: Maces
+ [7042] = 4, -- Forsaken Skill: Staves
+ [7044] = 4, -- Forsaken Skill: Guns
+ [7045] = 4, -- Forsaken Skill: 2H Axes
+ [7046] = 4, -- Forsaken Skill: 2H Maces
+ [7047] = 4, -- Forsaken Skill: 2H Swords
+ [7049] = 4, -- Forsaken Skill: Fire
+ [7051] = 4, -- Forsaken Skill: Holy
+ [7053] = 4, -- Forsaken Skill: Shadow
+ [7054] = 4, -- Forsaken Skills
+ [7057] = 4, -- Haunting Spirits
+ [7068] = 4, -- Veil of Shadow
+ [7074] = 1, -- Screams of the Past
+ [7124] = 4, -- Arugal's Gift
+ [7125] = 3, -- Toxic Saliva
+ [7127] = 1, -- Wavering Will
+ [7140] = 1, -- Expose Weakness
+ [7295] = 1, -- Soul Drain
+ [7321] = 1, -- Chilled (Rank 1)
+ [7322] = 1, -- Frostbolt (Rank 4)
+ [7399] = 1, -- Terrify
+ [7621] = 4, -- Arugal's Curse
+ [7648] = 1, -- Corruption (Rank 4)
+ [7651] = 1, -- Drain Life (Rank 4)
+ [7739] = 1, -- Inferno Shell
+ [7812] = 1, -- Sacrifice (Rank 1)
+ [7947] = 3, -- Localized Toxin
+ [7948] = 1, -- Wild Regeneration
+ [7964] = 1, -- Smoke Bomb
+ [7992] = 3, -- Slowing Poison
+ [8040] = 1, -- Druid's Slumber
+ [8050] = 1, -- Flame Shock (Rank 1)
+ [8052] = 1, -- Flame Shock (Rank 2)
+ [8053] = 1, -- Flame Shock (Rank 3)
+ [8056] = 1, -- Frost Shock (Rank 1)
+ [8058] = 1, -- Frost Shock (Rank 2)
+ [8066] = 4, -- Shrink
+ [8068] = 1, -- Healthy Spirit
+ [8078] = 1, -- Thunderclap
+ [8096] = 1, -- Intellect (Rank 1)
+ [8101] = 1, -- Stamina (Level 3)
+ [8112] = 1, -- Spirit (Rank 1)
+ [8117] = 1, -- Agility (Rank 3)
+ [8119] = 1, -- Strength (Rank 2)
+ [8122] = 1, -- Psychic Scream
+ [8134] = 1, -- Lightning Shield (Rank 5)
+ [8140] = 1, -- Befuddlement (Rank 1)
+ [8202] = 1, -- Sapta Sight
+ [8267] = 4, -- Cursed Blood
+ [8272] = 1, -- Mind Tremor
+ [8275] = 3, -- Poisoned Shot
+ [8281] = 1, -- Sonic Burst
+ [8282] = 4, -- Curse of Blood
+ [8314] = 1, -- Rock Skin
+ [8316] = 1, -- Fire Shield (Rank 2)
+ [8317] = 1, -- Fire Shield (Rank 3)
+ [8362] = 1, -- Renew
+ [8365] = 1, -- Enlarge
+ [8382] = 3, -- Leech Poison
+ [8385] = 1, -- Swift Wind
+ [8398] = 1, -- Frostbolt Volley
+ [8399] = 1, -- Sleep
+ [8406] = 1, -- Frostbolt (Rank 5)
+ [8407] = 1, -- Frostbolt (Rank 6)
+ [8408] = 1, -- Frostbolt (Rank 7)
+ [8450] = 1, -- Dampen Magic (Rank 2)
+ [8451] = 1, -- Dampen Magic (Rank 3)
+ [8455] = 1, -- Amplify Magic (Rank 2)
+ [8492] = 1, -- Cone of Cold (Rank 2)
+ [8495] = 1, -- Mana Shield (Rank 3)
+ [8600] = 2, -- Fevered Plague
+ [8788] = 1, -- Lightning Shield (Rank 4)
+ [8898] = 1, -- Sapta Sight
+ [8907] = 1, -- Mark of the Wild (Rank 5)
+ [8910] = 1, -- Rejuvenation (Rank 7)
+ [8914] = 1, -- Thorns (Rank 4)
+ [8921] = 1, -- Moonfire
+ [8925] = 1, -- Moonfire (Rank 3)
+ [8926] = 1, -- Moonfire (Rank 4)
+ [8927] = 1, -- Moonfire (Rank 5)
+ [8928] = 1, -- Moonfire (Rank 6)
+ [8929] = 1, -- Moonfire (Rank 7)
+ [8936] = 1, -- Regrowth (Rank 1)
+ [8938] = 1, -- Regrowth (Rank 2)
+ [8939] = 1, -- Regrowth (Rank 3)
+ [8940] = 1, -- Regrowth (Rank 4)
+ [8941] = 1, -- Regrowth (Rank 5)
+ [8988] = 1, -- Silence (Rank 1)
+ [9034] = 1, -- Immolate
+ [9275] = 1, -- Immolate
+ [9459] = 1, -- Corrosive Ooze
+ [9482] = 1, -- Amplify Flames
+ [9484] = 1, -- Shackle Undead (Rank 1)
+ [9485] = 1, -- Shackle Undead (Rank 2)
+ [9672] = 1, -- Frostbolt
+ [9750] = 1, -- Regrowth (Rank 6)
+ [9756] = 1, -- Thorns (Rank 5)
+ [9775] = 2, -- Irradiated
+ [9833] = 1, -- Moonfire (Rank 8)
+ [9839] = 1, -- Rejuvenation (Rank 8)
+ [9840] = 1, -- Rejuvenation (Rank 9)
+ [9856] = 1, -- Regrowth (Rank 7)
+ [9884] = 1, -- Mark of the Wild (Rank 6)
+ [9885] = 1, -- Mark of the Wild (Rank 7)
+ [9906] = 1, -- Reflection
+ [9910] = 1, -- Thorns (Rank 6)
+ [10060] = 1, -- Power Infusion
+ [10156] = 1, -- Arcane Intellect (Rank 4)
+ [10157] = 1, -- Arcane Intellect (Rank 5)
+ [10159] = 1, -- Cone of Cold (Rank 3)
+ [10160] = 1, -- Cone of Cold (Rank 4)
+ [10170] = 1, -- Amplify Magic (Rank 4)
+ [10173] = 1, -- Dampen Magic (Rank 4)
+ [10174] = 1, -- Dampen Magic (Rank 5)
+ [10179] = 1, -- Frostbolt (Rank 8)
+ [10180] = 1, -- Frostbolt (Rank 9)
+ [10278] = 1, -- Hand of Protection (Rank 3)
+ [10308] = 1, -- Hammer of Justice (Rank 4)
+ [10326] = 1, -- Turn Evil
+ [10431] = 1, -- Lightning Shield (Rank 6)
+ [10432] = 1, -- Lightning Shield (Rank 7)
+ [10452] = 1, -- Flame Buffet
+ [10730] = 1, -- Pacify
+ [10831] = 1, -- Reflection Field
+ [10890] = 1, -- Psychic Scream (Rank 4)
+ [10892] = 1, -- Shadow Word: Pain (Rank 6)
+ [10894] = 1, -- Shadow Word: Pain (Rank 8)
+ [10898] = 1, -- Power Word: Shield (Rank 7)
+ [10899] = 1, -- Power Word: Shield (Rank 8)
+ [10901] = 1, -- Power Word: Shield (Rank 10)
+ [10927] = 1, -- Renew (Rank 7)
+ [10937] = 1, -- Power Word: Fortitude (Rank 5)
+ [10938] = 1, -- Power Word: Fortitude (Rank 6)
+ [10955] = 1, -- Shackle Undead (Rank 3)
+ [10957] = 1, -- Shadow Protection (Rank 2)
+ [10958] = 1, -- Shadow Protection (Rank 3)
+ [11020] = 1, -- Petrify
+ [11264] = 1, -- Ice Blast
+ [11397] = 2, -- Diseased Shot
+ [11426] = 1, -- Ice Barrier (Rank 1)
+ [11436] = 1, -- Slow
+ [11442] = 2, -- Withered Touch
+ [11443] = 1, -- Cripple
+ [11445] = 1, -- Bone Armor
+ [11538] = 1, -- Frostbolt
+ [11639] = 1, -- Shadow Word: Pain
+ [11640] = 1, -- Renew
+ [11641] = 1, -- Hex
+ [11665] = 1, -- Immolate (Rank 5)
+ [11671] = 1, -- Corruption (Rank 5)
+ [11699] = 1, -- Drain Life (Rank 5)
+ [11707] = 4, -- Curse of Weakness (Rank 5)
+ [11711] = 4, -- Curse of Agony (Rank 4)
+ [11712] = 4, -- Curse of Agony (Rank 5)
+ [11719] = 4, -- Curse of Tongues (Rank 2)
+ [11770] = 1, -- Fire Shield (Rank 4)
+ [11841] = 1, -- Static Barrier
+ [11922] = 1, -- Entangling Roots
+ [11962] = 1, -- Immolate
+ [11974] = 1, -- Power Word: Shield
+ [11980] = 4, -- Curse of Weakness
+ [12040] = 1, -- Shadow Shield
+ [12042] = 1, -- Arcane Power
+ [12043] = 1, -- Presence of Mind
+ [12096] = 1, -- Fear
+ [12098] = 1, -- Sleep
+ [12178] = 1, -- Stamina (Level 4)
+ [12245] = 2, -- Infected Spine
+ [12248] = 1, -- Amplify Damage
+ [12251] = 3, -- Virulent Poison
+ [12255] = 4, -- Curse of Tuten'kash
+ [12472] = 1, -- Icy Veins
+ [12493] = 4, -- Curse of Weakness
+ [12494] = 1, -- Frostbite
+ [12528] = 1, -- Silence
+ [12530] = 1, -- Frailty
+ [12531] = 1, -- Chilling Touch
+ [12536] = 1, -- Clearcasting
+ [12541] = 2, -- Ghoul Rot
+ [12544] = 1, -- Frost Armor
+ [12548] = 1, -- Frost Shock
+ [12579] = 1, -- Winter's Chill
+ [12611] = 1, -- Cone of Cold
+ [12654] = 1, -- Ignite
+ [12741] = 4, -- Curse of Weakness
+ [12824] = 1, -- Polymorph (Rank 2)
+ [12826] = 1, -- Polymorph (Rank 4)
+ [12890] = 1, -- Deep Slumber
+ [12946] = 2, -- Putrid Stench
+ [13218] = 3, -- Wound Poison (Rank 1)
+ [13222] = 3, -- Wound Poison II (Rank 2)
+ [13298] = 3, -- Poison
+ [13326] = 1, -- Arcane Intellect
+ [13439] = 1, -- Frostbolt
+ [13526] = 3, -- Corrosive Poison
+ [13542] = 1, -- Mend Pet (Rank 5)
+ [13549] = 3, -- Serpent Sting (Rank 2)
+ [13550] = 3, -- Serpent Sting (Rank 3)
+ [13551] = 3, -- Serpent Sting (Rank 4)
+ [13552] = 3, -- Serpent Sting (Rank 5)
+ [13553] = 3, -- Serpent Sting (Rank 6)
+ [13555] = 3, -- Serpent Sting (Rank 8)
+ [13704] = 1, -- Psychic Scream
+ [13797] = 1, -- Immolation Trap (Rank 1)
+ [13864] = 1, -- Power Word: Fortitude
+ [14032] = 1, -- Shadow Word: Pain
+ [14202] = 5, -- Enrage
+ [14298] = 1, -- Immolation Trap (Rank 2)
+ [14308] = 1, -- Freezing Trap Effect (Rank 2)
+ [14309] = 1, -- Freezing Trap Effect (Rank 3)
+ [14323] = 1, -- Hunter's Mark (Rank 2)
+ [14324] = 1, -- Hunter's Mark (Rank 3)
+ [14325] = 1, -- Hunter's Mark (Rank 4)
+ [14515] = 1, -- Dominate Mind
+ [14517] = 1, -- Crusader Strike
+ [14518] = 1, -- Crusader Strike
+ [14751] = 1, -- Inner Focus
+ [14752] = 1, -- Divine Spirit (Rank 1)
+ [14818] = 1, -- Divine Spirit (Rank 2)
+ [14819] = 1, -- Divine Spirit (Rank 3)
+ [14893] = 1, -- Inspiration (Rank 1)
+ [14914] = 1, -- Holy Fire (Rank 1)
+ [15039] = 1, -- Flame Shock
+ [15258] = 1, -- Shadow Weaving (Rank 1)
+ [15262] = 1, -- Holy Fire (Rank 2)
+ [15263] = 1, -- Holy Fire (Rank 3)
+ [15265] = 1, -- Holy Fire (Rank 5)
+ [15266] = 1, -- Holy Fire (Rank 6)
+ [15271] = 1, -- Spirit Tap (Rank 1)
+ [15357] = 1, -- Inspiration (Rank 2)
+ [15359] = 1, -- Inspiration (Rank 3)
+ [15487] = 1, -- Silence
+ [15531] = 1, -- Frost Nova
+ [15532] = 1, -- Frost Nova
+ [15548] = 1, -- Thunderclap
+ [15588] = 1, -- Thunderclap
+ [16166] = 1, -- Elemental Mastery
+ [16177] = 1, -- Ancestral Fortitude (Rank 1)
+ [16188] = 1, -- Nature's Swiftness
+ [16236] = 1, -- Ancestral Fortitude (Rank 2)
+ [16237] = 1, -- Ancestral Fortitude (Rank 3)
+ [16246] = 1, -- Clearcasting
+ [16468] = 3, -- Mother's Milk
+ [16567] = 4, -- Tainted Mind
+ [16591] = 1, -- Noggenfogger Elixir
+ [16593] = 1, -- Noggenfogger Elixir
+ [16595] = 1, -- Noggenfogger Elixir
+ [16689] = 1, -- Nature's Grasp (Rank 1)
+ [16711] = 1, -- Grow
+ [16810] = 1, -- Nature's Grasp (Rank 2)
+ [16811] = 1, -- Nature's Grasp (Rank 3)
+ [16812] = 1, -- Nature's Grasp (Rank 4)
+ [16857] = 1, -- Faerie Fire (Feral)
+ [16870] = 1, -- Clearcasting
+ [16886] = 1, -- Nature's Grace
+ [17116] = 1, -- Nature's Swiftness
+ [17154] = 1, -- The Green Tower (Rank 1)
+ [17800] = 1, -- Shadow Mastery
+ [17928] = 1, -- Howl of Terror (Rank 2)
+ [17941] = 1, -- Shadow Trance
+ [18093] = 1, -- Pyroclasm
+ [18118] = 1, -- Aftermath
+ [18223] = 4, -- Curse of Exhaustion
+ [18266] = 4, -- Curse of Agony
+ [18267] = 4, -- Curse of Weakness
+ [18425] = 1, -- Silenced - Improved Kick
+ [18469] = 1, -- Silenced - Improved Counterspell (Rank 1)
+ [18498] = 1, -- Silenced - Gag Order
+ [18647] = 1, -- Banish (Rank 2)
+ [18657] = 1, -- Hibernate (Rank 2)
+ [18658] = 1, -- Hibernate (Rank 3)
+ [18972] = 1, -- Slow
+ [19276] = 2, -- Devouring Plague (Rank 2)
+ [19277] = 2, -- Devouring Plague (Rank 3)
+ [19278] = 2, -- Devouring Plague (Rank 4)
+ [19386] = 3, -- Wyvern Sting (Rank 1)
+ [19440] = 1, -- Sacrifice (Rank 3)
+ [19740] = 1, -- Blessing of Might (Rank 1)
+ [19742] = 1, -- Blessing of Wisdom (Rank 1)
+ [19821] = 1, -- Arcane Bomb
+ [19834] = 1, -- Blessing of Might (Rank 2)
+ [19835] = 1, -- Blessing of Might (Rank 3)
+ [19836] = 1, -- Blessing of Might (Rank 4)
+ [19837] = 1, -- Blessing of Might (Rank 5)
+ [19838] = 1, -- Blessing of Might (Rank 6)
+ [19850] = 1, -- Blessing of Wisdom (Rank 2)
+ [19852] = 1, -- Blessing of Wisdom (Rank 3)
+ [19853] = 1, -- Blessing of Wisdom (Rank 4)
+ [19854] = 1, -- Blessing of Wisdom (Rank 5)
+ [19972] = 1, -- Entangling Roots (Rank 4)
+ [19973] = 1, -- Entangling Roots (Rank 3)
+ [19974] = 1, -- Entangling Roots (Rank 2)
+ [19975] = 1, -- Entangling Roots
+ [20006] = 1, -- Unholy Curse
+ [20050] = 1, -- Conviction
+ [20052] = 1, -- Conviction
+ [20053] = 1, -- Vengeance
+ [20066] = 1, -- Repentance
+ [20184] = 1, -- Judgement of Justice
+ [20185] = 1, -- Judgement of Light (Rank 1)
+ [20186] = 1, -- Judgement of Wisdom (Rank 1)
+ [20216] = 1, -- Divine Favor
+ [20217] = 1, -- Blessing of Kings
+ [20236] = 1, -- Lay on Hands (Rank 2)
+ [20798] = 1, -- Demon Skin
+ [20800] = 1, -- Immolate
+ [20911] = 1, -- Blessing of Sanctuary
+ [20925] = 1, -- Holy Shield (Rank 1)
+ [20927] = 1, -- Holy Shield (Rank 2)
+ [21007] = 4, -- Curse of Weakness
+ [21049] = 1, -- Bloodlust
+ [21062] = 2, -- Putrid Breath
+ [21067] = 3, -- Poison Bolt
+ [21068] = 1, -- Corruption
+ [21069] = 3, -- Larva Goo
+ [21331] = 1, -- Entangling Roots
+ [21337] = 1, -- Thorns
+ [21562] = 1, -- Prayer of Fortitude (Rank 1)
+ [21564] = 1, -- Prayer of Fortitude (Rank 2)
+ [21687] = 3, -- Toxic Volley
+ [21787] = 3, -- Deadly Poison
+ [21849] = 1, -- Gift of the Wild (Rank 1)
+ [21850] = 1, -- Gift of the Wild (Rank 2)
+ [22812] = 1, -- Barkskin
+ [22959] = 1, -- Improved Scorch
+ [23028] = 1, -- Arcane Brilliance (Rank 1)
+ [24131] = 3, -- Wyvern Sting
+ [24259] = 1, -- Spell Lock
+ [24398] = 1, -- Water Shield (Rank 7)
+ [24586] = 3, -- Scorpid Poison (Rank 3)
+ [24844] = 1, -- Lightning Breath
+ [24974] = 1, -- Insect Swarm (Rank 2)
+ [25046] = 1, -- Arcane Torrent (Racial)
+ [25058] = 1, -- Renew
+ [25207] = 1, -- Amulet of the Moon
+ [25217] = 1, -- Power Word: Shield (Rank 11)
+ [25218] = 1, -- Power Word: Shield (Rank 12)
+ [25221] = 1, -- Renew (Rank 11)
+ [25222] = 1, -- Renew (Rank 12)
+ [25290] = 1, -- Blessing of Wisdom (Rank 6)
+ [25291] = 1, -- Blessing of Might (Rank 7)
+ [25295] = 3, -- Serpent Sting (Rank 9)
+ [25312] = 1, -- Divine Spirit (Rank 5)
+ [25368] = 1, -- Shadow Word: Pain (Rank 10)
+ [25389] = 1, -- Power Word: Fortitude (Rank 7)
+ [25392] = 1, -- Prayer of Fortitude (Rank 3)
+ [25433] = 1, -- Shadow Protection (Rank 4)
+ [25467] = 2, -- Devouring Plague (Rank 7)
+ [25469] = 1, -- Lightning Shield (Rank 8)
+ [25472] = 1, -- Lightning Shield (Rank 9)
+ [25606] = 1, -- Pendant of the Agate Shield
+ [25746] = 1, -- Damage Absorb
+ [25747] = 1, -- Damage Absorb
+ [25780] = 1, -- Righteous Fury
+ [25809] = 3, -- Crippling Poison (Rank 1)
+ [25810] = 3, -- Mind-numbing Poison
+ [25894] = 1, -- Greater Blessing of Wisdom (Rank 1)
+ [25898] = 1, -- Greater Blessing of Kings
+ [25899] = 1, -- Greater Blessing of Sanctuary
+ [25916] = 1, -- Greater Blessing of Might (Rank 2)
+ [25918] = 1, -- Greater Blessing of Wisdom (Rank 2)
+ [26017] = 1, -- Vindication (Rank 2)
+ [26968] = 3, -- Deadly Poison VI (Rank 6)
+ [26990] = 1, -- Mark of the Wild (Rank 8)
+ [26991] = 1, -- Gift of the Wild (Rank 3)
+ [26992] = 1, -- Thorns (Rank 7)
+ [27009] = 1, -- Nature's Grasp (Rank 7)
+ [27046] = 1, -- Mend Pet (Rank 8)
+ [27126] = 1, -- Arcane Intellect (Rank 6)
+ [27127] = 1, -- Arcane Brilliance (Rank 2)
+ [27140] = 1, -- Blessing of Might (Rank 8)
+ [27142] = 1, -- Blessing of Wisdom (Rank 7)
+ [27143] = 1, -- Greater Blessing of Wisdom (Rank 3)
+ [27187] = 3, -- Deadly Poison VII (Rank 7)
+ [27243] = 1, -- Seed of Corruption
+ [27681] = 1, -- Prayer of Spirit (Rank 1)
+ [27683] = 1, -- Prayer of Shadow Protection (Rank 1)
+ [27813] = 1, -- Blessed Recovery (Rank 1)
+ [27817] = 1, -- Blessed Recovery (Rank 2)
+ [27818] = 1, -- Blessed Recovery (Rank 3)
+ [27828] = 1, -- Focused Casting (Rank 2)
+ [27841] = 1, -- Divine Spirit (Rank 4)
+ [28271] = 1, -- Polymorph (turtle)
+ [28272] = 1, -- Polymorph (pig)
+ [28682] = 1, -- Combustion
+ [28730] = 1, -- Arcane Torrent (Racial)
+ [29166] = 1, -- Innervate
+ [29228] = 1, -- Flame Shock (Rank 6)
+ [29674] = 1, -- Lesser Shielding
+ [30108] = 1, -- Unstable Affliction
+ [30283] = 1, -- Shadowfury
+ [30910] = 4, -- Curse of Doom (Rank 2)
+ [31117] = 1, -- Unstable Affliction
+ [31589] = 1, -- Slow
+ [31643] = 1, -- Blazing Speed
+ [31661] = 1, -- Dragon's Breath (Rank 1)
+ [31803] = 1, -- Holy Vengeance (Rank 1)
+ [31834] = 1, -- Light's Grace
+ [31842] = 1, -- Divine Illumination
+ [31884] = 1, -- Avenging Wrath
+ [31935] = 1, -- Avenger's Shield
+ [32182] = 1, -- Heroism
+ [32386] = 1, -- Shadow Embrace
+ [32388] = 1, -- Shadow Embrace
+ [32389] = 1, -- Shadow Embrace
+ [32390] = 1, -- Shadow Embrace
+ [32391] = 1, -- Shadow Embrace
+ [32593] = 1, -- Earth Shield (Rank 2)
+ [32594] = 1, -- Earth Shield (Rank 3)
+ [32645] = 3, -- Envenom
+ [32999] = 1, -- Prayer of Spirit (Rank 2)
+ [33041] = 1, -- Dragon's Breath (Rank 2)
+ [33042] = 1, -- Dragon's Breath (Rank 3)
+ [33043] = 1, -- Dragon's Breath (Rank 4)
+ [33082] = 1, -- Strength (Rank 5)
+ [33151] = 1, -- Surge of Light (Rank 1)
+ [33206] = 1, -- Pain Suppression
+ [33395] = 1, -- Freeze
+ [33736] = 1, -- Water Shield (Rank 8)
+ [33763] = 1, -- Lifebloom (Rank 1)
+ [33944] = 1, -- Dampen Magic (Rank 6)
+ [33946] = 1, -- Amplify Magic (Rank 6)
+ [34490] = 1, -- Silencing Shot
+ [34501] = 1, -- Expose Weakness
+ [34655] = 3, -- Deadly Poison
+ [34914] = 1, -- Vampiric Touch
+ [34917] = 1, -- Vampiric Touch (Rank 3)
+ [34936] = 1, -- Backlash
+ [35944] = 1, -- Power Word: Shield
+ [38254] = 2, -- Festering Wound
+ [38384] = 1, -- Cone of Cold
+ [39374] = 1, -- Prayer of Shadow Protection (Rank 2)
+ [39796] = 1, -- Stoneclaw Stun
+ [41635] = 1, -- Prayer of Mending (Rank 1)
+ [42702] = 2, -- Decrepify
+ [42740] = 1, -- Njord's Rune of Protection
+ [42842] = 1, -- Frostbolt (Rank 16)
+ [42917] = 1, -- Frost Nova (Rank 6)
+ [42931] = 1, -- Cone of Cold (Rank 8)
+ [42949] = 1, -- Dragon's Breath (Rank 5)
+ [42950] = 1, -- Dragon's Breath (Rank 6)
+ [42995] = 1, -- Arcane Intellect (Rank 7)
+ [43002] = 1, -- Arcane Brilliance (Rank 3)
+ [43010] = 1, -- Fire Ward (Rank 7)
+ [43012] = 1, -- Frost Ward (Rank 7)
+ [43015] = 1, -- Dampen Magic (Rank 7)
+ [43017] = 1, -- Amplify Magic (Rank 7)
+ [43019] = 1, -- Mana Shield (Rank 8)
+ [43020] = 1, -- Mana Shield (Rank 9)
+ [43038] = 1, -- Ice Barrier (Rank 7)
+ [43039] = 1, -- Ice Barrier (Rank 8)
+ [43195] = 1, -- Intellect (Rank 6)
+ [43196] = 1, -- Armor (Rank 6)
+ [43197] = 1, -- Spirit (Rank 6)
+ [44401] = 1, -- Missile Barrage
+ [44413] = 1, -- Incanter's Absorption
+ [44415] = 1, -- Blackout (Rank 1)
+ [44457] = 1, -- Living Bomb
+ [44544] = 1, -- Fingers of Frost
+ [44572] = 1, -- Deep Freeze
+ [44614] = 1, -- Frostfire Bolt (Rank 1)
+ [45241] = 1, -- Focused Will (Rank 2)
+ [45242] = 1, -- Focused Will (Rank 3)
+ [45282] = 1, -- Natural Perfection (Rank 2)
+ [45283] = 1, -- Natural Perfection (Rank 3)
+ [45438] = 1, -- Ice Block
+ [45524] = 1, -- Chains of Ice
+ [46604] = 1, -- Ice Block
+ [46987] = 1, -- Frostbolt
+ [46989] = 1, -- Improved Blink
+ [47283] = 1, -- Empowered Imp
+ [47476] = 1, -- Strangulate
+ [47610] = 1, -- Frostfire Bolt (Rank 2)
+ [47699] = 1, -- Crystal Bark
+ [47753] = 1, -- Divine Aegis (Rank 1)
+ [47779] = 1, -- Arcane Torrent
+ [47811] = 1, -- Immolate (Rank 11)
+ [47813] = 1, -- Corruption (Rank 10)
+ [47836] = 1, -- Seed of Corruption (Rank 3)
+ [47843] = 1, -- Unstable Affliction (Rank 5)
+ [47847] = 1, -- Shadowfury (Rank 5)
+ [47857] = 1, -- Drain Life (Rank 9)
+ [47860] = 1, -- Death Coil (Rank 6)
+ [47864] = 4, -- Curse of Agony (Rank 9)
+ [47865] = 4, -- Curse of the Elements (Rank 5)
+ [47867] = 4, -- Curse of Doom (Rank 3)
+ [47891] = 1, -- Shadow Ward (Rank 6)
+ [47930] = 1, -- Grace
+ [47960] = 1, -- Shadowflame
+ [47983] = 1, -- Fire Shield (Rank 7)
+ [47986] = 1, -- Sacrifice (Rank 9)
+ [47990] = 1, -- Suffering (Rank 8)
+ [48058] = 1, -- Crystal Bloom
+ [48065] = 1, -- Power Word: Shield (Rank 13)
+ [48066] = 1, -- Power Word: Shield (Rank 14)
+ [48068] = 1, -- Renew (Rank 14)
+ [48073] = 1, -- Divine Spirit (Rank 6)
+ [48074] = 1, -- Prayer of Spirit (Rank 3)
+ [48100] = 1, -- Intellect (Rank 7)
+ [48101] = 1, -- Stamina (Level 6)
+ [48102] = 1, -- Stamina (Level 6)
+ [48103] = 1, -- Spirit (Rank 7)
+ [48111] = 1, -- Prayer of Mending (Rank 3)
+ [48125] = 1, -- Shadow Word: Pain (Rank 12)
+ [48135] = 1, -- Holy Fire (Rank 11)
+ [48160] = 1, -- Vampiric Touch (Rank 5)
+ [48161] = 1, -- Power Word: Fortitude (Rank 8)
+ [48162] = 1, -- Prayer of Fortitude (Rank 4)
+ [48169] = 1, -- Shadow Protection (Rank 5)
+ [48170] = 1, -- Prayer of Shadow Protection (Rank 3)
+ [48181] = 1, -- Haunt
+ [48299] = 2, -- Devouring Plague (Rank 8)
+ [48300] = 2, -- Devouring Plague (Rank 9)
+ [48301] = 1, -- Mind Trauma
+ [48438] = 1, -- Wild Growth
+ [48440] = 1, -- Rejuvenation (Rank 14)
+ [48441] = 1, -- Rejuvenation (Rank 15)
+ [48442] = 1, -- Regrowth (Rank 11)
+ [48443] = 1, -- Regrowth (Rank 12)
+ [48450] = 1, -- Lifebloom (Rank 2)
+ [48451] = 1, -- Lifebloom (Rank 3)
+ [48463] = 1, -- Moonfire (Rank 14)
+ [48468] = 1, -- Insect Swarm (Rank 7)
+ [48469] = 1, -- Mark of the Wild (Rank 9)
+ [48470] = 1, -- Gift of the Wild (Rank 4)
+ [48817] = 1, -- Holy Wrath (Rank 5)
+ [48827] = 1, -- Avenger's Shield (Rank 5)
+ [48931] = 1, -- Blessing of Might (Rank 9)
+ [48932] = 1, -- Blessing of Might (Rank 10)
+ [48933] = 1, -- Greater Blessing of Might (Rank 4)
+ [48934] = 1, -- Greater Blessing of Might (Rank 5)
+ [48935] = 1, -- Blessing of Wisdom (Rank 8)
+ [48936] = 1, -- Blessing of Wisdom (Rank 9)
+ [48937] = 1, -- Greater Blessing of Wisdom (Rank 4)
+ [48938] = 1, -- Greater Blessing of Wisdom (Rank 5)
+ [48952] = 1, -- Holy Shield (Rank 6)
+ [48989] = 1, -- Mend Pet (Rank 9)
+ [48990] = 1, -- Mend Pet (Rank 10)
+ [49000] = 3, -- Serpent Sting (Rank 11)
+ [49001] = 3, -- Serpent Sting (Rank 12)
+ [49005] = 1, -- Mark of Blood
+ [49010] = 3, -- Wyvern Sting (Rank 6)
+ [49012] = 3, -- Wyvern Sting (Rank 6)
+ [49054] = 1, -- Immolation Trap (Rank 8)
+ [49203] = 1, -- Hungering Cold (Rank 1)
+ [49232] = 1, -- Flame Shock (Rank 8)
+ [49233] = 1, -- Flame Shock (Rank 9)
+ [49236] = 1, -- Frost Shock (Rank 7)
+ [49280] = 1, -- Lightning Shield (Rank 10)
+ [49281] = 1, -- Lightning Shield (Rank 11)
+ [49284] = 1, -- Earth Shield (Rank 5)
+ [50263] = 1, -- Quickness of the Sailor
+ [50448] = 1, -- Bloody Vengeance
+ [50449] = 1, -- Bloody Vengeance
+ [50486] = 1, -- Acclimation
+ [50510] = 2, -- Crypt Fever
+ [50511] = 4, -- Curse of Weakness (Rank 9)
+ [50613] = 1, -- Arcane Torrent (Racial)
+ [51209] = 1, -- Hungering Cold (Rank 1)
+ [51514] = 4, -- Hex
+ [51726] = 2, -- Ebon Plague
+ [51735] = 2, -- Ebon Plague
+ [51945] = 1, -- Earthliving (Rank 1)
+ [51990] = 1, -- Earthliving (Rank 2)
+ [51999] = 1, -- Earthliving (Rank 5)
+ [52000] = 1, -- Earthliving (Rank 6)
+ [52127] = 1, -- Water Shield (Rank 1)
+ [52129] = 1, -- Water Shield (Rank 2)
+ [52131] = 1, -- Water Shield (Rank 3)
+ [52134] = 1, -- Water Shield (Rank 4)
+ [52136] = 1, -- Water Shield (Rank 5)
+ [52138] = 1, -- Water Shield (Rank 6)
+ [52493] = 3, -- Poison Spray
+ [53030] = 3, -- Leech Poison
+ [53251] = 1, -- Wild Growth (Rank 4)
+ [53307] = 1, -- Thorns (Rank 8)
+ [53308] = 1, -- Entangling Roots (Rank 8)
+ [53312] = 1, -- Nature's Grasp (Rank 8)
+ [53313] = 1, -- Entangling Roots (Rank 8)
+ [53330] = 2, -- Infected Wound
+ [53338] = 1, -- Hunter's Mark (Rank 5)
+ [53390] = 1, -- Tidal Waves
+ [53515] = 1, -- Owl's Focus
+ [53517] = 1, -- Roar of Recovery
+ [53547] = 1, -- Pin (Rank 5)
+ [53548] = 1, -- Pin (Rank 6)
+ [53563] = 1, -- Beacon of Light
+ [53601] = 1, -- Sacred Shield (Rank 1)
+ [53742] = 1, -- Blood Corruption (Rank 1)
+ [53817] = 1, -- Maelstrom Weapon
+ [54203] = 1, -- Sheath of Light
+ [54277] = 1, -- Backdraft
+ [54309] = 1, -- Mark of Darkness
+ [54370] = 1, -- Nether Protection
+ [54371] = 1, -- Nether Protection
+ [54372] = 1, -- Nether Protection
+ [54373] = 1, -- Nether Protection
+ [54374] = 1, -- Nether Protection
+ [54375] = 1, -- Nether Protection
+ [54428] = 1, -- Divine Plea
+ [54646] = 1, -- Focus Magic
+ [54648] = 1, -- Focus Magic
+ [54706] = 1, -- Venom Web Spray
+ [54833] = 1, -- Glyph of Innervate
+ [54965] = 1, -- Bolthorn's Rune of Flame
+ [55021] = 1, -- Silenced - Improved Counterspell (Rank 2)
+ [55078] = 2, -- Blood Plague
+ [55080] = 1, -- Shattered Barrier
+ [55095] = 2, -- Frost Fever
+ [55166] = 1, -- Tidal Force
+ [55360] = 1, -- Living Bomb (Rank 3)
+ [56161] = 1, -- Glyph of Prayer of Healing
+ [56352] = 1, -- Storm Punch
+ [56520] = 1, -- Blessing of Might (Rank 10)
+ [56521] = 1, -- Blessing of Wisdom
+ [56525] = 1, -- Blessing of Kings
+ [56778] = 1, -- Mana Shield
+ [56827] = 1, -- Aura of Arcane Haste
+ [57063] = 1, -- Arcane Attraction
+ [57350] = 1, -- Illusionary Barrier
+ [57519] = 5, -- Enrage
+ [57524] = 1, -- Metanoia
+ [57529] = 1, -- Arcane Potency
+ [57531] = 1, -- Arcane Potency
+ [57580] = 1, -- Lightning Infusion
+ [57761] = 1, -- Fireball!
+ [57960] = 1, -- Water Shield (Rank 9)
+ [57969] = 3, -- Deadly Poison VIII (Rank 8)
+ [57970] = 3, -- Deadly Poison IX (Rank 9)
+ [57974] = 3, -- Wound Poison VI (Rank 6)
+ [57975] = 3, -- Wound Poison VII (Rank 7)
+ [57993] = 3, -- Envenom (Rank 4)
+ [58179] = 2, -- Infected Wounds
+ [58180] = 2, -- Infected Wounds
+ [58181] = 2, -- Infected Wounds
+ [58448] = 1, -- Strength (Rank 7)
+ [58449] = 1, -- Strength (Rank 8)
+ [58450] = 1, -- Agility (Rank 7)
+ [58451] = 1, -- Agility (Rank 8)
+ [58452] = 1, -- Armor (Rank 7)
+ [58501] = 1, -- Iron Boot Flask
+ [58597] = 1, -- Sacred Shield (Rank 1)
+ [58610] = 1, -- Lava Breath (Rank 5)
+ [58611] = 1, -- Lava Breath (Rank 6)
+ [59000] = 1, -- Improved Spirit Tap (Rank 2)
+ [59052] = 1, -- Freezing Fog
+ [59164] = 1, -- Haunt (Rank 4)
+ [59578] = 1, -- The Art of War (Rank 2)
+ [59638] = 1, -- Frostbolt
+ [59888] = 1, -- Borrowed Time
+ [59889] = 1, -- Borrowed Time
+ [59891] = 1, -- Borrowed Time
+ [60210] = 1, -- Freezing Arrow Effect (Rank 1) (PvP duration)
+ [60433] = 1, -- Earth and Moon
+ [60518] = 1, -- Touched by a Troll
+ [60946] = 1, -- Nightmare
+ [60947] = 1, -- Nightmare
+ [61024] = 1, -- Dalaran Intellect (Rank 7)
+ [61291] = 1, -- Shadowflame
+ [61295] = 1, -- Riptide
+ [61299] = 1, -- Riptide (Rank 2)
+ [61301] = 1, -- Riptide (Rank 4)
+ [61305] = 1, -- Polymorph (cat)
+ [61316] = 1, -- Dalaran Brilliance (Rank 3)
+ [61394] = 1, -- Glyph of Freezing Trap
+ [61721] = 1, -- Polymorph (Rabbit)
+ [61840] = 1, -- Righteous Vengeance
+ [63167] = 1, -- Decimation
+ [63243] = 1, -- Pyroclasm
+ [63244] = 1, -- Pyroclasm
+ [63321] = 1, -- Life Tap
+ [63529] = 1, -- Silenced - Shield of the Templar
+ [63668] = 1, -- Black Arrow (Rank 2)
+ [63672] = 1, -- Black Arrow (Rank 6)
+ [63685] = 1, -- Freeze
+ [63725] = 1, -- Holy Concentration
+ [63734] = 1, -- Serendipity
+ [63735] = 1, -- Serendipity
+ [64044] = 1, -- Psychic Horror
+ [64128] = 1, -- Body and Soul
+ [64205] = 1, -- Divine Sacrifice
+ [64368] = 1, -- Eradication
+ [64370] = 1, -- Eradication
+ [64371] = 1, -- Eradication
+ [64695] = 1, -- Earthgrab
+ [64701] = 1, -- Elemental Mastery
+ [64803] = 1, -- Entrapment
+ [64804] = 1, -- Entrapment
+ [64844] = 1, -- Divine Hymn
+ [64904] = 1, -- Hymn of Hope
+ [65081] = 1, -- Body and Soul
+ [65142] = 2, -- Ebon Plague
+ [65264] = 1, -- Lava Flows
+ [66922] = 1, -- Flash of Light
+ [67631] = 1, -- Aegis
+ [68055] = 1, -- Judgements of the Just (Rank 1)
+ [69180] = 4, -- Gutgore Ripper
+ [69369] = 1, -- Predator's Swiftness
+ [70691] = 1, -- Rejuvenation
+ [71824] = 1, -- Lava Burst
+ [71870] = 1, -- Blessing of Light
+ [71875] = 1, -- Necrotic Touch
+ [71877] = 1, -- Necrotic Touch
+ [71882] = 1, -- Invigoration
+ [72104] = 1, -- Freezing Ground
+ [72586] = 1, -- Blessing of Forgotten Kings
+ [72588] = 1, -- Gift of the Wild
+ [72590] = 1, -- Fortitude
+ [73320] = 1, -- Frostborn Illusion
+ [74347] = 1, -- Silenced - Gag Order
+}
+
+--Durations that don't match PvE durations.
+--http://www.wowwiki.com/Diminishing_returns
+lib.auraInfoPvP = {
+ [118] = 10, -- Polymorph (Rank 1)
+ [339] = 10, -- Entangling Roots (Rank 1)
+ [605] = 10, -- Mind Control
+ [770] = 40, -- Faerie Fire
+-- [1513] = 10, -- Scare Beast (Rank 1)
+ [1715] = 10, -- Hamstring
+ [3355] = 10, -- Freezing Trap Effect (Rank 1)
+ [6215] = 10, -- Fear (Rank 3)
+ [6358] = 10, -- Seduction
+ [6770] = 10, -- Sap (Rank 1)
+ [8643] = 6, -- Kidney Shot (Rank 2) (time based on comob points, i'll assume they're using 5 points)
+ [10326] = 10, -- Turn Evil
+-- [10955] = 10, -- Shackle Undead
+ [14308] = 10, -- Freezing Trap Effect (Rank 2)
+ [14309] = 10, -- Freezing Trap Effect (Rank 3)
+ [16857] = 40, -- Faerie Fire (Feral)
+ [18647] = 6, -- Banish (Rank 2)
+ [18657] = 10, -- Hibernate (Rank 2)
+ [20066] = 6, -- Repentance
+ [47865] = 120, -- Curse of the Elements (Rank 5)
+ [49012] = 6, -- Wyvern Sting (Rank 6)
+ [51514] = 10, -- Hex
+ [51724] = 10, -- Sap (Rank 4)
+ [53308] = 10, -- Entangling Roots (Rank 8)
+ [53313] = 10, -- Entangling Roots (Rank 8)
+ [53338] = 120, -- Hunter's Mark (Rank 5)* Confirm Duration",
+ [61721] = 10, -- Polymorph (Rabbit)
+}
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibBase64-1.0/LibBase64-1.0.lua b/ElvUI/Libraries/LibBase64-1.0/LibBase64-1.0.lua
new file mode 100644
index 0000000..1d35fea
--- /dev/null
+++ b/ElvUI/Libraries/LibBase64-1.0/LibBase64-1.0.lua
@@ -0,0 +1,164 @@
+--[[
+Name: LibBase64-1.0
+Author(s): ckknight (ckknight@gmail.com)
+Website: http://www.wowace.com/projects/libbase64-1-0/
+Description: A library to encode and decode Base64 strings
+License: MIT
+]]
+
+local MAJOR, MINOR = 'LibBase64-1.0-ElvUI', 2
+local LibBase64 = LibStub:NewLibrary(MAJOR, MINOR)
+if not LibBase64 then return end
+
+local wipe, type, error, format, strsub, strchar, strbyte, tconcat = wipe, type, error, format, strsub, strchar, strbyte, table.concat
+local _chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+local byteToNum, numToChar = {}, {}
+for i = 1, #_chars do
+ numToChar[i - 1] = strsub(_chars, i, i)
+ byteToNum[strbyte(_chars, i)] = i - 1
+end
+
+local t = {}
+local equals_byte = strbyte("=")
+local whitespace = {
+ [strbyte(" ")] = true,
+ [strbyte("\t")] = true,
+ [strbyte("\n")] = true,
+ [strbyte("\r")] = true,
+}
+
+--- Encode a normal bytestring into a Base64-encoded string
+-- @param text a bytestring, can be binary data
+-- @param maxLineLength This should be a multiple of 4, greater than 0 or nil. If non-nil, it will break up the output into lines no longer than the given number of characters. 76 is recommended.
+-- @param lineEnding a string to end each line with. This is "\r\n" by default.
+-- @usage LibBase64.Encode("Hello, how are you doing today?") == "SGVsbG8sIGhvdyBhcmUgeW91IGRvaW5nIHRvZGF5Pw=="
+-- @return a Base64-encoded string
+function LibBase64:Encode(text, maxLineLength, lineEnding)
+ if type(text) ~= "string" then
+ error(format("Bad argument #1 to `Encode'. Expected string, got %q", type(text)), 2)
+ end
+
+ if maxLineLength then
+ if type(maxLineLength) ~= "number" then
+ error(format("Bad argument #2 to `Encode'. Expected number or nil, got %q", type(maxLineLength)), 2)
+ elseif (maxLineLength % 4) ~= 0 then
+ error(format("Bad argument #2 to `Encode'. Expected a multiple of 4, got %s", maxLineLength), 2)
+ elseif maxLineLength <= 0 then
+ error(format("Bad argument #2 to `Encode'. Expected a number > 0, got %s", maxLineLength), 2)
+ end
+ end
+
+ if lineEnding == nil then
+ lineEnding = "\r\n"
+ elseif type(lineEnding) ~= "string" then
+ error(format("Bad argument #3 to `Encode'. Expected string, got %q", type(lineEnding)), 2)
+ end
+
+ local currentLength = 0
+ for i = 1, #text, 3 do
+ local a, b, c = strbyte(text, i, i+2)
+ local nilNum = 0
+ if not b then
+ nilNum, b, c = 2, 0, 0
+ elseif not c then
+ nilNum, c = 1, 0
+ end
+
+ local num = a * 2^16 + b * 2^8 + c
+ local d = num % 2^6;num = (num - d) / 2^6
+ c = num % 2^6;num = (num - c) / 2^6
+ b = num % 2^6;num = (num - b) / 2^6
+ a = num % 2^6
+
+ t[#t+1] = numToChar[a]
+ t[#t+1] = numToChar[b]
+ t[#t+1] = (nilNum >= 2) and "=" or numToChar[c]
+ t[#t+1] = (nilNum >= 1) and "=" or numToChar[d]
+
+ currentLength = currentLength + 4
+ if maxLineLength and (currentLength % maxLineLength) == 0 then
+ t[#t+1] = lineEnding
+ end
+ end
+
+ local s = tconcat(t)
+ wipe(t)
+
+ return s
+end
+
+local t2 = {}
+
+--- Decode a Base64-encoded string into a bytestring
+-- this will raise an error if the data passed in is not a Base64-encoded string
+-- this will ignore whitespace, but not invalid characters
+-- @param text a Base64-encoded string
+-- @usage LibBase64.Encode("SGVsbG8sIGhvdyBhcmUgeW91IGRvaW5nIHRvZGF5Pw==") == "Hello, how are you doing today?"
+-- @return a bytestring
+function LibBase64:Decode(text)
+ if type(text) ~= "string" then
+ error(format("Bad argument #1 to `Decode'. Expected string, got %q", type(text)), 2)
+ end
+
+ for i = 1, #text do
+ local byte = strbyte(text, i)
+ if not (whitespace[byte] or byte == equals_byte) then
+ local num = byteToNum[byte]
+ if not num then
+ wipe(t2)
+
+ error(format("Bad argument #1 to `Decode'. Received an invalid char: %q", strsub(text, i, i)), 2)
+ end
+
+ t2[#t2+1] = num
+ end
+ end
+
+ for i = 1, #t2, 4 do
+ local a, b, c, d = t2[i], t2[i+1], t2[i+2], t2[i+3]
+ local nilNum = 0
+ if not c then
+ nilNum, c, d = 2, 0, 0
+ elseif not d then
+ nilNum, d = 1, 0
+ end
+
+ local num = a * 2^18 + b * 2^12 + c * 2^6 + d
+ c = num % 2^8;num = (num - c) / 2^8
+ b = num % 2^8;num = (num - b) / 2^8
+ a = num % 2^8
+
+ t[#t+1] = strchar(a)
+ if nilNum < 2 then t[#t+1] = strchar(b) end
+ if nilNum < 1 then t[#t+1] = strchar(c) end
+ end
+
+ wipe(t2)
+
+ local s = tconcat(t)
+ wipe(t)
+
+ return s
+end
+
+function LibBase64:IsBase64(text)
+ if type(text) ~= "string" then
+ error(format("Bad argument #1 to `IsBase64'. Expected string, got %q", type(text)), 2)
+ end
+
+ if #text % 4 ~= 0 then
+ return false
+ end
+
+ for i = 1, #text do
+ local byte = strbyte(text, i)
+ if not (whitespace[byte] or byte == equals_byte) then
+ local num = byteToNum[byte]
+ if not num then
+ return false
+ end
+ end
+ end
+
+ return true
+end
diff --git a/ElvUI/Libraries/LibChatAnims/LibChatAnims.lua b/ElvUI/Libraries/LibChatAnims/LibChatAnims.lua
new file mode 100644
index 0000000..268ae47
--- /dev/null
+++ b/ElvUI/Libraries/LibChatAnims/LibChatAnims.lua
@@ -0,0 +1,191 @@
+
+local MAJOR, MINOR = "LibChatAnims", 1 -- Bump minor on changes
+local LCA = LibStub:NewLibrary(MAJOR, MINOR)
+if not LCA then return end -- No upgrade needed
+
+LCA.animations = LCA.animations or {} -- Animation storage
+local anims = LCA.animations
+
+----------------------------------------------------
+-- Note, most of this code is simply replicated from
+-- Blizzard's FloatingChatFrame.lua file.
+-- The only real changes are the creation and use
+-- of animations vs the use of UIFrameFlash.
+--
+
+FCFDockOverflowButton_UpdatePulseState = function(self)
+ local dock = self:GetParent()
+ local shouldPulse = false
+ for _, chatFrame in pairs(FCFDock_GetChatFrames(dock)) do
+ local chatTab = _G[chatFrame:GetName().."Tab"]
+ if ( not chatFrame.isStaticDocked and chatTab.alerting) then
+ -- Make sure the rects are valid. (Not always the case when resizing the WoW client
+ if ( not chatTab:GetRight() or not dock.scrollFrame:GetRight() ) then
+ return false
+ end
+ -- Check if it's off the screen.
+ local DELTA = 3 -- Chosen through experimentation
+ if ( chatTab:GetRight() < (dock.scrollFrame:GetLeft() + DELTA) or chatTab:GetLeft() > (dock.scrollFrame:GetRight() - DELTA) ) then
+ shouldPulse = true
+ break
+ end
+ end
+ end
+
+ local tex = self:GetHighlightTexture()
+ if shouldPulse then
+ if not anims[tex] then
+ anims[tex] = tex:CreateAnimationGroup()
+
+ local fade1 = anims[tex]:CreateAnimation("Alpha")
+ fade1:SetDuration(1)
+ fade1:SetChange(1)
+ fade1:SetOrder(1)
+
+ local fade2 = anims[tex]:CreateAnimation("Alpha")
+ fade2:SetDuration(1)
+ fade2:SetChange(-1)
+ fade2:SetOrder(2)
+ end
+ tex:Show()
+ tex:SetAlpha(0)
+ anims[tex]:SetLooping("REPEAT")
+ anims[tex]:Play()
+
+ self:LockHighlight()
+ self.alerting = true
+ else
+ if anims[tex] then
+ anims[tex]:Stop()
+ end
+ self:UnlockHighlight()
+ tex:SetAlpha(1)
+ tex:Show()
+ self.alerting = false
+ end
+
+ if self.list:IsShown() then
+ FCFDockOverflowList_Update(self.list, dock)
+ end
+ return true
+end
+
+FCFDockOverflowListButton_SetValue = function(button, chatFrame)
+ local chatTab = _G[chatFrame:GetName().."Tab"]
+ button.chatFrame = chatFrame
+ button:SetText(chatFrame.name)
+
+ local colorTable = chatTab.selectedColorTable or DEFAULT_TAB_SELECTED_COLOR_TABLE
+
+ if chatTab.selectedColorTable then
+ button:GetFontString():SetTextColor(colorTable.r, colorTable.g, colorTable.b)
+ else
+ button:GetFontString():SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
+ end
+
+ button.glow:SetVertexColor(colorTable.r, colorTable.g, colorTable.b)
+
+ if chatTab.conversationIcon then
+ button.conversationIcon:SetVertexColor(colorTable.r, colorTable.g, colorTable.b)
+ button.conversationIcon:Show()
+ else
+ button.conversationIcon:Hide()
+ end
+
+ if chatTab.alerting then
+ button.alerting = true
+ if not anims[button.glow] then
+ anims[button.glow] = button.glow:CreateAnimationGroup()
+
+ local fade1 = anims[button.glow]:CreateAnimation("Alpha")
+ fade1:SetDuration(1)
+ fade1:SetChange(1)
+ fade1:SetOrder(1)
+
+ local fade2 = anims[button.glow]:CreateAnimation("Alpha")
+ fade2:SetDuration(1)
+ fade2:SetChange(-1)
+ fade2:SetOrder(2)
+ end
+ button.glow:Show()
+ button.glow:SetAlpha(0)
+ anims[button.glow]:SetLooping("REPEAT")
+ anims[button.glow]:Play()
+ else
+ button.alerting = false
+ if anims[button.glow] then
+ anims[button.glow]:Stop()
+ end
+ button.glow:Hide()
+ end
+ button:Show()
+end
+
+FCF_StartAlertFlash = function(chatFrame)
+ local chatTab = _G[chatFrame:GetName().."Tab"]
+
+ if chatFrame.minFrame then
+ if not anims[chatFrame.minFrame] then
+ anims[chatFrame.minFrame] = chatFrame.minFrame.glow:CreateAnimationGroup()
+
+ local fade1 = anims[chatFrame.minFrame]:CreateAnimation("Alpha")
+ fade1:SetDuration(1)
+ fade1:SetChange(1)
+ fade1:SetOrder(1)
+
+ local fade2 = anims[chatFrame.minFrame]:CreateAnimation("Alpha")
+ fade2:SetDuration(1)
+ fade2:SetChange(-1)
+ fade2:SetOrder(2)
+ end
+ chatFrame.minFrame.glow:Show()
+ chatFrame.minFrame.glow:SetAlpha(0)
+ anims[chatFrame.minFrame]:SetLooping("REPEAT")
+ anims[chatFrame.minFrame]:Play()
+ chatFrame.minFrame.alerting = true
+ end
+
+ if not anims[chatTab.glow] then
+ anims[chatTab.glow] = chatTab.glow:CreateAnimationGroup()
+
+ local fade1 = anims[chatTab.glow]:CreateAnimation("Alpha")
+ fade1:SetDuration(1)
+ fade1:SetChange(1)
+ fade1:SetOrder(1)
+
+ local fade2 = anims[chatTab.glow]:CreateAnimation("Alpha")
+ fade2:SetDuration(1)
+ fade2:SetChange(-1)
+ fade2:SetOrder(2)
+ end
+ chatTab.glow:Show()
+ chatTab.glow:SetAlpha(0)
+ anims[chatTab.glow]:SetLooping("REPEAT")
+ anims[chatTab.glow]:Play()
+ chatTab.alerting = true
+
+ FCFTab_UpdateAlpha(chatFrame)
+ FCFDockOverflowButton_UpdatePulseState(GENERAL_CHAT_DOCK.overflowButton)
+end
+
+FCF_StopAlertFlash = function(chatFrame)
+ local chatTab = _G[chatFrame:GetName().."Tab"]
+
+ if chatFrame.minFrame then
+ if anims[chatFrame.minFrame] then
+ anims[chatFrame.minFrame]:Stop()
+ end
+ chatFrame.minFrame.glow:Hide()
+ chatFrame.minFrame.alerting = false
+ end
+
+ if anims[chatTab.glow] then
+ anims[chatTab.glow]:Stop()
+ end
+ chatTab.glow:Hide()
+ chatTab.alerting = false
+
+ FCFTab_UpdateAlpha(chatFrame)
+ FCFDockOverflowButton_UpdatePulseState(GENERAL_CHAT_DOCK.overflowButton)
+end
+
diff --git a/ElvUI/Libraries/LibCompress/LibCompress.lua b/ElvUI/Libraries/LibCompress/LibCompress.lua
new file mode 100644
index 0000000..978ee40
--- /dev/null
+++ b/ElvUI/Libraries/LibCompress/LibCompress.lua
@@ -0,0 +1,1254 @@
+----------------------------------------------------------------------------------
+--
+-- LibCompress.lua
+--
+-- Authors: jjsheets and Galmok of European Stormrage (Horde)
+-- Email : sheets.jeff@gmail.com and galmok@gmail.com
+-- Licence: GPL version 2 (General Public License)
+-- Revision: $Revision: 83 $
+-- Date: $Date: 2018-07-03 14:33:48 +0000 (Tue, 03 Jul 2018) $
+----------------------------------------------------------------------------------
+
+
+local LibCompress = LibStub:NewLibrary("LibCompress", 90000 + tonumber(("$Revision: 83 $"):match("%d+")))
+
+if not LibCompress then return end
+
+-- list of codecs in this file:
+-- \000 - Never used
+-- \001 - Uncompressed
+-- \002 - LZW
+-- \003 - Huffman
+
+
+-- local is faster than global
+local CreateFrame = CreateFrame
+local type = type
+local tostring = tostring
+local select = select
+local next = next
+local loadstring = loadstring
+local setmetatable = setmetatable
+local rawset = rawset
+local assert = assert
+local table_insert = table.insert
+local table_remove = table.remove
+local table_concat = table.concat
+local string_char = string.char
+local string_byte = string.byte
+local string_len = string.len
+local string_sub = string.sub
+local unpack = unpack
+local pairs = pairs
+local bit_band = bit.band
+local bit_bor = bit.bor
+local bit_bxor = bit.bxor
+local bit_bnot = bit.bnot
+local bit_lshift = bit.lshift
+local bit_rshift = bit.rshift
+
+--------------------------------------------------------------------------------
+-- Cleanup
+
+local tables = {} -- tables that may be cleaned have to be kept here
+local tables_to_clean = {} -- list of tables by name (string) that may be reset to {} after a timeout
+
+-- tables that may be erased
+local function cleanup()
+ for k in pairs(tables_to_clean) do
+ tables[k] = {}
+ tables_to_clean[k] = nil
+ end
+end
+
+local timeout = -1
+local function onUpdate(frame, elapsed)
+ frame:Hide()
+ timeout = timeout - elapsed
+ if timeout <= 0 then
+ cleanup()
+ end
+end
+
+LibCompress.frame = LibCompress.frame or CreateFrame("frame", nil, UIParent) -- reuse the old frame
+LibCompress.frame:SetScript("OnUpdate", onUpdate)
+LibCompress.frame:Hide()
+
+local function setCleanupTables(...)
+ timeout = 15 -- empty tables after 15 seconds
+ if not LibCompress.frame:IsShown() then
+ LibCompress.frame:Show()
+ end
+ for i = 1, select("#",...) do
+ tables_to_clean[(select(i, ...))] = true
+ end
+end
+
+----------------------------------------------------------------------
+----------------------------------------------------------------------
+--
+-- compression algorithms
+
+--------------------------------------------------------------------------------
+-- LZW codec
+-- implemented by sheets.jeff@gmail.com
+
+-- encode is used to uniquely encode a number into a sequence of bytes that can be decoded using decode()
+-- the bytes returned by this do not contain "\000"
+local bytes = {}
+local function encode(x)
+ for k = 1, #bytes do
+ bytes[k] = nil
+ end
+
+ bytes[#bytes + 1] = x % 255
+ x=math.floor(x/255)
+
+ while x > 0 do
+ bytes[#bytes + 1] = x % 255
+ x=math.floor(x/255)
+ end
+ if #bytes == 1 and bytes[1] > 0 and bytes[1] < 250 then
+ return string_char(bytes[1])
+ else
+ for i = 1, #bytes do
+ bytes[i] = bytes[i] + 1
+ end
+ return string_char(256 - #bytes, unpack(bytes))
+ end
+end
+
+--decode converts a unique character sequence into its equivalent number, from ss, beginning at the ith char.
+-- returns the decoded number and the count of characters used in the decode process.
+local function decode(ss, i)
+ i = i or 1
+ local a = string_byte(ss, i, i)
+ if a > 249 then
+ local r = 0
+ a = 256 - a
+ for n = i + a, i + 1, -1 do
+ r = r * 255 + string_byte(ss, n, n) - 1
+ end
+ return r, a + 1
+ else
+ return a, 1
+ end
+end
+
+-- Compresses the given uncompressed string.
+-- Unless the uncompressed string starts with "\002", this is guaranteed to return a string equal to or smaller than
+-- the passed string.
+-- the returned string will only contain "\000" characters in rare circumstances, and will contain none if the
+-- source string has none.
+local dict = {}
+function LibCompress:CompressLZW(uncompressed)
+ if type(uncompressed) == "string" then
+ local dict_size = 256
+ for k in pairs(dict) do
+ dict[k] = nil
+ end
+
+ local result = {"\002"}
+ local w = ''
+ local ressize = 1
+
+ for i = 0, 255 do
+ dict[string_char(i)] = i
+ end
+
+ for i = 1, #uncompressed do
+ local c = uncompressed:sub(i, i)
+ local wc = w..c
+ if dict[wc] then
+ w = wc
+ else
+ dict[wc] = dict_size
+ dict_size = dict_size + 1
+ local r = encode(dict[w])
+ ressize = ressize + #r
+ result[#result + 1] = r
+ w = c
+ end
+ end
+
+ if w then
+ local r = encode(dict[w])
+ ressize = ressize + #r
+ result[#result + 1] = r
+ end
+
+ if (#uncompressed + 1) > ressize then
+ return table_concat(result)
+ else
+ return string_char(1)..uncompressed
+ end
+ else
+ return nil, "Can only compress strings"
+ end
+end
+
+-- if the passed string is a compressed string, this will decompress it and return the decompressed string.
+-- Otherwise it return an error message
+-- compressed strings are marked by beginning with "\002"
+function LibCompress:DecompressLZW(compressed)
+ if type(compressed) == "string" then
+ if compressed:sub(1, 1) ~= "\002" then
+ return nil, "Can only decompress LZW compressed data ("..tostring(compressed:sub(1, 1))..")"
+ end
+
+ compressed = compressed:sub(2)
+ local dict_size = 256
+
+ for k in pairs(dict) do
+ dict[k] = nil
+ end
+
+ for i = 0, 255 do
+ dict[i] = string_char(i)
+ end
+
+ local result = {}
+ local t = 1
+ local delta, k
+ k, delta = decode(compressed, t)
+ t = t + delta
+ result[#result + 1] = dict[k]
+
+ local w = dict[k]
+ local entry
+ while t <= #compressed do
+ k, delta = decode(compressed, t)
+ t = t + delta
+ entry = dict[k] or (w..w:sub(1, 1))
+ result[#result + 1] = entry
+ dict[dict_size] = w..entry:sub(1, 1)
+ dict_size = dict_size + 1
+ w = entry
+ end
+ return table_concat(result)
+ else
+ return nil, "Can only uncompress strings"
+ end
+end
+
+
+--------------------------------------------------------------------------------
+-- Huffman codec
+-- implemented by Galmok of European Stormrage (Horde), galmok@gmail.com
+
+local function addCode(tree, bcode, length)
+ if tree then
+ tree.bcode = bcode
+ tree.blength = length
+ if tree.c1 then
+ addCode(tree.c1, bit_bor(bcode, bit_lshift(1, length)), length + 1)
+ end
+ if tree.c2 then
+ addCode(tree.c2, bcode, length + 1)
+ end
+ end
+end
+
+local function escape_code(code, length)
+ local escaped_code = 0
+ local b
+ local l = 0
+ for i = length -1, 0, - 1 do
+ b = bit_band(code, bit_lshift(1, i)) == 0 and 0 or 1
+ escaped_code = bit_lshift(escaped_code, 1 + b) + b
+ l = l + b
+ end
+ if length + l > 32 then
+ return nil, "escape overflow ("..(length + l)..")"
+ end
+ return escaped_code, length + l
+end
+
+tables.Huffman_compressed = {}
+tables.Huffman_large_compressed = {}
+
+local compressed_size = 0
+local remainder
+local remainder_length
+local function addBits(tbl, code, length)
+ if remainder_length+length >= 32 then
+ -- we have at least 4 bytes to store; bulk it
+ remainder = remainder + bit_lshift(code, remainder_length) -- this overflows! Top part of code is lost (but we handle it below)
+ -- remainder now holds 4 full bytes to store. So lets do it.
+ compressed_size = compressed_size + 1
+ tbl[compressed_size] = string_char(bit_band(remainder, 255)) ..
+ string_char(bit_band(bit_rshift(remainder, 8), 255)) ..
+ string_char(bit_band(bit_rshift(remainder, 16), 255)) ..
+ string_char(bit_band(bit_rshift(remainder, 24), 255))
+ remainder = 0
+ code = bit_rshift(code, 32 - remainder_length)
+ length = remainder_length + length - 32
+ remainder_length = 0
+ end
+ if remainder_length+length >= 16 then
+ -- we have at least 2 bytes to store; bulk it
+ remainder = remainder + bit_lshift(code, remainder_length)
+ remainder_length = length + remainder_length
+ -- remainder now holds at least 2 full bytes to store. So lets do it.
+ compressed_size = compressed_size + 1
+ tbl[compressed_size] = string_char(bit_band(remainder, 255)) .. string_char(bit_band(bit_rshift(remainder, 8), 255))
+ remainder = bit_rshift(remainder, 16)
+ code = remainder
+ length = remainder_length - 16
+ remainder = 0
+ remainder_length = 0
+ end
+ remainder = remainder + bit_lshift(code, remainder_length)
+ remainder_length = length + remainder_length
+ if remainder_length >= 8 then
+ compressed_size = compressed_size + 1
+ tbl[compressed_size] = string_char(bit_band(remainder, 255))
+ remainder = bit_rshift(remainder, 8)
+ remainder_length = remainder_length -8
+ end
+end
+
+-- word size for this huffman algorithm is 8 bits (1 byte).
+-- this means the best compression is representing 1 byte with 1 bit, i.e. compress to 0.125 of original size.
+function LibCompress:CompressHuffman(uncompressed)
+ if type(uncompressed) ~= "string" then
+ return nil, "Can only compress strings"
+ end
+ if #uncompressed == 0 then
+ return "\001"
+ end
+
+ -- make histogram
+ local hist = {}
+ -- don't have to use all data to make the histogram
+ local uncompressed_size = string_len(uncompressed)
+ local c
+ for i = 1, uncompressed_size do
+ c = string_byte(uncompressed, i)
+ hist[c] = (hist[c] or 0) + 1
+ end
+
+ --Start with as many leaves as there are symbols.
+ local leafs = {}
+ local leaf
+ local symbols = {}
+ for symbol, weight in pairs(hist) do
+ leaf = { symbol=string_char(symbol), weight=weight }
+ symbols[symbol] = leaf
+ table_insert(leafs, leaf)
+ end
+
+ -- Enqueue all leaf nodes into the first queue (by probability in increasing order,
+ -- so that the least likely item is in the head of the queue).
+ sort(leafs, function(a, b)
+ if a.weight < b.weight then
+ return true
+ elseif a.weight > b.weight then
+ return false
+ else
+ return nil
+ end
+ end)
+
+ local nLeafs = #leafs
+
+ -- create tree
+ local huff = {}
+ --While there is more than one node in the queues:
+ local length, height, li, hi, leaf1, leaf2
+ local newNode
+ while (#leafs + #huff > 1) do
+ -- Dequeue the two nodes with the lowest weight.
+ -- Dequeue first
+ if not next(huff) then
+ li, leaf1 = next(leafs)
+ table_remove(leafs, li)
+ elseif not next(leafs) then
+ hi, leaf1 = next(huff)
+ table_remove(huff, hi)
+ else
+ li, length = next(leafs)
+ hi, height = next(huff)
+ if length.weight <= height.weight then
+ leaf1 = length
+ table_remove(leafs, li)
+ else
+ leaf1 = height
+ table_remove(huff, hi)
+ end
+ end
+
+ -- Dequeue second
+ if not next(huff) then
+ li, leaf2 = next(leafs)
+ table_remove(leafs, li)
+ elseif not next(leafs) then
+ hi, leaf2 = next(huff)
+ table_remove(huff, hi)
+ else
+ li, length = next(leafs)
+ hi, height = next(huff)
+ if length.weight <= height.weight then
+ leaf2 = length
+ table_remove(leafs, li)
+ else
+ leaf2 = height
+ table_remove(huff, hi)
+ end
+ end
+
+ --Create a new internal node, with the two just-removed nodes as children (either node can be either child) and the sum of their weights as the new weight.
+ newNode = {
+ c1 = leaf1,
+ c2 = leaf2,
+ weight = leaf1.weight + leaf2.weight
+ }
+ table_insert(huff,newNode)
+ end
+
+ if #leafs > 0 then
+ li, length = next(leafs)
+ table_insert(huff, length)
+ table_remove(leafs, li)
+ end
+ huff = huff[1]
+
+ -- assign codes to each symbol
+ -- c1 = "0", c2 = "1"
+ -- As a common convention, bit '0' represents following the left child and bit '1' represents following the right child.
+ -- c1 = left, c2 = right
+
+ addCode(huff, 0, 0)
+ if huff then
+ huff.bcode = 0
+ huff.blength = 1
+ end
+
+ -- READING
+ -- bitfield = 0
+ -- bitfield_len = 0
+ -- read byte1
+ -- bitfield = bitfield + bit_lshift(byte1, bitfield_len)
+ -- bitfield_len = bitfield_len + 8
+ -- read byte2
+ -- bitfield = bitfield + bit_lshift(byte2, bitfield_len)
+ -- bitfield_len = bitfield_len + 8
+ -- (use 5 bits)
+ -- word = bit_band( bitfield, bit_lshift(1,5)-1)
+ -- bitfield = bit_rshift( bitfield, 5)
+ -- bitfield_len = bitfield_len - 5
+ -- read byte3
+ -- bitfield = bitfield + bit_lshift(byte3, bitfield_len)
+ -- bitfield_len = bitfield_len + 8
+
+ -- WRITING
+ remainder = 0
+ remainder_length = 0
+
+ local compressed = tables.Huffman_compressed
+ --compressed_size = 0
+
+ -- first byte is version info. 0 = uncompressed, 1 = 8 - bit word huffman compressed
+ compressed[1] = "\003"
+
+ -- Header: byte 0 = #leafs, bytes 1-3 = size of uncompressed data
+ -- max 2^24 bytes
+ length = string_len(uncompressed)
+ compressed[2] = string_char(bit_band(nLeafs -1, 255)) -- number of leafs
+ compressed[3] = string_char(bit_band(length, 255)) -- bit 0-7
+ compressed[4] = string_char(bit_band(bit_rshift(length, 8), 255)) -- bit 8-15
+ compressed[5] = string_char(bit_band(bit_rshift(length, 16), 255)) -- bit 16-23
+ compressed_size = 5
+
+ -- create symbol/code map
+ local escaped_code, escaped_code_len
+ for symbol, leaf in pairs(symbols) do
+ addBits(compressed, symbol, 8)
+ escaped_code, escaped_code_len = escape_code(leaf.bcode, leaf.blength)
+ if not escaped_code then
+ return nil, escaped_code_len
+ end
+ addBits(compressed, escaped_code, escaped_code_len)
+ addBits(compressed, 3, 2)
+ end
+
+ -- create huffman code
+ local large_compressed = tables.Huffman_large_compressed
+ local large_compressed_size = 0
+ local ulimit
+ for i = 1, length, 200 do
+ ulimit = length < (i + 199) and length or (i + 199)
+
+ for sub_i = i, ulimit do
+ c = string_byte(uncompressed, sub_i)
+ addBits(compressed, symbols[c].bcode, symbols[c].blength)
+ end
+
+ large_compressed_size = large_compressed_size + 1
+ large_compressed[large_compressed_size] = table_concat(compressed, "", 1, compressed_size)
+ compressed_size = 0
+ end
+
+ -- add remaining bits (if any)
+ if remainder_length > 0 then
+ large_compressed_size = large_compressed_size + 1
+ large_compressed[large_compressed_size] = string_char(remainder)
+ end
+ local compressed_string = table_concat(large_compressed, "", 1, large_compressed_size)
+
+ -- is compression worth it? If not, return uncompressed data.
+ if (#uncompressed + 1) <= #compressed_string then
+ return "\001"..uncompressed
+ end
+
+ setCleanupTables("Huffman_compressed", "Huffman_large_compressed")
+ return compressed_string
+end
+
+-- lookuptable (cached between calls)
+local lshiftMask = {}
+setmetatable(lshiftMask, {
+ __index = function (t, k)
+ local v = bit_lshift(1, k)
+ rawset(t, k, v)
+ return v
+ end
+})
+
+-- lookuptable (cached between calls)
+local lshiftMinusOneMask = {}
+setmetatable(lshiftMinusOneMask, {
+ __index = function (t, k)
+ local v = bit_lshift(1, k) - 1
+ rawset(t, k, v)
+ return v
+ end
+})
+
+local function bor64(valueA_high, valueA, valueB_high, valueB)
+ return bit_bor(valueA_high, valueB_high),
+ bit_bor(valueA, valueB)
+end
+
+local function band64(valueA_high, valueA, valueB_high, valueB)
+ return bit_band(valueA_high, valueB_high),
+ bit_band(valueA, valueB)
+end
+
+local function lshift64(value_high, value, lshift_amount)
+ if lshift_amount == 0 then
+ return value_high, value
+ end
+ if lshift_amount >= 64 then
+ return 0, 0
+ end
+ if lshift_amount < 32 then
+ return bit_bor(bit_lshift(value_high, lshift_amount), bit_rshift(value, 32-lshift_amount)),
+ bit_lshift(value, lshift_amount)
+ end
+ -- 32-63 bit shift
+ return bit_lshift(value, lshift_amount), -- builtin modulus 32 on shift amount
+ 0
+end
+
+local function rshift64(value_high, value, rshift_amount)
+ if rshift_amount == 0 then
+ return value_high, value
+ end
+ if rshift_amount >= 64 then
+ return 0, 0
+ end
+ if rshift_amount < 32 then
+ return bit_rshift(value_high, rshift_amount),
+ bit_bor(bit_lshift(value_high, 32-rshift_amount), bit_rshift(value, rshift_amount))
+ end
+ -- 32-63 bit shift
+ return 0,
+ bit_rshift(value_high, rshift_amount)
+end
+
+local function getCode2(bitfield_high, bitfield, field_len)
+ if field_len >= 2 then
+ -- [bitfield_high..bitfield]: bit 0 is right most in bitfield. bit is left most in bitfield_high
+ local b1, b2, remainder_high, remainder
+ for i = 0, field_len - 2 do
+ b1 = i <= 31 and bit_band(bitfield, bit_lshift(1, i)) or bit_band(bitfield_high, bit_lshift(1, i)) -- for shifts, 32 = 0 (5 bit used)
+ b2 = (i+1) <= 31 and bit_band(bitfield, bit_lshift(1, i+1)) or bit_band(bitfield_high, bit_lshift(1, i+1))
+ if not (b1 == 0) and not (b2 == 0) then
+ -- found 2 bits set right after each other (stop bits) with i pointing at the first stop bit
+ -- return the two bitfields separated by the two stopbits (3 values for each: bitfield_high, bitfield, field_len)
+ -- bits left: field_len - (i+2)
+ remainder_high, remainder = rshift64(bitfield_high, bitfield, i+2)
+ -- first bitfield is the lower part
+ return (i-1) >= 32 and bit_band(bitfield_high, bit_lshift(1, i) - 1) or 0,
+ i >= 32 and bitfield or bit_band(bitfield, bit_lshift(1, i) - 1),
+ i,
+ remainder_high,
+ remainder,
+ field_len-(i+2)
+ end
+ end
+ end
+ return nil
+end
+
+local function unescape_code(code, code_len)
+ local unescaped_code = 0
+ local b
+ local l = 0
+ local i = 0
+ while i < code_len do
+ b = bit_band( code, lshiftMask[i])
+ if not (b == 0) then
+ unescaped_code = bit_bor(unescaped_code, lshiftMask[l])
+ i = i + 1
+ end
+ i = i + 1
+ l = l + 1
+ end
+ return unescaped_code, l
+end
+
+tables.Huffman_uncompressed = {}
+tables.Huffman_large_uncompressed = {} -- will always be as big as the largest string ever decompressed. Bad, but clearing it every time takes precious time.
+
+function LibCompress:DecompressHuffman(compressed)
+ if not type(compressed) == "string" then
+ return nil, "Can only uncompress strings"
+ end
+
+ local compressed_size = #compressed
+ --decode header
+ local info_byte = string_byte(compressed)
+ -- is data compressed
+ if info_byte == 1 then
+ return compressed:sub(2) --return uncompressed data
+ end
+ if not (info_byte == 3) then
+ return nil, "Can only decompress Huffman compressed data ("..tostring(info_byte)..")"
+ end
+
+ local num_symbols = string_byte(string_sub(compressed, 2, 2)) + 1
+ local c0 = string_byte(string_sub(compressed, 3, 3))
+ local c1 = string_byte(string_sub(compressed, 4, 4))
+ local c2 = string_byte(string_sub(compressed, 5, 5))
+ local orig_size = c2 * 65536 + c1 * 256 + c0
+ if orig_size == 0 then
+ return ""
+ end
+
+ -- decode code -> symbol map
+ local bitfield = 0
+ local bitfield_high = 0
+ local bitfield_len = 0
+ local map = {} -- only table not reused in Huffman decode.
+ setmetatable(map, {
+ __index = function (t, k)
+ local v = {}
+ rawset(t, k, v)
+ return v
+ end
+ })
+
+ local i = 6 -- byte 1-5 are header bytes
+ local c, cl
+ local minCodeLen = 1000
+ local maxCodeLen = 0
+ local symbol, code_high, code, code_len, temp_high, temp, _bitfield_high, _bitfield, _bitfield_len
+ local n = 0
+ local state = 0 -- 0 = get symbol (8 bits), 1 = get code (varying bits, ends with 2 bits set)
+ while n < num_symbols do
+ if i > compressed_size then
+ return nil, "Cannot decode map"
+ end
+
+ c = string_byte(compressed, i)
+ temp_high, temp = lshift64(0, c, bitfield_len)
+ bitfield_high, bitfield = bor64(bitfield_high, bitfield, temp_high, temp)
+ bitfield_len = bitfield_len + 8
+
+ if state == 0 then
+ symbol = bit_band(bitfield, 255)
+ bitfield_high, bitfield = rshift64(bitfield_high, bitfield, 8)
+ bitfield_len = bitfield_len - 8
+ state = 1 -- search for code now
+ else
+ code_high, code, code_len, _bitfield_high, _bitfield, _bitfield_len = getCode2(bitfield_high, bitfield, bitfield_len)
+ if code_high then
+ bitfield_high, bitfield, bitfield_len = _bitfield_high, _bitfield, _bitfield_len
+ if code_len > 32 then
+ return nil, "Unsupported symbol code length ("..code_len..")"
+ end
+ c, cl = unescape_code(code, code_len)
+ map[cl][c] = string_char(symbol)
+ minCodeLen = cl < minCodeLen and cl or minCodeLen
+ maxCodeLen = cl > maxCodeLen and cl or maxCodeLen
+ --print("symbol: "..string_char(symbol).." code: "..tobinary(c, cl))
+ n = n + 1
+ state = 0 -- search for next symbol (if any)
+ end
+ end
+ i = i + 1
+ end
+
+ -- don't create new subtables for entries not in the map. Waste of space.
+ -- But do return an empty table to prevent runtime errors. (instead of returning nil)
+ local mt = {}
+ setmetatable(map, {
+ __index = function (t, k)
+ return mt
+ end
+ })
+
+ local uncompressed = tables.Huffman_uncompressed
+ local large_uncompressed = tables.Huffman_large_uncompressed
+ local uncompressed_size = 0
+ local large_uncompressed_size = 0
+ local test_code
+ local test_code_len = minCodeLen
+ local dec_size = 0
+ compressed_size = compressed_size + 1
+ local temp_limit = 200 -- first limit of uncompressed data. large_uncompressed will hold strings of length 200
+ temp_limit = temp_limit > orig_size and orig_size or temp_limit
+
+ while true do
+ if test_code_len <= bitfield_len then
+ test_code = bit_band( bitfield, lshiftMinusOneMask[test_code_len])
+ symbol = map[test_code_len][test_code]
+
+ if symbol then
+ uncompressed_size = uncompressed_size + 1
+ uncompressed[uncompressed_size] = symbol
+ dec_size = dec_size + 1
+ if dec_size >= temp_limit then
+ if dec_size >= orig_size then -- checked here for speed reasons
+ break
+ end
+ -- process compressed bytes in smaller chunks
+ large_uncompressed_size = large_uncompressed_size + 1
+ large_uncompressed[large_uncompressed_size] = table_concat(uncompressed, "", 1, uncompressed_size)
+ uncompressed_size = 0
+ temp_limit = temp_limit + 200 -- repeated chunk size is 200 uncompressed bytes
+ temp_limit = temp_limit > orig_size and orig_size or temp_limit
+ end
+
+ bitfield = bit_rshift(bitfield, test_code_len)
+ bitfield_len = bitfield_len - test_code_len
+ test_code_len = minCodeLen
+ else
+ test_code_len = test_code_len + 1
+ if test_code_len > maxCodeLen then
+ return nil, "Decompression error at "..tostring(i).."/"..tostring(#compressed)
+ end
+ end
+ else
+ c = string_byte(compressed, i)
+ bitfield = bitfield + bit_lshift(c or 0, bitfield_len)
+ bitfield_len = bitfield_len + 8
+ if i > compressed_size then
+ break
+ end
+ i = i + 1
+ end
+ end
+
+ setCleanupTables("Huffman_uncompressed", "Huffman_large_uncompressed")
+ return table_concat(large_uncompressed, "", 1, large_uncompressed_size)..table_concat(uncompressed, "", 1, uncompressed_size)
+end
+
+--------------------------------------------------------------------------------
+-- Generic codec interface
+
+function LibCompress:Store(uncompressed)
+ if type(uncompressed) ~= "string" then
+ return nil, "Can only compress strings"
+ end
+ return "\001"..uncompressed
+end
+
+function LibCompress:DecompressUncompressed(data)
+ if type(data) ~= "string" then
+ return nil, "Can only handle strings"
+ end
+ if string_byte(data) ~= 1 then
+ return nil, "Can only handle uncompressed data"
+ end
+ return data:sub(2)
+end
+
+local compression_methods = {
+ [2] = LibCompress.CompressLZW,
+ [3] = LibCompress.CompressHuffman
+}
+
+local decompression_methods = {
+ [1] = LibCompress.DecompressUncompressed,
+ [2] = LibCompress.DecompressLZW,
+ [3] = LibCompress.DecompressHuffman
+}
+
+-- try all compression codecs and return best result
+function LibCompress:Compress(data)
+ local method = next(compression_methods)
+ local result = compression_methods[method](self, data)
+ local n
+ method = next(compression_methods, method)
+ while method do
+ n = compression_methods[method](self, data)
+ if #n < #result then
+ result = n
+ end
+ method = next(compression_methods, method)
+ end
+ return result
+end
+
+function LibCompress:Decompress(data)
+ local header_info = string_byte(data)
+ if decompression_methods[header_info] then
+ return decompression_methods[header_info](self, data)
+ else
+ return nil, "Unknown compression method ("..tostring(header_info)..")"
+ end
+end
+
+----------------------------------------------------------------------
+----------------------------------------------------------------------
+--
+-- Encoding algorithms
+
+--------------------------------------------------------------------------------
+-- Prefix encoding algorithm
+-- implemented by Galmok of European Stormrage (Horde), galmok@gmail.com
+
+--[[
+ Howto: Encode and Decode:
+
+ 3 functions are supplied, 2 of them are variants of the first. They return a table with functions to encode and decode text.
+
+ table, msg = LibCompress:GetEncodeTable(reservedChars, escapeChars, mapChars)
+
+ reservedChars: The characters in this string will not appear in the encoded data.
+ escapeChars: A string of characters used as escape-characters (don't supply more than needed). #escapeChars >= 1
+ mapChars: First characters in reservedChars maps to first characters in mapChars. (#mapChars <= #reservedChars)
+
+ return value:
+ table
+ if nil then msg holds an error message, otherwise use like this:
+
+ encoded_message = table:Encode(message)
+ message = table:Decode(encoded_message)
+
+ GetAddonEncodeTable: Sets up encoding for the addon channel (\000 is encoded)
+ GetChatEncodeTable: Sets up encoding for the chat channel (many bytes encoded, see the function for details)
+
+ Except for the mapped characters, all encoding will be with 1 escape character followed by 1 suffix, i.e. 2 bytes.
+]]
+-- to be able to match any requested byte value, the search string must be preprocessed
+-- characters to escape with %:
+-- ( ) . % + - * ? [ ] ^ $
+-- "illegal" byte values:
+-- 0 is replaces %z
+local gsub_escape_table = {
+ ['\000'] = "%z",
+ [('(')] = "%(",
+ [(')')] = "%)",
+ [('.')] = "%.",
+ [('%')] = "%%",
+ [('+')] = "%+",
+ [('-')] = "%-",
+ [('*')] = "%*",
+ [('?')] = "%?",
+ [('[')] = "%[",
+ [(']')] = "%]",
+ [('^')] = "%^",
+ [('$')] = "%$"
+}
+
+local function escape_for_gsub(str)
+ return str:gsub("([%z%(%)%.%%%+%-%*%?%[%]%^%$])", gsub_escape_table)
+end
+
+function LibCompress:GetEncodeTable(reservedChars, escapeChars, mapChars)
+ reservedChars = reservedChars or ""
+ escapeChars = escapeChars or ""
+ mapChars = mapChars or ""
+
+ -- select a default escape character
+ if escapeChars == "" then
+ return nil, "No escape characters supplied"
+ end
+
+ if #reservedChars < #mapChars then
+ return nil, "Number of reserved characters must be at least as many as the number of mapped chars"
+ end
+
+ if reservedChars == "" then
+ return nil, "No characters to encode"
+ end
+
+ -- list of characters that must be encoded
+ local encodeBytes = reservedChars..escapeChars..mapChars
+
+ -- build list of bytes not available as a suffix to a prefix byte
+ local taken = {}
+ for i = 1, string_len(encodeBytes) do
+ taken[string_sub(encodeBytes, i, i)] = true
+ end
+
+ -- allocate a table to hold encode/decode strings/functions
+ local codecTable = {}
+
+ -- the encoding can be a single gsub, but the decoding can require multiple gsubs
+ local decode_func_string = {}
+
+ local encode_search = {}
+ local encode_translate = {}
+ local encode_func
+ local decode_search = {}
+ local decode_translate = {}
+ local decode_func
+ local c, r, to, from
+ local escapeCharIndex, escapeChar = 0
+
+ -- map single byte to single byte
+ if #mapChars > 0 then
+ for i = 1, #mapChars do
+ from = string_sub(reservedChars, i, i)
+ to = string_sub(mapChars, i, i)
+ encode_translate[from] = to
+ table_insert(encode_search, from)
+ decode_translate[to] = from
+ table_insert(decode_search, to)
+ end
+ codecTable["decode_search"..tostring(escapeCharIndex)] = "([".. escape_for_gsub(table_concat(decode_search)).."])"
+ codecTable["decode_translate"..tostring(escapeCharIndex)] = decode_translate
+ table_insert(decode_func_string, "str = str:gsub(self.decode_search"..tostring(escapeCharIndex)..", self.decode_translate"..tostring(escapeCharIndex)..");")
+
+ end
+
+ -- map single byte to double-byte
+ escapeCharIndex = escapeCharIndex + 1
+ escapeChar = string_sub(escapeChars, escapeCharIndex, escapeCharIndex)
+ r = 0 -- suffix char value to the escapeChar
+ decode_search = {}
+ decode_translate = {}
+ for i = 1, string_len(encodeBytes) do
+ c = string_sub(encodeBytes, i, i)
+ if not encode_translate[c] then
+ -- this loop will update escapeChar and r
+ while r >= 256 or taken[string_char(r)] do
+ r = r + 1
+ if r > 255 then -- switch to next escapeChar
+ codecTable["decode_search"..tostring(escapeCharIndex)] = escape_for_gsub(escapeChar).."([".. escape_for_gsub(table_concat(decode_search)).."])"
+ codecTable["decode_translate"..tostring(escapeCharIndex)] = decode_translate
+ table_insert(decode_func_string, "str = str:gsub(self.decode_search"..tostring(escapeCharIndex)..", self.decode_translate"..tostring(escapeCharIndex)..");")
+
+ escapeCharIndex = escapeCharIndex + 1
+ escapeChar = string_sub(escapeChars, escapeCharIndex, escapeCharIndex)
+
+ if escapeChar == "" then -- we are out of escape chars and we need more!
+ return nil, "Out of escape characters"
+ end
+
+ r = 0
+ decode_search = {}
+ decode_translate = {}
+ end
+ end
+ encode_translate[c] = escapeChar..string_char(r)
+ table_insert(encode_search, c)
+ decode_translate[string_char(r)] = c
+ table_insert(decode_search, string_char(r))
+ r = r + 1
+ end
+ end
+
+ if r > 0 then
+ codecTable["decode_search"..tostring(escapeCharIndex)] = escape_for_gsub(escapeChar).."([".. escape_for_gsub(table_concat(decode_search)).."])"
+ codecTable["decode_translate"..tostring(escapeCharIndex)] = decode_translate
+ table_insert(decode_func_string, "str = str:gsub(self.decode_search"..tostring(escapeCharIndex)..", self.decode_translate"..tostring(escapeCharIndex)..");")
+ end
+
+ -- change last line from "str = ...;" to "return ...;";
+ decode_func_string[#decode_func_string] = decode_func_string[#decode_func_string]:gsub("str = (.*);", "return %1;")
+ decode_func_string = "return function(self, str) "..table_concat(decode_func_string).." end"
+
+ encode_search = "([".. escape_for_gsub(table_concat(encode_search)).."])"
+ decode_search = escape_for_gsub(escapeChars).."([".. escape_for_gsub(table_concat(decode_search)).."])"
+
+ encode_func = assert(loadstring("return function(self, str) return str:gsub(self.encode_search, self.encode_translate); end"))()
+ decode_func = assert(loadstring(decode_func_string))()
+ codecTable.encode_search = encode_search
+ codecTable.encode_translate = encode_translate
+ codecTable.Encode = encode_func
+ codecTable.decode_search = decode_search
+ codecTable.decode_translate = decode_translate
+ codecTable.Decode = decode_func
+
+ codecTable.decode_func_string = decode_func_string -- to be deleted
+ return codecTable
+end
+
+-- Addons: Call this only once and reuse the returned table for all encodings/decodings.
+function LibCompress:GetAddonEncodeTable(reservedChars, escapeChars, mapChars )
+ reservedChars = reservedChars or ""
+ escapeChars = escapeChars or ""
+ mapChars = mapChars or ""
+ -- Following byte values are not allowed:
+ -- \000
+ if escapeChars == "" then
+ escapeChars = "\001"
+ end
+ return self:GetEncodeTable( (reservedChars or "").."\000", escapeChars, mapChars)
+end
+
+-- Addons: Call this only once and reuse the returned table for all encodings/decodings.
+function LibCompress:GetChatEncodeTable(reservedChars, escapeChars, mapChars)
+ reservedChars = reservedChars or ""
+ escapeChars = escapeChars or ""
+ mapChars = mapChars or ""
+ -- Following byte values are not allowed:
+ -- \000, s, S, \010, \013, \124, %
+ -- Because SendChatMessage will error if an UTF8 multibyte character is incomplete,
+ -- all character values above 127 have to be encoded to avoid this. This costs quite a bit of bandwidth (about 13-14%)
+ -- Also, because drunken status is unknown for the received, strings used with SendChatMessage should be terminated with
+ -- an identifying byte value, after which the server MAY add "...hic!" or as much as it can fit(!).
+ -- Pass the identifying byte as a reserved character to this function to ensure the encoding doesn't contain that value.
+ -- or use this: local message, match = arg1:gsub("^(.*)\029.-$", "%1")
+ -- arg1 is message from channel, \029 is the string terminator, but may be used in the encoded datastream as well. :-)
+ -- This encoding will expand data anywhere from:
+ -- 0% (average with pure ascii text)
+ -- 53.5% (average with random data valued zero to 255)
+ -- 100% (only encoding data that encodes to two bytes)
+ local r = {}
+
+ for i = 128, 255 do
+ table_insert(r, string_char(i))
+ end
+
+ reservedChars = "sS\000\010\013\124%"..table_concat(r)..(reservedChars or "")
+ if escapeChars == "" then
+ escapeChars = "\029\031"
+ end
+
+ if mapChars == "" then
+ mapChars = "\015\020";
+ end
+ return self:GetEncodeTable(reservedChars, escapeChars, mapChars)
+end
+
+--------------------------------------------------------------------------------
+-- 7 bit encoding algorithm
+-- implemented by Galmok of European Stormrage (Horde), galmok@gmail.com
+
+-- The encoded data holds values from 0 to 127 inclusive. Additional encoding may be necessary.
+-- This algorithm isn't exactly fast and be used with care and consideration
+
+tables.encode7bit = {}
+
+function LibCompress:Encode7bit(str)
+ local remainder = 0
+ local remainder_length = 0
+ local tbl = tables.encode7bit
+ local encoded_size = 0
+ local length = #str
+ for i = 1, length do
+ local code = string_byte(str, i)
+ remainder = remainder + bit_lshift(code, remainder_length)
+ remainder_length = 8 + remainder_length
+ while remainder_length >= 7 do
+ encoded_size = encoded_size + 1
+ tbl[encoded_size] = string_char(bit_band(remainder, 127))
+ remainder = bit_rshift(remainder, 7)
+ remainder_length = remainder_length -7
+ end
+ end
+
+ if remainder_length > 0 then
+ encoded_size = encoded_size + 1
+ tbl[encoded_size] = string_char(remainder)
+ end
+ setCleanupTables("encode7bit")
+ return table_concat(tbl, "", 1, encoded_size)
+end
+
+tables.decode8bit = {}
+
+function LibCompress:Decode7bit(str)
+ local bit8 = tables.decode8bit
+ local decoded_size = 0
+ local ch
+ local i = 1
+ local bitfield_len = 0
+ local bitfield = 0
+ local length = #str
+ while true do
+ if bitfield_len >= 8 then
+ decoded_size = decoded_size + 1
+ bit8[decoded_size] = string_char(bit_band(bitfield, 255))
+ bitfield = bit_rshift(bitfield, 8)
+ bitfield_len = bitfield_len - 8
+ end
+ ch = string_byte(str, i)
+ bitfield=bitfield + bit_lshift(ch or 0, bitfield_len)
+ bitfield_len = bitfield_len + 7
+ if i > length then
+ break
+ end
+ i = i + 1
+ end
+ setCleanupTables("decode8bit")
+ return table_concat(bit8, "", 1, decoded_size)
+end
+
+----------------------------------------------------------------------
+----------------------------------------------------------------------
+--
+-- Checksum/hash algorithms
+
+--------------------------------------------------------------------------------
+-- FCS16/32 checksum algorithms
+-- converted from C by Galmok of European Stormrage (Horde), galmok@gmail.com
+-- usage:
+-- code = LibCompress:fcs16init()
+-- code = LibCompress:fcs16update(code, data1)
+-- code = LibCompress:fcs16update(code, data2)
+-- code = LibCompress:fcs16update(code, data...)
+-- code = LibCompress:fcs16final(code)
+--
+-- data = string
+-- fcs16 provides a 16 bit checksum, fcs32 provides a 32 bit checksum.
+
+
+--[[/* The following copyright notice concerns only the FCS hash algorithm
+---------------------------------------------------------------------------
+Copyright (c) 2003, Dominik Reichl , Germany.
+All rights reserved.
+
+Distributed under the terms of the GNU General Public License v2.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its properties, including, but not limited to, correctness
+and/or fitness for purpose.
+---------------------------------------------------------------------------
+*/]]
+--// FCS-16 algorithm implemented as described in RFC 1331
+local FCSINIT16 = 65535
+--// Fast 16 bit FCS lookup table
+local fcs16tab = { [0]=0, 4489, 8978, 12955, 17956, 22445, 25910, 29887,
+ 35912, 40385, 44890, 48851, 51820, 56293, 59774, 63735,
+ 4225, 264, 13203, 8730, 22181, 18220, 30135, 25662,
+ 40137, 36160, 49115, 44626, 56045, 52068, 63999, 59510,
+ 8450, 12427, 528, 5017, 26406, 30383, 17460, 21949,
+ 44362, 48323, 36440, 40913, 60270, 64231, 51324, 55797,
+ 12675, 8202, 4753, 792, 30631, 26158, 21685, 17724,
+ 48587, 44098, 40665, 36688, 64495, 60006, 55549, 51572,
+ 16900, 21389, 24854, 28831, 1056, 5545, 10034, 14011,
+ 52812, 57285, 60766, 64727, 34920, 39393, 43898, 47859,
+ 21125, 17164, 29079, 24606, 5281, 1320, 14259, 9786,
+ 57037, 53060, 64991, 60502, 39145, 35168, 48123, 43634,
+ 25350, 29327, 16404, 20893, 9506, 13483, 1584, 6073,
+ 61262, 65223, 52316, 56789, 43370, 47331, 35448, 39921,
+ 29575, 25102, 20629, 16668, 13731, 9258, 5809, 1848,
+ 65487, 60998, 56541, 52564, 47595, 43106, 39673, 35696,
+ 33800, 38273, 42778, 46739, 49708, 54181, 57662, 61623,
+ 2112, 6601, 11090, 15067, 20068, 24557, 28022, 31999,
+ 38025, 34048, 47003, 42514, 53933, 49956, 61887, 57398,
+ 6337, 2376, 15315, 10842, 24293, 20332, 32247, 27774,
+ 42250, 46211, 34328, 38801, 58158, 62119, 49212, 53685,
+ 10562, 14539, 2640, 7129, 28518, 32495, 19572, 24061,
+ 46475, 41986, 38553, 34576, 62383, 57894, 53437, 49460,
+ 14787, 10314, 6865, 2904, 32743, 28270, 23797, 19836,
+ 50700, 55173, 58654, 62615, 32808, 37281, 41786, 45747,
+ 19012, 23501, 26966, 30943, 3168, 7657, 12146, 16123,
+ 54925, 50948, 62879, 58390, 37033, 33056, 46011, 41522,
+ 23237, 19276, 31191, 26718, 7393, 3432, 16371, 11898,
+ 59150, 63111, 50204, 54677, 41258, 45219, 33336, 37809,
+ 27462, 31439, 18516, 23005, 11618, 15595, 3696, 8185,
+ 63375, 58886, 54429, 50452, 45483, 40994, 37561, 33584,
+ 31687, 27214, 22741, 18780, 15843, 11370, 7921, 3960 }
+
+function LibCompress:fcs16init()
+ return FCSINIT16
+end
+
+function LibCompress:fcs16update(uFcs16, pBuffer)
+ local length = string_len(pBuffer)
+ for i = 1, length do
+ uFcs16 = bit_bxor(bit_rshift(uFcs16,8), fcs16tab[bit_band(bit_bxor(uFcs16, string_byte(pBuffer, i)), 255)])
+ end
+ return uFcs16
+end
+
+function LibCompress:fcs16final(uFcs16)
+ return bit_bxor(uFcs16,65535)
+end
+-- END OF FCS16
+
+--[[/*
+---------------------------------------------------------------------------
+Copyright (c) 2003, Dominik Reichl , Germany.
+All rights reserved.
+
+Distributed under the terms of the GNU General Public License v2.
+
+This software is provided 'as is' with no explicit or implied warranties
+in respect of its properties, including, but not limited to, correctness
+and/or fitness for purpose.
+---------------------------------------------------------------------------
+*/]]
+
+--// FCS-32 algorithm implemented as described in RFC 1331
+
+local FCSINIT32 = -1
+
+--// Fast 32 bit FCS lookup table
+local fcs32tab = { [0] = 0, 1996959894, -301047508, -1727442502, 124634137, 1886057615, -379345611, -1637575261,
+ 249268274, 2044508324, -522852066, -1747789432, 162941995, 2125561021, -407360249, -1866523247,
+ 498536548, 1789927666, -205950648, -2067906082, 450548861, 1843258603, -187386543, -2083289657,
+ 325883990, 1684777152, -43845254, -1973040660, 335633487, 1661365465, -99664541, -1928851979,
+ 997073096, 1281953886, -715111964, -1570279054, 1006888145, 1258607687, -770865667, -1526024853,
+ 901097722, 1119000684, -608450090, -1396901568, 853044451, 1172266101, -589951537, -1412350631,
+ 651767980, 1373503546, -925412992, -1076862698, 565507253, 1454621731, -809855591, -1195530993,
+ 671266974, 1594198024, -972236366, -1324619484, 795835527, 1483230225, -1050600021, -1234817731,
+ 1994146192, 31158534, -1731059524, -271249366, 1907459465, 112637215, -1614814043, -390540237,
+ 2013776290, 251722036, -1777751922, -519137256, 2137656763, 141376813, -1855689577, -429695999,
+ 1802195444, 476864866, -2056965928, -228458418, 1812370925, 453092731, -2113342271, -183516073,
+ 1706088902, 314042704, -1950435094, -54949764, 1658658271, 366619977, -1932296973, -69972891,
+ 1303535960, 984961486, -1547960204, -725929758, 1256170817, 1037604311, -1529756563, -740887301,
+ 1131014506, 879679996, -1385723834, -631195440, 1141124467, 855842277, -1442165665, -586318647,
+ 1342533948, 654459306, -1106571248, -921952122, 1466479909, 544179635, -1184443383, -832445281,
+ 1591671054, 702138776, -1328506846, -942167884, 1504918807, 783551873, -1212326853, -1061524307,
+ -306674912, -1698712650, 62317068, 1957810842, -355121351, -1647151185, 81470997, 1943803523,
+ -480048366, -1805370492, 225274430, 2053790376, -468791541, -1828061283, 167816743, 2097651377,
+ -267414716, -2029476910, 503444072, 1762050814, -144550051, -2140837941, 426522225, 1852507879,
+ -19653770, -1982649376, 282753626, 1742555852, -105259153, -1900089351, 397917763, 1622183637,
+ -690576408, -1580100738, 953729732, 1340076626, -776247311, -1497606297, 1068828381, 1219638859,
+ -670225446, -1358292148, 906185462, 1090812512, -547295293, -1469587627, 829329135, 1181335161,
+ -882789492, -1134132454, 628085408, 1382605366, -871598187, -1156888829, 570562233, 1426400815,
+ -977650754, -1296233688, 733239954, 1555261956, -1026031705, -1244606671, 752459403, 1541320221,
+ -1687895376, -328994266, 1969922972, 40735498, -1677130071, -351390145, 1913087877, 83908371,
+ -1782625662, -491226604, 2075208622, 213261112, -1831694693, -438977011, 2094854071, 198958881,
+ -2032938284, -237706686, 1759359992, 534414190, -2118248755, -155638181, 1873836001, 414664567,
+ -2012718362, -15766928, 1711684554, 285281116, -1889165569, -127750551, 1634467795, 376229701,
+ -1609899400, -686959890, 1308918612, 956543938, -1486412191, -799009033, 1231636301, 1047427035,
+ -1362007478, -640263460, 1088359270, 936918000, -1447252397, -558129467, 1202900863, 817233897,
+ -1111625188, -893730166, 1404277552, 615818150, -1160759803, -841546093, 1423857449, 601450431,
+ -1285129682, -1000256840, 1567103746, 711928724, -1274298825, -1022587231, 1510334235, 755167117 }
+
+function LibCompress:fcs32init()
+ return FCSINIT32
+end
+
+function LibCompress:fcs32update(uFcs32, pBuffer)
+ local length = string_len(pBuffer)
+ for i = 1, length do
+ uFcs32 = bit_bxor(bit_rshift(uFcs32, 8), fcs32tab[bit_band(bit_bxor(uFcs32, string_byte(pBuffer, i)), 255)])
+ end
+ return uFcs32
+end
+
+function LibCompress:fcs32final(uFcs32)
+ return bit_bnot(uFcs32)
+end
diff --git a/ElvUI/Libraries/LibDataBroker/LibDataBroker-1.1.lua b/ElvUI/Libraries/LibDataBroker/LibDataBroker-1.1.lua
new file mode 100644
index 0000000..f47c0cd
--- /dev/null
+++ b/ElvUI/Libraries/LibDataBroker/LibDataBroker-1.1.lua
@@ -0,0 +1,90 @@
+
+assert(LibStub, "LibDataBroker-1.1 requires LibStub")
+assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
+
+local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4)
+if not lib then return end
+oldminor = oldminor or 0
+
+
+lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
+lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
+local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
+
+if oldminor < 2 then
+ lib.domt = {
+ __metatable = "access denied",
+ __index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
+ }
+end
+
+if oldminor < 3 then
+ lib.domt.__newindex = function(self, key, value)
+ if not attributestorage[self] then attributestorage[self] = {} end
+ if attributestorage[self][key] == value then return end
+ attributestorage[self][key] = value
+ local name = namestorage[self]
+ if not name then return end
+ callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
+ callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
+ callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
+ callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
+ end
+end
+
+if oldminor < 2 then
+ function lib:NewDataObject(name, dataobj)
+ if self.proxystorage[name] then return end
+
+ if dataobj then
+ assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
+ self.attributestorage[dataobj] = {}
+ for i,v in pairs(dataobj) do
+ self.attributestorage[dataobj][i] = v
+ dataobj[i] = nil
+ end
+ end
+ dataobj = setmetatable(dataobj or {}, self.domt)
+ self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
+ self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
+ return dataobj
+ end
+end
+
+if oldminor < 1 then
+ function lib:DataObjectIterator()
+ return pairs(self.proxystorage)
+ end
+
+ function lib:GetDataObjectByName(dataobjectname)
+ return self.proxystorage[dataobjectname]
+ end
+
+ function lib:GetNameByDataObject(dataobject)
+ return self.namestorage[dataobject]
+ end
+end
+
+if oldminor < 4 then
+ local next = pairs(attributestorage)
+ function lib:pairs(dataobject_or_name)
+ local t = type(dataobject_or_name)
+ assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)")
+
+ local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
+ assert(attributestorage[dataobj], "Data object not found")
+
+ return next, attributestorage[dataobj], nil
+ end
+
+ local ipairs_iter = ipairs(attributestorage)
+ function lib:ipairs(dataobject_or_name)
+ local t = type(dataobject_or_name)
+ assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)")
+
+ local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
+ assert(attributestorage[dataobj], "Data object not found")
+
+ return ipairs_iter, attributestorage[dataobj], 0
+ end
+end
diff --git a/ElvUI/Libraries/LibDualSpec-1.0/LibDualSpec-1.0.lua b/ElvUI/Libraries/LibDualSpec-1.0/LibDualSpec-1.0.lua
new file mode 100644
index 0000000..ef6bdfc
--- /dev/null
+++ b/ElvUI/Libraries/LibDualSpec-1.0/LibDualSpec-1.0.lua
@@ -0,0 +1,328 @@
+--[[
+LibDualSpec-1.0 - Adds dual spec support to individual AceDB-3.0 databases
+Copyright (C) 2009 Adirelle
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Redistribution of a stand alone version is strictly prohibited without
+ prior written authorization from the LibDualSpec project manager.
+ * Neither the name of the LibDualSpec authors nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--]]
+
+local MAJOR, MINOR = "LibDualSpec-1.0", 4
+assert(LibStub, MAJOR.." requires LibStub")
+local lib = LibStub:NewLibrary(MAJOR, MINOR)
+if not lib then return end
+
+-- ----------------------------------------------------------------------------
+-- Library data
+-- ----------------------------------------------------------------------------
+
+lib.talentGroup = lib.talentGroup or GetActiveTalentGroup()
+lib.eventFrame = lib.eventFrame or CreateFrame("Frame")
+
+lib.registry = lib.registry or {}
+lib.options = lib.options or {}
+lib.mixin = lib.mixin or {}
+
+-- ----------------------------------------------------------------------------
+-- Locals
+-- ----------------------------------------------------------------------------
+
+local registry = lib.registry
+local options = lib.options
+local mixin = lib.mixin
+
+-- "Externals"
+local AceDB3 = LibStub('AceDB-3.0', true)
+local AceDBOptions3 = LibStub('AceDBOptions-3.0', true)
+
+-- ----------------------------------------------------------------------------
+-- Localization
+-- ----------------------------------------------------------------------------
+
+local L_DUALSPEC_DESC, L_ENABLED, L_ENABLED_DESC, L_DUAL_PROFILE, L_DUAL_PROFILE_DESC
+
+do
+ L_DUALSPEC_DESC = "When enabled, this feature allow you to select a different "..
+ "profile for each talent spec. The dual profile will be swapped with the "..
+ "current profile each time you switch from a talent spec to the other."
+ L_ENABLED = 'Enable dual profile'
+ L_ENABLED_DESC = 'Check this box to automatically swap profiles on talent switch.'
+ L_DUAL_PROFILE = 'Dual profile'
+ L_DUAL_PROFILE_DESC = 'Select the profile to swap with on talent switch.'
+
+ local locale = GetLocale()
+ if locale == "frFR" then
+ L_DUALSPEC_DESC = "Lorsqu'elle est activée, cette fonctionnalité vous permet de choisir un profil différent pour chaque spécialisation de talents. Le second profil sera échangé avec le profil courant chaque fois que vous passerez d'une spécialisation à l'autre."
+ L_DUAL_PROFILE = "Second profil"
+ L_DUAL_PROFILE_DESC = "Sélectionnez le profil à échanger avec le profil courant lors du changement de spécialisation."
+ L_ENABLED = "Activez le second profil"
+ L_ENABLED_DESC = "Cochez cette case pour échanger automatiquement les profils lors d'un changement de spécialisation."
+ elseif locale == "deDE" then
+ L_DUALSPEC_DESC = "Wenn aktiv, wechselt dieses Feature bei jedem Wechsel der dualen Talentspezialisierung das Profil. Das duale Profil wird beim Wechsel automatisch mit dem derzeit aktiven Profil getauscht."
+ L_DUAL_PROFILE = "Duales Profil"
+ L_DUAL_PROFILE_DESC = "Wähle das Profil, das beim Wechsel der Talente aktiviert wird."
+ L_ENABLED = "Aktiviere Duale Profile"
+ L_ENABLED_DESC = "Aktiviere diese Option, um beim Talentwechsel automatisch zwischen den Profilen zu wechseln."
+ elseif locale == "koKR" then
+ L_DUALSPEC_DESC = "|n전문화 변경 시 현재 프로필을 첫 번째 전문화 때에, 여기서 설정하는 프로필을 두 번째 전문화 때에 적용시킵니다.|n전문화별로 설정을 다르게 하고 싶을 때 아주 유용합니다."
+ L_DUAL_PROFILE = "두번째 전문화 때 프로필"
+ L_DUAL_PROFILE_DESC = "두번째 전문화 때 적용할 프로필을 선택하세요."
+ L_ENABLED = "이중 프로필 사용"
+ L_ENABLED_DESC = "전문화에 따라 다른 프로필을 적용시킵니다."
+ elseif locale == "ruRU" then
+ L_DUALSPEC_DESC = "Двойной профиль позволяет вам выбрать различные профили для каждой раскладки талантов. Профили будут переключаться каждый раз, когда вы переключаете раскладку талантов."
+ L_DUAL_PROFILE = "Второй профиль"
+ L_DUAL_PROFILE_DESC = "Выберите профиль, который необходимо активировать при переключениии талантов."
+ L_ENABLED = "Включить двойной профиль"
+ L_ENABLED_DESC = "Включите эту опцию для автоматического переключения между профилями при переключении раскладки талантов."
+ elseif locale == "zhCN" then
+ L_DUALSPEC_DESC = "启时,你可以为你的双天赋设定另一组配置文件,你的双重配置文件将在你转换天赋时自动与目前使用配置文件交换。"
+ L_DUAL_PROFILE = "双重配置文件"
+ L_DUAL_PROFILE_DESC = "选择转换天赋时所要使用的配置文件"
+ L_ENABLED = "开启双重配置文件"
+ L_ENABLED_DESC = "勾选以便转换天赋时自动交换配置文件。"
+ elseif locale == "zhTW" then
+ L_DUALSPEC_DESC = "啟用時,你可以為你的雙天賦設定另一組設定檔。你的雙設定檔將在你轉換天賦時自動與目前使用設定檔交換。"
+ L_DUAL_PROFILE = "雙設定檔"
+ L_DUAL_PROFILE_DESC = "選擇轉換天賦後所要使用的設定檔"
+ L_ENABLED = "啟用雙設定檔"
+ L_ENABLED_DESC = "勾選以在轉換天賦時自動交換設定檔"
+ elseif locale == "esES" then
+ L_DUALSPEC_DESC = "Si está activa, esta característica te permite seleccionar un perfil distinto para cada configuración de talentos. El perfil secundario será intercambiado por el activo cada vez que cambies de una configuración de talentos a otra."
+ L_DUAL_PROFILE = "Perfil secundario"
+ L_DUAL_PROFILE_DESC = "Elige el perfil secundario que se usará cuando cambies de talentos."
+ L_ENABLED = "Activar perfil secundario"
+ L_ENABLED_DESC = "Activa esta casilla para alternar automáticamente entre prefiles cuando cambies de talentos."
+ end
+end
+
+-- ----------------------------------------------------------------------------
+-- Mixin
+-- ----------------------------------------------------------------------------
+
+--- Get dual spec feature status.
+-- @return (boolean) true is dual spec feature enabled.
+-- @name enhancedDB:IsDualSpecEnabled
+function mixin:IsDualSpecEnabled()
+ return registry[self].db.char.enabled
+end
+
+--- Enable/disabled dual spec feature.
+-- @param enabled (boolean) true to enable dual spec feature, false to disable it.
+-- @name enhancedDB:SetDualSpecEnabled
+function mixin:SetDualSpecEnabled(enabled)
+ local db = registry[self].db
+ if enabled and not db.char.talentGroup then
+ db.char.talentGroup = lib.talentGroup
+ db.char.profile = self:GetCurrentProfile()
+ db.char.enabled = true
+ else
+ db.char.enabled = enabled
+ self:CheckDualSpecState()
+ end
+end
+
+--- Get the alternate profile name.
+-- Defaults to the current profile.
+-- @return (string) Alternate profile name.
+-- @name enhancedDB:GetDualSpecProfile
+function mixin:GetDualSpecProfile()
+ return registry[self].db.char.profile or self:GetCurrentProfile()
+end
+
+--- Set the alternate profile name.
+-- No validation are done to ensure the profile is valid.
+-- @param profileName (string) the profile name to use.
+-- @name enhancedDB:SetDualSpecProfile
+function mixin:SetDualSpecProfile(profileName)
+ registry[self].db.char.profile = profileName
+end
+
+--- Check if a profile swap should occur.
+-- Do nothing if the dual spec feature is disabled. In the other
+-- case, if the internally stored talent spec is different from the
+-- actual active talent spec, the database swaps to the alternate profile.
+-- There is normally no reason to call this method directly as LibDualSpec
+-- takes care of calling it at appropriate times.
+-- @name enhancedDB:CheckDualSpecState
+function mixin:CheckDualSpecState()
+ local db = registry[self].db
+ if db.char.enabled and db.char.talentGroup ~= lib.talentGroup then
+ local currentProfile = self:GetCurrentProfile()
+ local newProfile = db.char.profile
+ db.char.talentGroup = lib.talentGroup
+ if newProfile ~= currentProfile then
+ db.char.profile = currentProfile
+ self:SetProfile(newProfile)
+ end
+ end
+end
+
+-- ----------------------------------------------------------------------------
+-- AceDB-3.0 support
+-- ----------------------------------------------------------------------------
+
+local function EmbedMixin(target)
+ for k,v in pairs(mixin) do
+ rawset(target, k, v)
+ end
+end
+
+-- Upgrade existing mixins
+for target in pairs(registry) do
+ EmbedMixin(target)
+end
+
+-- Actually enhance the database
+-- This is used on first initialization and everytime the database is reset using :ResetDB
+function lib:_EnhanceDatabase(event, target)
+ registry[target].db = target:GetNamespace(MAJOR, true) or target:RegisterNamespace(MAJOR)
+ EmbedMixin(target)
+ target:CheckDualSpecState()
+end
+
+--- Embed dual spec feature into an existing AceDB-3.0 database.
+-- LibDualSpec specific methods are added to the instance.
+-- @name LibDualSpec:EnhanceDatabase
+-- @param target (table) the AceDB-3.0 instance.
+-- @param name (string) a user-friendly name of the database (best bet is the addon name).
+function lib:EnhanceDatabase(target, name)
+ AceDB3 = AceDB3 or LibStub('AceDB-3.0', true)
+ if type(target) ~= "table" then
+ error("Usage: LibDualSpec:EnhanceDatabase(target, name): target should be a table.", 2)
+ elseif type(name) ~= "string" then
+ error("Usage: LibDualSpec:EnhanceDatabase(target, name): name should be a string.", 2)
+ elseif not AceDB3 or not AceDB3.db_registry[target] then
+ error("Usage: LibDualSpec:EnhanceDatabase(target, name): target should be an AceDB-3.0 database.", 2)
+ elseif target.parent then
+ error("Usage: LibDualSpec:EnhanceDatabase(target, name): cannot enhance a namespace.", 2)
+ elseif registry[target] then
+ return
+ end
+ registry[target] = { name = name }
+ lib:_EnhanceDatabase("EnhanceDatabase", target)
+ target.RegisterCallback(lib, "OnDatabaseReset", "_EnhanceDatabase")
+end
+
+-- ----------------------------------------------------------------------------
+-- AceDBOptions-3.0 support
+-- ----------------------------------------------------------------------------
+
+local function NoDualSpec()
+ return GetNumTalentGroups() == 1
+end
+
+options.dualSpecDesc = {
+ name = L_DUALSPEC_DESC,
+ type = 'description',
+ order = 40.1,
+ hidden = NoDualSpec,
+}
+
+options.enabled = {
+ name = L_ENABLED,
+ desc = L_ENABLED_DESC,
+ type = 'toggle',
+ order = 40.2,
+ get = function(info) return info.handler.db:IsDualSpecEnabled() end,
+ set = function(info, value) info.handler.db:SetDualSpecEnabled(value) end,
+ hidden = NoDualSpec,
+}
+
+options.dualProfile = {
+ name = L_DUAL_PROFILE,
+ desc = L_DUAL_PROFILE_DESC,
+ type = 'select',
+ order = 40.3,
+ get = function(info) return info.handler.db:GetDualSpecProfile() end,
+ set = function(info, value) info.handler.db:SetDualSpecProfile(value) end,
+ values = "ListProfiles",
+ arg = "common",
+ hidden = NoDualSpec,
+ disabled = function(info) return not info.handler.db:IsDualSpecEnabled() end,
+}
+
+--- Embed dual spec options into an existing AceDBOptions-3.0 option table.
+-- @name LibDualSpec:EnhanceOptions
+-- @param optionTable (table) The option table returned by AceDBOptions-3.0.
+-- @param target (table) The AceDB-3.0 the options operate on.
+function lib:EnhanceOptions(optionTable, target)
+ AceDBOptions3 = AceDBOptions3 or LibStub('AceDBOptions-3.0', true)
+ if type(optionTable) ~= "table" then
+ error("Usage: LibDualSpec:EnhanceOptions(optionTable, target): optionTable should be a table.", 2)
+ elseif type(target) ~= "table" then
+ error("Usage: LibDualSpec:EnhanceOptions(optionTable, target): target should be a table.", 2)
+ elseif not (AceDBOptions3 and AceDBOptions3.optionTables[target]) then
+ error("Usage: LibDualSpec:EnhanceOptions(optionTable, target): optionTable is not an AceDBOptions-3.0 table.", 2)
+ elseif optionTable.handler.db ~= target then
+ error("Usage: LibDualSpec:EnhanceOptions(optionTable, target): optionTable must be the option table of target.", 2)
+ elseif not registry[target] then
+ error("Usage: LibDualSpec:EnhanceOptions(optionTable, target): EnhanceDatabase should be called before EnhanceOptions(optionTable, target).", 2)
+ elseif optionTable.plugins and optionTable.plugins[MAJOR] then
+ return
+ end
+ if not optionTable.plugins then
+ optionTable.plugins = {}
+ end
+ optionTable.plugins[MAJOR] = options
+end
+
+-- ----------------------------------------------------------------------------
+-- Inspection
+-- ----------------------------------------------------------------------------
+
+local function iterator(registry, key)
+ local data
+ key, data = next(registry, key)
+ if key then
+ return key, data.name
+ end
+end
+
+--- Iterate through enhanced AceDB3.0 instances.
+-- The iterator returns (instance, name) pairs where instance and name are the
+-- arguments that were provided to lib:EnhanceDatabase.
+-- @name LibDualSpec:IterateDatabases
+-- @return Values to be used in a for .. in .. do statement.
+function lib:IterateDatabases()
+ return iterator, lib.registry
+end
+
+-- ----------------------------------------------------------------------------
+-- Switching logic
+-- ----------------------------------------------------------------------------
+
+lib.eventFrame:RegisterEvent('PLAYER_TALENT_UPDATE')
+lib.eventFrame:SetScript('OnEvent', function()
+ local newTalentGroup = GetActiveTalentGroup()
+ if lib.talentGroup ~= newTalentGroup then
+ lib.talentGroup = newTalentGroup
+ for target in pairs(registry) do
+ target:CheckDualSpecState()
+ end
+ end
+end)
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibElvUIPlugin-1.0/LibElvUIPlugin-1.0.lua b/ElvUI/Libraries/LibElvUIPlugin-1.0/LibElvUIPlugin-1.0.lua
new file mode 100644
index 0000000..e0827d7
--- /dev/null
+++ b/ElvUI/Libraries/LibElvUIPlugin-1.0/LibElvUIPlugin-1.0.lua
@@ -0,0 +1,335 @@
+local MAJOR, MINOR = "LibElvUIPlugin-1.0", 31
+local lib = LibStub:NewLibrary(MAJOR, MINOR)
+if not lib then return end
+-- GLOBALS: ElvUI
+
+--[[----------------------------
+Plugin Table Format: (for reference only).
+ {
+ name - name of the plugin
+ callback - callback to call when ElvUI_OptionsUI is loaded
+ isLib - plugin is a library
+ version - version of the plugin (pulls version info from metadata, libraries can define their own)
+
+ -- After new version recieved from another user:
+ old - plugin is old version
+ newversion - newer version number
+ }
+
+LibElvUIPlugin API:
+ RegisterPlugin(name, callback, isLib, libVersion)
+ -- Registers a module with the given name and option callback:
+ name - name of plugin
+ verion - version number
+ isLib - plugin is a library
+ libVersion - plugin library version (optional, defaults to 1)
+
+ HookInitialize(table, function)
+ -- Posthook ElvUI Initialize function:
+ table - addon table
+ function - function to call after Initialize (may be a string, that exists on the addons table: table['string'])
+----------------------------]]--
+
+local pairs, ipairs = pairs, ipairs
+local tonumber, type = tonumber, type
+local ceil = math.ceil
+local format, gmatch, gsub, len, match, sub = string.format, string.gmatch, string.gsub, string.len, string.match, string.sub
+local tinsert, wipe = table.insert, table.wipe
+
+local GetAddOnMetadata = GetAddOnMetadata
+local GetNumPartyMembers = GetNumRaidMembers
+local GetNumRaidMembers = GetNumRaidMembers
+local IsAddOnLoaded = IsAddOnLoaded
+local IsInInstance = IsInInstance
+local SendAddonMessage = SendAddonMessage
+
+local UNKNOWN = UNKNOWN
+
+lib.prefix = "ElvUIPluginVC"
+lib.plugins = {}
+lib.groupSize = 0
+lib.index = 0
+
+local MSG_OUTDATED = "Your version of %s %s is out of date (latest is version %s). You can download the latest version from https://github.com/BanditTech/ElvUI-Ascension/"
+local HDR_CONFIG = "Plugins"
+local HDR_INFORMATION = "LibElvUIPlugin-1.0.%d - Plugins Loaded (Green means you have current version, Red means out of date)"
+local INFO_BY = "by"
+local INFO_VERSION = "Version:"
+local INFO_NEW = "Newest:"
+local LIBRARY = "Library"
+
+local locale = GetLocale()
+if locale == "deDE" then
+ MSG_OUTDATED = "Deine Version von %s %s ist veraltet (akutelle Version ist %s). Du kannst die aktuelle Version von https://github.com/BanditTech/ElvUI-Ascension/ herunterrladen."
+ HDR_CONFIG = "Plugins"
+ HDR_INFORMATION = "LibElvUIPlugin-1.0.%d - Plugins geladen (Grün bedeutet du hast die aktuelle Version, Rot bedeutet es ist veraltet)"
+ INFO_BY = "von"
+ INFO_VERSION = "Version:"
+ INFO_NEW = "Neuste:"
+ LIBRARY = "Bibliothek"
+elseif locale == "ruRU" then
+ MSG_OUTDATED = "Ваша версия %s %s устарела (последняя версия %s). Вы можете скачать последнюю версию на https://github.com/BanditTech/ElvUI-Ascension/"
+ HDR_CONFIG = "Плагины"
+ HDR_INFORMATION = "LibElvUIPlugin-1.0.%d - загруженные плагины (зеленый означает, что у вас последняя версия, красный - устаревшая)"
+ INFO_BY = "от"
+ INFO_VERSION = "Версия:"
+ INFO_NEW = "Последняя:"
+ LIBRARY = "Библиотека"
+elseif locale == "zhCN" then
+ MSG_OUTDATED = "你的 %s %s 版本已经过期 (最新版本是 %s)。你可以从 https://github.com/BanditTech/ElvUI-Ascension/ 下载最新版本"
+ HDR_CONFIG = "插件"
+ HDR_INFORMATION = "LibElvUIPlugin-1.0.%d - 载入的插件 (绿色表示拥有当前版本, 红色表示版本已经过期)"
+ INFO_BY = "作者"
+ INFO_VERSION = "版本:"
+ INFO_NEW = "最新:"
+ LIBRARY = "库"
+elseif locale == "zhTW" then
+ MSG_OUTDATED = "你的 %s %s 版本已經過期 (最新版本為 %s)。你可以透過 https://github.com/BanditTech/ElvUI-Ascension/ 下載最新的版本"
+ HDR_CONFIG = "插件"
+ HDR_INFORMATION = "LibElvUIPlugin-1.0.%d - 載入的插件 (綠色表示擁有當前版本, 紅色表示版本已經過期)"
+ INFO_BY = "作者"
+ INFO_VERSION = "版本:"
+ INFO_NEW = "最新:"
+ LIBRARY = "庫"
+end
+
+local E
+local function checkElvUI()
+ if not E then
+ E = ElvUI[1]
+ assert(E, "ElvUI not found.")
+ end
+end
+
+function lib:RegisterPlugin(name, callback, isLib, libVersion)
+ checkElvUI()
+
+ local plugin = {
+ name = name,
+ callback = callback
+ }
+
+ if isLib then
+ plugin.isLib = true
+ plugin.version = libVersion or 1
+ else
+ plugin.version = (name == MAJOR and MINOR) or GetAddOnMetadata(name, "Version") or UNKNOWN
+ end
+
+ lib.plugins[name] = plugin
+
+ if not lib.registeredPrefix and E.global.general.versionCheck then
+ lib.VCFrame:RegisterEvent("CHAT_MSG_ADDON")
+ lib.VCFrame:RegisterEvent("RAID_ROSTER_UPDATE")
+ lib.VCFrame:RegisterEvent("PARTY_MEMBERS_CHANGED")
+ lib.VCFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
+ lib.registeredPrefix = true
+ end
+
+ local loaded = IsAddOnLoaded("ElvUI_OptionsUI")
+ if not loaded then
+ lib.CFFrame:RegisterEvent("ADDON_LOADED")
+ elseif loaded then
+ if name ~= MAJOR then
+ E.Options.args.plugins.args.plugins.name = lib:GeneratePluginList()
+ end
+
+ if callback then
+ callback()
+ end
+ end
+
+ return plugin
+end
+
+local function SendVersionCheckMessage()
+ lib:SendPluginVersionCheck(lib:GenerateVersionCheckMessage())
+end
+
+function lib:DelayedSendVersionCheck(delay)
+ if not E.SendPluginVersionCheck then
+ E.SendPluginVersionCheck = SendVersionCheckMessage
+ end
+
+ if not lib.SendMessageWaiting then
+ lib.SendMessageWaiting = E:Delay(delay or 10, E.SendPluginVersionCheck)
+ end
+end
+
+function lib:OptionsUILoaded(_, addon)
+ if addon == "ElvUI_OptionsUI" then
+ lib:GetPluginOptions()
+
+ for _, plugin in pairs(lib.plugins) do
+ if plugin.callback then
+ plugin.callback()
+ end
+ end
+
+ lib.CFFrame:UnregisterEvent("ADDON_LOADED")
+ end
+end
+
+function lib:GenerateVersionCheckMessage()
+ local list = ""
+ for _, plugin in pairs(lib.plugins) do
+ if plugin.name ~= MAJOR then
+ list = list .. plugin.name .. "=" .. plugin.version .. ";"
+ end
+ end
+ return list
+end
+
+function lib:GetPluginOptions()
+ E.Options.args.plugins = {
+ order = -10,
+ type = "group",
+ name = HDR_CONFIG,
+ guiInline = false,
+ args = {
+ pluginheader = {
+ order = 1,
+ type = "header",
+ name = format(HDR_INFORMATION, MINOR)
+ },
+ plugins = {
+ order = 2,
+ type = "description",
+ name = lib:GeneratePluginList()
+ }
+ }
+ }
+end
+
+do -- this will handle `8.1.5.0015` into `8.150015` etc
+ local verStrip = function(a, b) return a..gsub(b, "%.", "") end
+ function lib:StripVersion(version)
+ local ver = gsub(version, "(%d-%.)([%d%.]+)", verStrip)
+ return tonumber(ver)
+ end
+end
+
+function lib:VersionCheck(event, prefix, message, _, sender)
+ if (event == "CHAT_MSG_ADDON" and prefix == lib.prefix) and (sender and message and not match(message, "^%s-$")) then
+ if sender == E.myname then return end
+
+ if not E.pluginRecievedOutOfDateMessage then
+ for name, version in gmatch(message, "([^=]+)=([%d%p]+);") do
+ local plugin = (version and name) and lib.plugins[name]
+ if plugin and plugin.version then
+ local Pver, ver = lib:StripVersion(plugin.version), lib:StripVersion(version)
+ if (ver and Pver) and (ver > Pver) then
+ plugin.old, plugin.newversion = true, version
+ local title = GetAddOnMetadata(plugin.name, "Title") or plugin.name
+ E:Print(format(MSG_OUTDATED, title, plugin.version, plugin.newversion))
+ E.pluginRecievedOutOfDateMessage = true
+ end
+ end
+ end
+ end
+ elseif event == "PLAYER_ENTERING_WORLD" then
+ lib:DelayedSendVersionCheck()
+ else
+ local numRaid = GetNumRaidMembers()
+ local num = numRaid > 0 and numRaid or (GetNumPartyMembers() + 1)
+
+ if num ~= lib.groupSize then
+ if num > 1 and num > lib.groupSize then
+ lib:DelayedSendVersionCheck()
+ end
+ lib.groupSize = num
+ end
+ end
+end
+
+function lib:GeneratePluginList()
+ local list = ""
+ for _, plugin in pairs(lib.plugins) do
+ if plugin.name ~= MAJOR then
+ local author = GetAddOnMetadata(plugin.name, "Author")
+ local title = GetAddOnMetadata(plugin.name, "Title") or plugin.name
+ local color = (plugin.old and E:RGBToHex(1, 0, 0)) or E:RGBToHex(0, 1, 0)
+ list = list .. title
+ if author then list = list .. " " .. INFO_BY .. " " .. author end
+ list = list .. color .. (plugin.isLib and " " .. LIBRARY or " - " .. INFO_VERSION .. " " .. plugin.version)
+ if plugin.old then list = list .. " (" .. INFO_NEW .. plugin.newversion .. ")" end
+ list = list .. "|r\n"
+ end
+ end
+ return list
+end
+
+function lib:ClearSendMessageWait()
+ lib.SendMessageWaiting = nil
+end
+
+function lib:SendPluginVersionCheck(message)
+ if (not message) or match(message, "^%s-$") then
+ lib.ClearSendMessageWait()
+ return
+ end
+
+ local ChatType
+ if GetNumRaidMembers() > 1 then
+ local _, instanceType = IsInInstance()
+ ChatType = instanceType == "pvp" and "BATTLEGROUND" or "RAID"
+ elseif GetNumPartyMembers() > 0 then
+ ChatType = "PARTY"
+ end
+
+ if not ChatType then
+ lib.ClearSendMessageWait()
+ return
+ end
+
+ local maxChar, msgLength = 254 - len(lib.prefix), len(message)
+ if msgLength > maxChar then
+ local delay, splitMessage = 0
+
+ for _ = 1, ceil(msgLength / maxChar) do
+ splitMessage = match(sub(message, 1, maxChar), ".+;")
+ if splitMessage then -- incase the string is over `maxChar` but doesnt contain `;`
+ message = gsub(message, "^"..gsub(splitMessage, "([%-%.%+%[%]%(%)%$%^%%%?%*])", "%%%1"), "")
+ E:Delay(delay, SendAddonMessage, lib.prefix, splitMessage, ChatType)
+ delay = delay + 1
+ end
+ end
+
+ E:Delay(delay, lib.ClearSendMessageWait)
+ else
+ SendAddonMessage(lib.prefix, message, ChatType)
+ lib.ClearSendMessageWait()
+ end
+end
+
+function lib.Initialized()
+ if not lib.inits then return end
+
+ for _, initTbl in ipairs(lib.inits) do
+ initTbl[2](initTbl[1])
+ end
+
+ wipe(lib.inits)
+end
+
+function lib:HookInitialize(tbl, func)
+ if not (tbl and func) then return end
+
+ if type(func) == "string" then
+ func = tbl[func]
+ end
+
+ if not self.inits then
+ self.inits = {}
+ checkElvUI()
+ hooksecurefunc(E, "Initialize", self.Initialized)
+ end
+
+ tinsert(lib.inits, {tbl, func})
+end
+
+lib.VCFrame = CreateFrame("Frame")
+lib.VCFrame:SetScript("OnEvent", lib.VersionCheck)
+
+lib.CFFrame = CreateFrame("Frame")
+lib.CFFrame:SetScript("OnEvent", lib.OptionsUILoaded)
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibItemSearch-1.2/CustomSearch-1.0/CustomSearch-1.0.lua b/ElvUI/Libraries/LibItemSearch-1.2/CustomSearch-1.0/CustomSearch-1.0.lua
new file mode 100644
index 0000000..9ff84fb
--- /dev/null
+++ b/ElvUI/Libraries/LibItemSearch-1.2/CustomSearch-1.0/CustomSearch-1.0.lua
@@ -0,0 +1,203 @@
+--[[
+Copyright 2013 João Cardoso
+CustomSearch is distributed under the terms of the GNU General Public License (Version 3).
+As a special exception, the copyright holders of this library give you permission to embed it
+with independent modules to produce an addon, regardless of the license terms of these
+independent modules, and to copy and distribute the resulting software under terms of your
+choice, provided that you also meet, for each embedded independent module, the terms and
+conditions of the license of that module. Permission is not granted to modify this library.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the library. If not, see .
+
+This file is part of CustomSearch.
+--]]
+
+local Lib = LibStub:NewLibrary('CustomSearch-1.0', 9)
+if not Lib then
+ return
+end
+
+
+--[[ Parsing ]]--
+
+function Lib:Matches(object, search, filters)
+ if object then
+ self.filters = filters
+ self.object = object
+
+ return self:MatchAll(search or '')
+ end
+end
+
+function Lib:MatchAll(search)
+ for phrase in self:Clean(search):gmatch('[^&]+') do
+ if not self:MatchAny(phrase) then
+ return
+ end
+ end
+
+ return true
+end
+
+function Lib:MatchAny(search)
+ for phrase in search:gmatch('[^|]+') do
+ if self:Match(phrase) then
+ return true
+ end
+ end
+end
+
+function Lib:Match(search)
+ local tag, rest = search:match('^%s*(%S+):(.*)$')
+ if tag then
+ tag = '^' .. tag
+ search = rest
+ end
+
+ local words = search:gmatch('%S+')
+ local failed
+
+ for word in words do
+ if word == self.OR then
+ if failed then
+ failed = false
+ else
+ break
+ end
+
+ else
+ local negate, rest = word:match('^([!~]=*)(.*)$')
+ if negate or word == self.NOT_MATCH then
+ word = rest and rest ~= '' and rest or words() or ''
+ negate = -1
+ else
+ negate = 1
+ end
+
+ local operator, rest = word:match('^(=*[<>]=*)(.*)$')
+ if operator then
+ word = rest ~= '' and rest or words()
+ end
+
+ local result = self:Filter(tag, operator, word) and 1 or -1
+ if result * negate ~= 1 then
+ failed = true
+ end
+ end
+ end
+
+ return not failed
+end
+
+
+--[[ Filtering ]]--
+
+function Lib:Filter(tag, operator, search)
+ if not search then
+ return true
+ end
+
+ if tag then
+ for _, filter in pairs(self.filters) do
+ for _, value in pairs(filter.tags or {}) do
+ if value:find(tag) then
+ return self:UseFilter(filter, operator, search)
+ end
+ end
+ end
+ else
+ for _, filter in pairs(self.filters) do
+ if not filter.onlyTags and self:UseFilter(filter, operator, search) then
+ return true
+ end
+ end
+ end
+end
+
+function Lib:UseFilter(filter, operator, search)
+ local data = {filter:canSearch(operator, search, self.object)}
+ if data[1] then
+ return filter:match(self.object, operator, unpack(data))
+ end
+end
+
+
+--[[ Utilities ]]--
+
+function Lib:Find(search, ...)
+ for i = 1, select('#', ...) do
+ local text = select(i, ...)
+ if text and self:Clean(text):find(search) then
+ return true
+ end
+ end
+end
+
+function Lib:Clean(string)
+ string = string:lower()
+ string = string:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', function(c) return '%'..c end)
+
+ for accent, char in pairs(self.ACCENTS) do
+ string = string:gsub(accent, char)
+ end
+
+ return string
+end
+
+function Lib:Compare(op, a, b)
+ if op then
+ if op:find('<') then
+ if op:find('=') then
+ return a <= b
+ end
+
+ return a < b
+ end
+
+ if op:find('>')then
+ if op:find('=') then
+ return a >= b
+ end
+
+ return a > b
+ end
+ end
+
+ return a == b
+end
+
+
+--[[ Localization ]]--
+
+do
+ local no = {enUS = 'Not', frFR = 'Pas', deDE = 'Nicht', ruRU = 'Нет'}
+ local just_or = {enUS = 'Or', frFR = 'Ou', deDE = 'Oder', ruRU = 'Или'}
+ local accents = {
+ a = {'à','â','ã','å'},
+ e = {'è','é','ê','ê','ë'},
+ i = {'ì', 'í', 'î', 'ï'},
+ o = {'ó','ò','ô','õ'},
+ u = {'ù', 'ú', 'û', 'ü'},
+ c = {'ç'}, n = {'ñ'}
+ }
+
+ Lib.ACCENTS = {}
+ for char, accents in pairs(accents) do
+ for _, accent in ipairs(accents) do
+ Lib.ACCENTS[accent] = char
+ end
+ end
+
+ Lib.OR = Lib:Clean(just_or[GetLocale()] or "")
+ Lib.NOT = no[GetLocale()] or NO
+ Lib.NOT_MATCH = Lib:Clean(Lib.NOT)
+ setmetatable(Lib, {__call = Lib.Matches})
+end
+
+return Lib
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibItemSearch-1.2/LibItemSearch-1.2.lua b/ElvUI/Libraries/LibItemSearch-1.2/LibItemSearch-1.2.lua
new file mode 100644
index 0000000..edcc8ff
--- /dev/null
+++ b/ElvUI/Libraries/LibItemSearch-1.2/LibItemSearch-1.2.lua
@@ -0,0 +1,287 @@
+--[[
+ ItemSearch
+ An item text search engine of some sort
+--]]
+
+local Search = LibStub("CustomSearch-1.0")
+local Unfit = LibStub("Unfit-1.0")
+local Lib = LibStub:NewLibrary("LibItemSearch-1.2-ElvUI", 17)
+if Lib then
+ Lib.Scanner = LibItemSearchTooltipScanner or CreateFrame("GameTooltip", "LibItemSearchTooltipScanner", UIParent, "GameTooltipTemplate")
+ Lib.Filters = {}
+else
+ return
+end
+
+--[[ User API ]]--
+
+function Lib:Matches(link, search)
+ return Search(link, search, self.Filters)
+end
+
+function Lib:Tooltip(link, search)
+ return link and self.Filters.tip:match(link, nil, search)
+end
+
+function Lib:TooltipPhrase(link, search)
+ return link and self.Filters.tipPhrases:match(link, nil, search)
+end
+
+function Lib:InSet(link, search)
+ if IsEquippableItem(link) then
+ local id = tonumber(link:match("item:(%-?%d+)"))
+ return self:BelongsToSet(id, (search or ""):lower())
+ end
+end
+
+--[[ Internal API ]]--
+
+if IsAddOnLoaded("ItemRack") then
+ local sameID = ItemRack.SameID
+
+ function Lib:BelongsToSet(id, search)
+ for name, set in pairs(ItemRackUser.Sets) do
+ if name:sub(1,1) ~= "" and Search:Find(search, name) then
+ for _, item in pairs(set.equip) do
+ if sameID(id, item) then
+ return true
+ end
+ end
+ end
+ end
+ end
+
+elseif IsAddOnLoaded("Wardrobe") then
+ function Lib:BelongsToSet(id, search)
+ for _, outfit in ipairs(Wardrobe.CurrentConfig.Outfit) do
+ local name = outfit.OutfitName
+ if Search:Find(search, name) then
+ for _, item in pairs(outfit.Item) do
+ if item.IsSlotUsed == 1 and item.ItemID == id then
+ return true
+ end
+ end
+ end
+ end
+ end
+
+else
+ function Lib:BelongsToSet(id, search)
+ for i = 1, GetNumEquipmentSets() do
+ local name = GetEquipmentSetInfo(i)
+ if Search:Find(search, name) then
+ local items = GetEquipmentSetItemIDs(name)
+ for _, item in pairs(items) do
+ if id == item then
+ return true
+ end
+ end
+ end
+ end
+ end
+end
+
+--[[ General ]]--
+
+Lib.Filters.name = {
+ tags = {"n", "name"},
+
+ canSearch = function(self, operator, search)
+ return not operator and search
+ end,
+
+ match = function(self, item, _, search)
+ local name = item:match("%[(.-)%]")
+ return Search:Find(search, name)
+ end
+}
+
+Lib.Filters.type = {
+ tags = {"t", "type", "s", "slot"},
+
+ canSearch = function(self, operator, search)
+ return not operator and search
+ end,
+
+ match = function(self, item, _, search)
+ local type, subType, _, equipSlot = select(6, GetItemInfo(item))
+ return Search:Find(search, type, subType, _G[equipSlot])
+ end
+}
+
+Lib.Filters.level = {
+ tags = {"l", "level", "lvl", "ilvl"},
+
+ canSearch = function(self, _, search)
+ return tonumber(search)
+ end,
+
+ match = function(self, link, operator, num)
+ local lvl = select(4, GetItemInfo(link))
+ if lvl then
+ return Search:Compare(operator, lvl, num)
+ end
+ end
+}
+
+Lib.Filters.requiredlevel = {
+ tags = {"r", "req", "rl", "reql", "reqlvl"},
+
+ canSearch = function(self, _, search)
+ return tonumber(search)
+ end,
+
+ match = function(self, link, operator, num)
+ local lvl = select(5, GetItemInfo(link))
+ if lvl then
+ return Search:Compare(operator, lvl, num)
+ end
+ end
+}
+
+Lib.Filters.sets = {
+ tags = {"s", "set"},
+
+ canSearch = function(self, operator, search)
+ return not operator and search
+ end,
+
+ match = function(self, link, _, search)
+ return Lib:InSet(link, search)
+ end,
+}
+
+Lib.Filters.quality = {
+ tags = {"q", "quality"},
+ keywords = {},
+
+ canSearch = function(self, _, search)
+ for quality, name in pairs(self.keywords) do
+ if name:find(search) then
+ return quality
+ end
+ end
+ end,
+
+ match = function(self, link, operator, num)
+ local quality = select(3, GetItemInfo(link))
+ return Search:Compare(operator, quality, num)
+ end,
+}
+
+--[[
+ 0 Poor 9d9d9d
+ 1 Common ffffff
+ 2 Uncommon 1eff00
+ 3 Rare 0070dd
+ 4 Epic a335ee
+ 5 Legendary ff8000
+ 6 Artifact e6cc80
+ 7 Heirloom 00ccff
+]]
+for i = 0, 7 do -- Ascension change: was `#ITEM_QUALITY_COLORS` now `7`
+ Lib.Filters.quality.keywords[i] = _G["ITEM_QUALITY" .. i .. "_DESC"]:lower()
+end
+
+--[[ Classic Keywords ]]--
+
+Lib.Filters.items = {
+ keyword = ITEMS:lower(),
+
+ canSearch = function(self, operator, search)
+ return not operator and self.keyword:find(search)
+ end,
+
+ match = function(self, link)
+ return true
+ end
+}
+
+Lib.Filters.usable = {
+ keyword = USABLE_ITEMS:lower(),
+
+ canSearch = function(self, operator, search)
+ return not operator and self.keyword:find(search)
+ end,
+
+ match = function(self, link)
+ if not Unfit:IsItemUnusable(link) then
+ local lvl = select(5, GetItemInfo(link))
+ return lvl and (lvl ~= 0 and lvl <= UnitLevel("player"))
+ end
+ end
+}
+
+--[[ Tooltips ]]--
+
+Lib.Filters.tip = {
+ tags = {"tt", "tip", "tooltip"},
+ onlyTags = true,
+
+ canSearch = function(self, _, search)
+ return search
+ end,
+
+ match = function(self, link, _, search)
+ if link:find("item:") then
+ Lib.Scanner:SetOwner(UIParent, "ANCHOR_NONE")
+ Lib.Scanner:SetHyperlink(link)
+
+ for i = 1, Lib.Scanner:NumLines() do
+ if Search:Find(search, _G[Lib.Scanner:GetName() .. "TextLeft" .. i]:GetText()) then
+ return true
+ end
+ end
+ end
+ end
+}
+
+Lib.Filters.tipPhrases = {
+ canSearch = function(self, _, search)
+ if #search >= 3 then
+ for key, query in pairs(self.keywords) do
+ if key:find(search) then
+ return query
+ end
+ end
+ end
+ end,
+
+ match = function(self, link, _, search)
+ local id = link:match("item:(%d+)")
+ if not id then
+ return
+ end
+
+ local cached = self.cache[search][id]
+ if cached ~= nil then
+ return cached
+ end
+
+ Lib.Scanner:SetOwner(UIParent, "ANCHOR_NONE")
+ Lib.Scanner:SetHyperlink(link)
+
+ local matches = false
+ for i = 1, Lib.Scanner:NumLines() do
+ if search == _G[Lib.Scanner:GetName() .. "TextLeft" .. i]:GetText() then
+ matches = true
+ break
+ end
+ end
+
+ self.cache[search][id] = matches
+ return matches
+ end,
+
+ cache = setmetatable({}, {__index = function(t, k) local v = {} t[k] = v return v end}),
+ keywords = {
+ [ITEM_SOULBOUND:lower()] = ITEM_BIND_ON_PICKUP,
+ [QUESTS_LABEL:lower()] = ITEM_BIND_QUEST,
+
+ ["bound"] = ITEM_BIND_ON_PICKUP,
+ ["bop"] = ITEM_BIND_ON_PICKUP,
+ ["boe"] = ITEM_BIND_ON_EQUIP,
+ ["bou"] = ITEM_BIND_ON_USE,
+ ["boa"] = ITEM_BIND_TO_ACCOUNT,
+ }
+}
diff --git a/ElvUI/Libraries/LibItemSearch-1.2/LibItemSearch-1.2.xml b/ElvUI/Libraries/LibItemSearch-1.2/LibItemSearch-1.2.xml
new file mode 100644
index 0000000..1256827
--- /dev/null
+++ b/ElvUI/Libraries/LibItemSearch-1.2/LibItemSearch-1.2.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibItemSearch-1.2/Unfit-1.0/Unfit-1.0.lua b/ElvUI/Libraries/LibItemSearch-1.2/Unfit-1.0/Unfit-1.0.lua
new file mode 100644
index 0000000..9d1a2b3
--- /dev/null
+++ b/ElvUI/Libraries/LibItemSearch-1.2/Unfit-1.0/Unfit-1.0.lua
@@ -0,0 +1,40 @@
+--[[
+Copyright 2011-2016 João Cardoso
+Unfit is distributed under the terms of the GNU General Public License (Version 3).
+As a special exception, the copyright holders of this library give you permission to embed it
+with independent modules to produce an addon, regardless of the license terms of these
+independent modules, and to copy and distribute the resulting software under terms of your
+choice, provided that you also meet, for each embedded independent module, the terms and
+conditions of the license of that module. Permission is not granted to modify this library.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the library. If not, see .
+
+This file is part of Unfit.
+--]]
+
+local Lib = LibStub:NewLibrary('Unfit-1.0', 9)
+if not Lib then
+ return
+end
+
+
+--[[ Data ]]--
+
+Lib.unusable = {}
+Lib.cannotDual = nil
+
+--[[ API ]]--
+
+function Lib:IsItemUnusable(...)
+ return false
+end
+
+function Lib:IsClassUnusable(subclass, slot)
+ return false
+end
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibSharedMedia-3.0/LibSharedMedia-3.0.lua b/ElvUI/Libraries/LibSharedMedia-3.0/LibSharedMedia-3.0.lua
new file mode 100644
index 0000000..1b24822
--- /dev/null
+++ b/ElvUI/Libraries/LibSharedMedia-3.0/LibSharedMedia-3.0.lua
@@ -0,0 +1,245 @@
+--[[
+Name: LibSharedMedia-3.0
+Revision: $Revision: 62 $
+Author: Elkano (elkano@gmx.de)
+Inspired By: SurfaceLib by Haste/Otravi (troeks@gmail.com)
+Website: http://www.wowace.com/projects/libsharedmedia-3-0/
+Description: Shared handling of media data (fonts, sounds, textures, ...) between addons.
+Dependencies: LibStub, CallbackHandler-1.0
+License: LGPL v2.1
+]]
+
+local MAJOR, MINOR = "LibSharedMedia-3.0", 3030001 -- 3.3.5 / increase manually on changes
+local lib = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not lib then return end
+
+local _G = getfenv(0)
+
+local pairs = _G.pairs
+local type = _G.type
+
+local band = _G.bit.band
+local table_sort = _G.table.sort
+
+local locale = GetLocale()
+local locale_is_western
+local LOCALE_MASK = 0
+lib.LOCALE_BIT_koKR = 1
+lib.LOCALE_BIT_ruRU = 2
+lib.LOCALE_BIT_zhCN = 4
+lib.LOCALE_BIT_zhTW = 8
+lib.LOCALE_BIT_western = 128
+
+local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
+
+lib.callbacks = lib.callbacks or CallbackHandler:New(lib)
+
+lib.DefaultMedia = lib.DefaultMedia or {}
+lib.MediaList = lib.MediaList or {}
+lib.MediaTable = lib.MediaTable or {}
+lib.MediaType = lib.MediaType or {}
+lib.OverrideMedia = lib.OverrideMedia or {}
+
+local defaultMedia = lib.DefaultMedia
+local mediaList = lib.MediaList
+local mediaTable = lib.MediaTable
+local overrideMedia = lib.OverrideMedia
+
+
+-- create mediatype constants
+lib.MediaType.BACKGROUND = "background" -- background textures
+lib.MediaType.BORDER = "border" -- border textures
+lib.MediaType.FONT = "font" -- fonts
+lib.MediaType.STATUSBAR = "statusbar" -- statusbar textures
+lib.MediaType.SOUND = "sound" -- sound files
+
+-- populate lib with default Blizzard data
+-- BACKGROUND
+if not lib.MediaTable.background then lib.MediaTable.background = {} end
+lib.MediaTable.background["None"] = [[]]
+lib.MediaTable.background["Blizzard Dialog Background"] = [[Interface\DialogFrame\UI-DialogBox-Background]]
+lib.MediaTable.background["Blizzard Dialog Background Dark"] = [[Interface\DialogFrame\UI-DialogBox-Background-Dark]]
+lib.MediaTable.background["Blizzard Dialog Background Gold"] = [[Interface\DialogFrame\UI-DialogBox-Gold-Background]]
+lib.MediaTable.background["Blizzard Low Health"] = [[Interface\FullScreenTextures\LowHealth]]
+lib.MediaTable.background["Blizzard Marble"] = [[Interface\FrameGeneral\UI-Background-Marble]]
+lib.MediaTable.background["Blizzard Out of Control"] = [[Interface\FullScreenTextures\OutOfControl]]
+lib.MediaTable.background["Blizzard Parchment"] = [[Interface\AchievementFrame\UI-Achievement-Parchment-Horizontal]]
+lib.MediaTable.background["Blizzard Parchment 2"] = [[Interface\AchievementFrame\UI-GuildAchievement-Parchment-Horizontal]]
+lib.MediaTable.background["Blizzard Rock"] = [[Interface\FrameGeneral\UI-Background-Rock]]
+lib.MediaTable.background["Blizzard Tabard Background"] = [[Interface\TabardFrame\TabardFrameBackground]]
+lib.MediaTable.background["Blizzard Tooltip"] = [[Interface\Tooltips\UI-Tooltip-Background]]
+lib.MediaTable.background["Solid"] = [[Interface\Buttons\WHITE8X8]]
+lib.DefaultMedia.background = "None"
+
+-- BORDER
+if not lib.MediaTable.border then lib.MediaTable.border = {} end
+lib.MediaTable.border["None"] = [[]]
+lib.MediaTable.border["Blizzard Achievement Wood"] = [[Interface\AchievementFrame\UI-Achievement-WoodBorder]]
+lib.MediaTable.border["Blizzard Chat Bubble"] = [[Interface\Tooltips\ChatBubble-Backdrop]]
+lib.MediaTable.border["Blizzard Dialog"] = [[Interface\DialogFrame\UI-DialogBox-Border]]
+lib.MediaTable.border["Blizzard Dialog Gold"] = [[Interface\DialogFrame\UI-DialogBox-Gold-Border]]
+lib.MediaTable.border["Blizzard Party"] = [[Interface\CHARACTERFRAME\UI-Party-Border]]
+lib.MediaTable.border["Blizzard Tooltip"] = [[Interface\Tooltips\UI-Tooltip-Border]]
+lib.DefaultMedia.border = "None"
+
+-- FONT
+if not lib.MediaTable.font then lib.MediaTable.font = {} end
+local SML_MT_font = lib.MediaTable.font
+if locale == "koKR" then
+ LOCALE_MASK = lib.LOCALE_BIT_koKR
+--
+ SML_MT_font["굵은 글꼴"] = [[Fonts\2002B.TTF]]
+ SML_MT_font["기본 글꼴"] = [[Fonts\2002.TTF]]
+ SML_MT_font["데미지 글꼴"] = [[Fonts\K_Damage.TTF]]
+ SML_MT_font["퀘스트 글꼴"] = [[Fonts\K_Pagetext.TTF]]
+--
+ lib.DefaultMedia["font"] = "기본 글꼴" -- someone from koKR please adjust if needed
+--
+elseif locale == "zhCN" then
+ LOCALE_MASK = lib.LOCALE_BIT_zhCN
+--
+ SML_MT_font["伤害数字"] = [[Fonts\ZYKai_C.ttf]]
+ SML_MT_font["默认"] = [[Fonts\ZYKai_T.ttf]]
+ SML_MT_font["聊天"] = [[Fonts\ZYHei.ttf]]
+--
+ lib.DefaultMedia["font"] = "默认" -- someone from zhCN please adjust if needed
+--
+elseif locale == "zhTW" then
+ LOCALE_MASK = lib.LOCALE_BIT_zhTW
+--
+ SML_MT_font["提示訊息"] = [[Fonts\bHEI00M.ttf]]
+ SML_MT_font["聊天"] = [[Fonts\bHEI01B.ttf]]
+ SML_MT_font["傷害數字"] = [[Fonts\bKAI00M.ttf]]
+ SML_MT_font["預設"] = [[Fonts\bLEI00D.ttf]]
+--
+ lib.DefaultMedia["font"] = "預設" -- someone from zhTW please adjust if needed
+
+elseif locale == "ruRU" then
+ LOCALE_MASK = lib.LOCALE_BIT_ruRU
+--
+ SML_MT_font["Arial Narrow"] = [[Fonts\ARIALN.TTF]]
+ SML_MT_font["Friz Quadrata TT"] = [[Fonts\FRIZQT__.TTF]]
+ SML_MT_font["Morpheus"] = [[Fonts\MORPHEUS.TTF]]
+ SML_MT_font["Nimrod MT"] = [[Fonts\NIM_____.ttf]]
+ SML_MT_font["Skurri"] = [[Fonts\SKURRI.TTF]]
+--
+ lib.DefaultMedia.font = "Arial Narrow"
+--
+else
+ LOCALE_MASK = lib.LOCALE_BIT_western
+ locale_is_western = true
+--
+ SML_MT_font["Arial Narrow"] = [[Fonts\ARIALN.TTF]]
+ SML_MT_font["Friz Quadrata TT"] = [[Fonts\FRIZQT__.TTF]]
+ SML_MT_font["Morpheus"] = [[Fonts\MORPHEUS.TTF]]
+ SML_MT_font["Skurri"] = [[Fonts\SKURRI.TTF]]
+--
+ lib.DefaultMedia.font = "Friz Quadrata TT"
+--
+end
+
+-- STATUSBAR
+if not lib.MediaTable.statusbar then lib.MediaTable.statusbar = {} end
+lib.MediaTable.statusbar["Blizzard"] = [[Interface\TargetingFrame\UI-StatusBar]]
+lib.MediaTable.statusbar["Blizzard Character Skills Bar"] = [[Interface\PaperDollInfoFrame\UI-Character-Skills-Bar]]
+lib.DefaultMedia.statusbar = "Blizzard"
+
+-- SOUND
+if not lib.MediaTable.sound then lib.MediaTable.sound = {} end
+lib.MediaTable.sound["None"] = [[Interface\Quiet.ogg]] -- Relies on the fact that PlaySound[File] doesn't error on these values.
+lib.DefaultMedia.sound = "None"
+
+local function rebuildMediaList(mediatype)
+ local mtable = mediaTable[mediatype]
+ if not mtable then return end
+ if not mediaList[mediatype] then mediaList[mediatype] = {} end
+ local mlist = mediaList[mediatype]
+ -- list can only get larger, so simply overwrite it
+ local i = 0
+ for k in pairs(mtable) do
+ i = i + 1
+ mlist[i] = k
+ end
+ table_sort(mlist)
+end
+
+function lib:Register(mediatype, key, data, langmask)
+ if type(mediatype) ~= "string" then
+ error(MAJOR..":Register(mediatype, key, data, langmask) - mediatype must be string, got "..type(mediatype))
+ end
+ if type(key) ~= "string" then
+ error(MAJOR..":Register(mediatype, key, data, langmask) - key must be string, got "..type(key))
+ end
+ mediatype = mediatype:lower()
+ if mediatype == lib.MediaType.FONT and ((langmask and band(langmask, LOCALE_MASK) == 0) or not (langmask or locale_is_western)) then
+ -- ignore fonts that aren't flagged as supporting local glyphs on non-western clients
+ return false
+ end
+ if mediatype == lib.MediaType.SOUND and type(data) == "string" then
+ local path = data:lower()
+ if not path:find(".ogg", nil, true) and not path:find(".mp3", nil, true) and not path:find(".wav", nil, true) then
+ -- Only wav, ogg and mp3 are valid sounds.
+ return false
+ end
+ end
+ if not mediaTable[mediatype] then mediaTable[mediatype] = {} end
+ local mtable = mediaTable[mediatype]
+ if mtable[key] then return false end
+
+ mtable[key] = data
+ rebuildMediaList(mediatype)
+ self.callbacks:Fire("LibSharedMedia_Registered", mediatype, key)
+ return true
+end
+
+function lib:Fetch(mediatype, key, noDefault)
+ local mtt = mediaTable[mediatype]
+ local overridekey = overrideMedia[mediatype]
+ local result = mtt and ((overridekey and mtt[overridekey] or mtt[key]) or (not noDefault and defaultMedia[mediatype] and mtt[defaultMedia[mediatype]])) or nil
+ return result ~= "" and result or nil
+end
+
+function lib:IsValid(mediatype, key)
+ return mediaTable[mediatype] and (not key or mediaTable[mediatype][key]) and true or false
+end
+
+function lib:HashTable(mediatype)
+ return mediaTable[mediatype]
+end
+
+function lib:List(mediatype)
+ if not mediaTable[mediatype] then
+ return nil
+ end
+ if not mediaList[mediatype] then
+ rebuildMediaList(mediatype)
+ end
+ return mediaList[mediatype]
+end
+
+function lib:GetGlobal(mediatype)
+ return overrideMedia[mediatype]
+end
+
+function lib:SetGlobal(mediatype, key)
+ if not mediaTable[mediatype] then
+ return false
+ end
+ overrideMedia[mediatype] = (key and mediaTable[mediatype][key]) and key or nil
+ self.callbacks:Fire("LibSharedMedia_SetGlobal", mediatype, overrideMedia[mediatype])
+ return true
+end
+
+function lib:GetDefault(mediatype)
+ return defaultMedia[mediatype]
+end
+
+function lib:SetDefault(mediatype, key)
+ if mediaTable[mediatype] and mediaTable[mediatype][key] and not defaultMedia[mediatype] then
+ defaultMedia[mediatype] = key
+ return true
+ else
+ return false
+ end
+end
diff --git a/ElvUI/Libraries/LibSimpleSticky/LibSimpleSticky.lua b/ElvUI/Libraries/LibSimpleSticky/LibSimpleSticky.lua
new file mode 100644
index 0000000..3fadeda
--- /dev/null
+++ b/ElvUI/Libraries/LibSimpleSticky/LibSimpleSticky.lua
@@ -0,0 +1,296 @@
+--[[---------------------------------------------------------------------------------
+ General Library providing an alternate StartMoving() that allows you to
+ specify a number of frames to snap-to when moving the frame around
+
+ Example Usage:
+
+
+ this:RegisterForDrag("LeftButton")
+
+
+ StickyFrames:StartMoving(this, {WatchDogFrame_player, WatchDogFrame_target, WatchDogFrame_party1, WatchDogFrame_party2, WatchDogFrame_party3, WatchDogFrame_party4},3,3,3,3)
+
+
+ StickyFrames:StopMoving(this)
+ StickyFrames:AnchorFrame(this)
+
+
+------------------------------------------------------------------------------------
+This is a modified version by Elv for ElvUI
+------------------------------------------------------------------------------------]]
+
+local MAJOR, MINOR = "LibSimpleSticky-1.0", 2
+local StickyFrames = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not StickyFrames then return end
+
+local twipe = table.wipe
+
+local GetCursorPosition = GetCursorPosition
+local IsShiftKeyDown = IsShiftKeyDown
+
+--[[---------------------------------------------------------------------------------
+ Class declaration, along with a temporary table to hold any existing OnUpdate
+ scripts.
+------------------------------------------------------------------------------------]]
+
+StickyFrames.scripts = StickyFrames.scripts or {}
+StickyFrames.rangeX = 15
+StickyFrames.rangeY = 15
+StickyFrames.sticky = StickyFrames.sticky or {}
+
+local groupBlacklist = {}
+
+local function isGroupPoint(frame, frame2)
+ if groupBlacklist[frame2] then
+ return true
+ else
+ local _, point = frame2:GetPoint()
+ if groupBlacklist[point] or frame.parent == point then
+ groupBlacklist[frame2.parent] = true
+ return true
+ end
+ end
+end
+
+--[[---------------------------------------------------------------------------------
+ StickyFrames:StartMoving() - Sets a custom OnUpdate for the frame so it follows
+ the mouse and snaps to the frames you specify
+
+ frame: The frame we want to move. Is typically "this"
+
+ frameList: A integer indexed list of frames that the given frame should try to
+ stick to. These don't have to have anything special done to them,
+ and they don't really even need to exist. You can inclue the
+ moving frame in this list, it will be ignored. This helps you
+ if you have a number of frames, just make ONE list to pass.
+
+ {WatchDogFrame_player, WatchDogFrame_party1, .. WatchDogFrame_party4}
+
+ left: If your frame has a tranparent border around the entire frame
+ (think backdrops with borders). This can be used to fine tune the
+ edges when you're stickying groups. Refers to any offset on the
+ LEFT edge of the frame being moved.
+
+ top: same
+ right: same
+ bottom: same
+------------------------------------------------------------------------------------]]
+
+function StickyFrames:StartMoving(frame, frameList, left, top, right, bottom)
+ local x,y = GetCursorPosition()
+ local aX,aY = frame:GetCenter()
+ local aS = frame:GetEffectiveScale()
+
+ aX,aY = aX*aS,aY*aS
+ local xoffset,yoffset = (aX - x),(aY - y)
+ self.scripts[frame] = frame:GetScript("OnUpdate")
+ frame:SetScript("OnUpdate", self:GetUpdateFunc(frame, frameList, xoffset, yoffset, left, top, right, bottom))
+end
+
+--[[---------------------------------------------------------------------------------
+ This stops the OnUpdate, leaving the frame at its last position. This will
+ leave it anchored to UIParent. You can call StickyFrames:AnchorFrame() to
+ anchor it back "TOPLEFT" , "TOPLEFT" to the parent.
+------------------------------------------------------------------------------------]]
+
+function StickyFrames:StopMoving(frame)
+ frame:SetScript("OnUpdate", self.scripts[frame])
+ self.scripts[frame] = nil
+ twipe(groupBlacklist)
+
+ if StickyFrames.sticky[frame] then
+ local sticky = StickyFrames.sticky[frame]
+ StickyFrames.sticky[frame] = nil
+ return true, sticky
+ else
+ return false, nil
+ end
+end
+
+--[[---------------------------------------------------------------------------------
+ This can be called in conjunction with StickyFrames:StopMoving() to anchor the
+ frame right back to the parent, so you can manipulate its children as a group
+ (This is useful in WatchDog)
+------------------------------------------------------------------------------------]]
+
+function StickyFrames:AnchorFrame(frame)
+ local xA,yA = frame:GetCenter()
+ local parent = frame:GetParent() or UIParent
+ local xP,yP = parent:GetCenter()
+ local sA,sP = frame:GetEffectiveScale(), parent:GetEffectiveScale()
+
+ xP,yP = (xP*sP) / sA, (yP*sP) / sA
+
+ local xo,yo = (xP - xA)*-1, (yP - yA)*-1
+
+ frame:ClearAllPoints()
+ frame:SetPoint("CENTER", parent, "CENTER", xo, yo)
+end
+
+
+--[[---------------------------------------------------------------------------------
+ Internal Functions -- Do not call these.
+------------------------------------------------------------------------------------]]
+
+
+
+--[[---------------------------------------------------------------------------------
+ Returns an anonymous OnUpdate function for the frame in question. Need
+ to provide the frame, frameList along with the x and y offset (difference between
+ where the mouse picked up the frame, and the insets (left,top,right,bottom) in the
+ case of borders, etc.w
+------------------------------------------------------------------------------------]]
+
+function StickyFrames:GetUpdateFunc(frame, frameList, xoffset, yoffset, left, top, right, bottom)
+ return function()
+ local x,y = GetCursorPosition()
+ local s = frame:GetEffectiveScale()
+
+ x,y = x/s,y/s
+
+ frame:ClearAllPoints()
+ frame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x+xoffset, y+yoffset)
+
+ StickyFrames.sticky[frame] = nil
+ for i = 1, #frameList do
+ local v = frameList[i]
+ if frame ~= v and frame ~= v:GetParent() and not isGroupPoint(frame, v) and not IsShiftKeyDown() and v:IsVisible() then
+ if self:SnapFrame(frame, v, left, top, right, bottom) then
+ StickyFrames.sticky[frame] = v
+ break
+ end
+ end
+ end
+ end
+end
+
+
+--[[---------------------------------------------------------------------------------
+ Internal debug function.
+------------------------------------------------------------------------------------]]
+
+function StickyFrames:debug(msg)
+ DEFAULT_CHAT_FRAME:AddMessage("|cffffff00StickyFrames: |r"..tostring(msg))
+end
+
+--[[---------------------------------------------------------------------------------
+ This is called when finding an overlap between two sticky frame. If frameA is near
+ a sticky edge of frameB, then it will snap to that edge and return true. If there
+ is no sticky edge collision, will return false so we can test other frames for
+ stickyness.
+------------------------------------------------------------------------------------]]
+function StickyFrames:SnapFrame(frameA, frameB, left, top, right, bottom)
+ local sA, sB = frameA:GetEffectiveScale(), frameB:GetEffectiveScale()
+ local xA, yA = frameA:GetCenter()
+ local xB, yB = frameB:GetCenter()
+ local hA = frameA:GetHeight() / 2
+ local wA = frameA:GetWidth() / 2
+
+ local newX, newY = xA, yA
+
+ if not left then left = 0 end
+ if not top then top = 0 end
+ if not right then right = 0 end
+ if not bottom then bottom = 0 end
+
+ -- Lets translate B's coords into A's scale
+ if not xB or not yB or not sB or not sA or not sB then return end
+ xB, yB = (xB*sB) / sA, (yB*sB) / sA
+
+ -- Grab the edges of each frame, for easier comparison
+
+ local lA, tA, rA, bA = frameA:GetLeft(), frameA:GetTop(), frameA:GetRight(), frameA:GetBottom()
+ local lB, tB, rB, bB = frameB:GetLeft(), frameB:GetTop(), frameB:GetRight(), frameB:GetBottom()
+ local snap = nil
+
+ -- Translate into A's scale
+ lB, tB, rB, bB = (lB * sB) / sA, (tB * sB) / sA, (rB * sB) / sA, (bB * sB) / sA
+
+ if (bA <= tB and bB <= tA) then
+
+ -- Horizontal Centers
+ if xA <= (xB + StickyFrames.rangeX) and xA >= (xB - StickyFrames.rangeX) then
+ newX = xB
+ snap = true
+ end
+
+ -- Interior Left
+ if lA <= (lB + StickyFrames.rangeX) and lA >= (lB - StickyFrames.rangeX) then
+ newX = lB + wA
+ if frameB == UIParent or frameB == WorldFrame or frameB == ElvUIParent then
+ newX = newX + 4
+ end
+ snap = true
+ end
+
+ -- Interior Right
+ if rA <= (rB + StickyFrames.rangeX) and rA >= (rB - StickyFrames.rangeX) then
+ newX = rB - wA
+ if frameB == UIParent or frameB == WorldFrame or frameB == ElvUIParent then
+ newX = newX - 4
+ end
+ snap = true
+ end
+
+ -- Exterior Left to Right
+ if lA <= (rB + StickyFrames.rangeX) and lA >= (rB - StickyFrames.rangeX) then
+ newX = rB + (wA - left)
+
+ snap = true
+ end
+
+ -- Exterior Right to Left
+ if rA <= (lB + StickyFrames.rangeX) and rA >= (lB - StickyFrames.rangeX) then
+ newX = lB - (wA - right)
+ snap = true
+ end
+
+ end
+
+ if (lA <= rB and lB <= rA) then
+
+ -- Vertical Centers
+ if yA <= (yB + StickyFrames.rangeY) and yA >= (yB - StickyFrames.rangeY) then
+ newY = yB
+ snap = true
+ end
+
+ -- Interior Top
+ if tA <= (tB + StickyFrames.rangeY) and tA >= (tB - StickyFrames.rangeY) then
+ newY = tB - hA
+ if frameB == UIParent or frameB == WorldFrame or frameB == ElvUIParent then
+ newY = newY - 4
+ end
+ snap = true
+ end
+
+ -- Interior Bottom
+ if bA <= (bB + StickyFrames.rangeY) and bA >= (bB - StickyFrames.rangeY) then
+ newY = bB + hA
+ if frameB == UIParent or frameB == WorldFrame or frameB == ElvUIParent then
+ newY = newY + 4
+ end
+ snap = true
+ end
+
+ -- Exterior Top to Bottom
+ if tA <= (bB + StickyFrames.rangeY + bottom) and tA >= (bB - StickyFrames.rangeY + bottom) then
+ newY = bB - (hA - top)
+ snap = true
+ end
+
+ -- Exterior Bottom to Top
+ if bA <= (tB + StickyFrames.rangeY - top) and bA >= (tB - StickyFrames.rangeY - top) then
+ newY = tB + (hA - bottom)
+ snap = true
+ end
+
+ end
+
+ if snap then
+ frameA:ClearAllPoints()
+ frameA:SetPoint("CENTER", UIParent, "BOTTOMLEFT", newX, newY)
+ return true
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibSpellRange-1.0/LibSpellRange-1.0.lua b/ElvUI/Libraries/LibSpellRange-1.0/LibSpellRange-1.0.lua
new file mode 100644
index 0000000..fe6e4bf
--- /dev/null
+++ b/ElvUI/Libraries/LibSpellRange-1.0/LibSpellRange-1.0.lua
@@ -0,0 +1,235 @@
+--- = Background =
+-- Blizzard's IsSpellInRange API has always been very limited - you either must have the name of the spell, or its spell book ID. Checking directly by spellID is simply not possible.
+-- Now, in Mists of Pandaria, Blizzard changed the way that many talents and specialization spells work - instead of giving you a new spell when leaned, they replace existing spells. These replacement spells do not work with Blizzard's IsSpellInRange function whatsoever; this limitation is what prompted the creation of this lib.
+-- = Usage =
+-- **LibSpellRange-1.0** exposes an enhanced version of IsSpellInRange that:
+-- * Allows ranged checking based on both spell name and spellID.
+-- * Works correctly with replacement spells that will not work using Blizzard's IsSpellInRange method alone.
+--
+-- @class file
+-- @name LibSpellRange-1.0.lua
+
+local major = "SpellRange-1.0"
+local minor = 19
+
+assert(LibStub, format("%s requires LibStub.", major))
+
+local Lib = LibStub:NewLibrary(major, minor)
+if not Lib then return end
+
+local tonumber = _G.tonumber
+local strlower = _G.strlower
+local wipe = _G.wipe
+local type = _G.type
+
+local GetSpellInfo = _G.GetSpellInfo
+local GetSpellLink = _G.GetSpellLink
+local GetSpellName = _G.GetSpellName
+local GetSpellTabInfo = _G.GetSpellTabInfo
+
+local IsSpellInRange = _G.IsSpellInRange
+local SpellHasRange = _G.SpellHasRange
+
+local MAX_SKILLLINE_TABS = _G.MAX_SKILLLINE_TABS
+
+-- isNumber is basically a tonumber cache for maximum efficiency
+Lib.isNumber = Lib.isNumber or setmetatable({}, {
+ __mode = "kv",
+ __index = function(t, i)
+ local o = tonumber(i) or false
+ t[i] = o
+ return o
+end})
+local isNumber = Lib.isNumber
+
+-- strlower cache for maximum efficiency
+Lib.strlowerCache = Lib.strlowerCache or setmetatable(
+{}, {
+ __index = function(t, i)
+ if not i then return end
+ local o
+ if type(i) == "number" then
+ o = i
+ else
+ o = strlower(i)
+ end
+ t[i] = o
+ return o
+ end,
+}) local strlowerCache = Lib.strlowerCache
+
+-- Matches lowercase player spell names to their spellBookID
+Lib.spellsByName_spell = Lib.spellsByName_spell or {}
+local spellsByName_spell = Lib.spellsByName_spell
+
+-- Matches player spellIDs to their spellBookID
+Lib.spellsByID_spell = Lib.spellsByID_spell or {}
+local spellsByID_spell = Lib.spellsByID_spell
+
+-- Matches lowercase pet spell names to their spellBookID
+Lib.spellsByName_pet = Lib.spellsByName_pet or {}
+local spellsByName_pet = Lib.spellsByName_pet
+
+-- Matches pet spellIDs to their spellBookID
+Lib.spellsByID_pet = Lib.spellsByID_pet or {}
+local spellsByID_pet = Lib.spellsByID_pet
+
+local blacklistedIDs = {}
+
+-- Updates spellsByName and spellsByID
+local function UpdateBook(bookType)
+ local _, offs, numspells
+ local max = 0
+
+ for i = MAX_SKILLLINE_TABS, 1, -1 do
+ _, _, offs, numspells = GetSpellTabInfo(i)
+
+ if numspells > 0 then
+ max = offs + numspells
+ break
+ end
+ end
+
+ local spellsByName = Lib["spellsByName_" .. bookType]
+ local spellsByID = Lib["spellsByID_" .. bookType]
+
+ wipe(spellsByName)
+ wipe(spellsByID)
+ wipe(blacklistedIDs)
+
+ for spellBookID = 1, max do
+ local spellName, rank = GetSpellName(spellBookID, bookType)
+
+ if spellName and (rank == "" or rank:match("%d+")) then
+ local link = GetSpellLink(spellName, rank)
+ local spellID = tonumber(link and link:gsub("|", "||"):match("spell:(%d+)"))
+
+ if spellName then
+ spellsByName[strlower(spellName)] = spellBookID
+ end
+
+ if spellID then
+ spellsByID[spellID] = spellBookID
+ end
+ end
+ end
+end
+
+-- Handles updating spellsByName and spellsByID
+if not Lib.updaterFrame then
+ Lib.updaterFrame = CreateFrame("Frame")
+end
+Lib.updaterFrame:UnregisterAllEvents()
+Lib.updaterFrame:RegisterEvent("LEARNED_SPELL_IN_TAB")
+Lib.updaterFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
+
+local function UpdateSpells(_, event)
+ UpdateBook("spell")
+ UpdateBook("pet")
+ if event == "PLAYER_ENTERING_WORLD" then
+ Lib.updaterFrame:UnregisterEvent(event)
+ end
+end
+
+Lib.updaterFrame:SetScript("OnEvent", UpdateSpells)
+UpdateSpells()
+
+--- Improved spell range checking function.
+-- @name SpellRange.IsSpellInRange
+-- @paramsig spell, unit
+-- @param spell Name or spellID of a spell that you wish to check the range of. The spell must be a spell that you have in your spellbook or your pet's spellbook.
+-- @param unit UnitID of the spell that you wish to check the range on.
+-- @return Exact same returns as http://wowprogramming.com/docs/api/IsSpellInRange
+-- @usage
+-- -- Check spell range by spell name on unit "target"
+-- local SpellRange = LibStub("SpellRange-1.0")
+-- local inRange = SpellRange.IsSpellInRange("Stormstrike", "target")
+--
+-- -- Check spell range by spellID on unit "mouseover"
+-- local SpellRange = LibStub("SpellRange-1.0")
+-- local inRange = SpellRange.IsSpellInRange(17364, "mouseover")
+function Lib.IsSpellInRange(spellInput, unit)
+ if isNumber[spellInput] then
+ local spell = spellsByID_spell[spellInput]
+ if spell then
+ return IsSpellInRange(spell, "spell", unit)
+ else
+ spell = spellsByID_pet[spellInput]
+ if spell then
+ return IsSpellInRange(spell, "pet", unit)
+ elseif not blacklistedIDs[spellInput] then
+ spell = GetSpellInfo(spellInput)
+ if spell then
+ spell = strlowerCache[spell]
+ if spellsByName_spell[spell] then
+ local spellBookID = spellsByName_spell[spell]
+ Lib["spellsByID_spell"][spellInput] = spellBookID
+ return IsSpellInRange(spellBookID, "spell", unit)
+ elseif spellsByName_pet[spell] then
+ local spellBookID = spellsByName_pet[spell]
+ Lib["spellsByID_pet"][spellInput] = spellBookID
+ return IsSpellInRange(spellBookID, "pet", unit)
+ end
+ end
+
+ blacklistedIDs[spellInput] = true
+ return
+ end
+ end
+ else
+ spellInput = strlowerCache[spellInput]
+
+ local spell = spellsByName_spell[spellInput]
+ if spell then
+ return IsSpellInRange(spell, "spell", unit)
+ else
+ spell = spellsByName_pet[spellInput]
+ if spell then
+ return IsSpellInRange(spell, "pet", unit)
+ end
+ end
+
+ return IsSpellInRange(spellInput, unit)
+ end
+end
+
+--- Improved SpellHasRange.
+-- @name SpellRange.SpellHasRange
+-- @paramsig spell
+-- @param spell Name or spellID of a spell that you wish to check for a range. The spell must be a spell that you have in your spellbook or your pet's spellbook.
+-- @return Exact same returns as http://wowprogramming.com/docs/api/SpellHasRange
+-- @usage
+-- -- Check if a spell has a range by spell name
+-- local SpellRange = LibStub("SpellRange-1.0")
+-- local hasRange = SpellRange.SpellHasRange("Stormstrike")
+--
+-- -- Check if a spell has a range by spellID
+-- local SpellRange = LibStub("SpellRange-1.0")
+-- local hasRange = SpellRange.SpellHasRange(17364)
+function Lib.SpellHasRange(spellInput)
+ if isNumber[spellInput] then
+ local spell = spellsByID_spell[spellInput]
+ if spell then
+ return SpellHasRange(spell, "spell")
+ else
+ spell = spellsByID_pet[spellInput]
+ if spell then
+ return SpellHasRange(spell, "pet")
+ end
+ end
+ else
+ spellInput = strlowerCache[spellInput]
+
+ local spell = spellsByName_spell[spellInput]
+ if spell then
+ return SpellHasRange(spell, "spell")
+ else
+ spell = spellsByName_pet[spellInput]
+ if spell then
+ return SpellHasRange(spell, "pet")
+ end
+ end
+
+ return SpellHasRange(spellInput)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Libraries/LibTranslit-1.0/LibTranslit-1.0.lua b/ElvUI/Libraries/LibTranslit-1.0/LibTranslit-1.0.lua
new file mode 100644
index 0000000..774d7b1
--- /dev/null
+++ b/ElvUI/Libraries/LibTranslit-1.0/LibTranslit-1.0.lua
@@ -0,0 +1,113 @@
+local MAJOR_VERSION = "LibTranslit-1.0"
+local MINOR_VERSION = 3
+if not LibStub then
+ error(MAJOR_VERSION .. " requires LibStub.")
+end
+local lib = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION)
+if not lib then
+ return
+end
+
+local CyrToLat = {
+ ["А"] = "A",
+ ["а"] = "a",
+ ["Б"] = "B",
+ ["б"] = "b",
+ ["В"] = "V",
+ ["в"] = "v",
+ ["Г"] = "G",
+ ["г"] = "g",
+ ["Д"] = "D",
+ ["д"] = "d",
+ ["Е"] = "E",
+ ["е"] = "e",
+ ["Ё"] = "e",
+ ["ё"] = "e",
+ ["Ж"] = "Zh",
+ ["ж"] = "zh",
+ ["З"] = "Z",
+ ["з"] = "z",
+ ["И"] = "I",
+ ["и"] = "i",
+ ["Й"] = "Y",
+ ["й"] = "y",
+ ["К"] = "K",
+ ["к"] = "k",
+ ["Л"] = "L",
+ ["л"] = "l",
+ ["М"] = "M",
+ ["м"] = "m",
+ ["Н"] = "N",
+ ["н"] = "n",
+ ["О"] = "O",
+ ["о"] = "o",
+ ["П"] = "P",
+ ["п"] = "p",
+ ["Р"] = "R",
+ ["р"] = "r",
+ ["С"] = "S",
+ ["с"] = "s",
+ ["Т"] = "T",
+ ["т"] = "t",
+ ["У"] = "U",
+ ["у"] = "u",
+ ["Ф"] = "F",
+ ["ф"] = "f",
+ ["Х"] = "Kh",
+ ["х"] = "kh",
+ ["Ц"] = "Ts",
+ ["ц"] = "ts",
+ ["Ч"] = "Ch",
+ ["ч"] = "ch",
+ ["Ш"] = "Sh",
+ ["ш"] = "sh",
+ ["Щ"] = "Shch",
+ ["щ"] = "shch",
+ ["Ъ"] = "",
+ ["ъ"] = "",
+ ["Ы"] = "Y",
+ ["ы"] = "y",
+ ["Ь"] = "",
+ ["ь"] = "",
+ ["Э"] = "E",
+ ["э"] = "e",
+ ["Ю"] = "Yu",
+ ["ю"] = "yu",
+ ["Я"] = "Ya",
+ ["я"] = "ya"
+}
+
+function lib:Transliterate(str, mark)
+ if not str then
+ return ""
+ end
+
+ local mark = mark or ""
+ local tstr = ""
+ local marked = false
+ local i = 1
+
+ while i <= string.len(str) do
+ local c = str:sub(i, i)
+ local b = string.byte(c)
+
+ if b == 208 or b == 209 then
+ if marked == false then
+ tstr = tstr .. mark
+ marked = true
+ end
+ c = str:sub(i + 1, i + 1)
+ tstr = tstr .. (CyrToLat[string.char(b, string.byte(c))] or string.char(b, string.byte(c)))
+
+ i = i + 2
+ else
+ if c == " " or c == "-" then
+ marked = false
+ end
+ tstr = tstr .. c
+ i = i + 1
+ end
+ end
+
+ return tstr
+end
diff --git a/ElvUI/Libraries/Load_Libraries.xml b/ElvUI/Libraries/Load_Libraries.xml
new file mode 100644
index 0000000..9439cd6
--- /dev/null
+++ b/ElvUI/Libraries/Load_Libraries.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/UTF8/UTF8.xml b/ElvUI/Libraries/UTF8/UTF8.xml
new file mode 100644
index 0000000..04aec2b
--- /dev/null
+++ b/ElvUI/Libraries/UTF8/UTF8.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/ElvUI/Libraries/UTF8/utf8.lua b/ElvUI/Libraries/UTF8/utf8.lua
new file mode 100644
index 0000000..5e23002
--- /dev/null
+++ b/ElvUI/Libraries/UTF8/utf8.lua
@@ -0,0 +1,318 @@
+-- $Id: utf8.lua 179 2009-04-03 18:10:03Z pasta $
+--
+-- Provides UTF-8 aware string functions implemented in pure lua:
+-- * string.utf8len(s)
+-- * string.utf8sub(s, i, j)
+-- * string.utf8reverse(s)
+--
+-- If utf8data.lua (containing the lower<->upper case mappings) is loaded, these
+-- additional functions are available:
+-- * string.utf8upper(s)
+-- * string.utf8lower(s)
+--
+-- All functions behave as their non UTF-8 aware counterparts with the exception
+-- that UTF-8 characters are used instead of bytes for all units.
+
+--[[
+Copyright (c) 2006-2007, Kyle Smith
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--]]
+
+-- ABNF from RFC 3629
+--
+-- UTF8-octets = *( UTF8-char )
+-- UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
+-- UTF8-1 = %x00-7F
+-- UTF8-2 = %xC2-DF UTF8-tail
+-- UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
+-- %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
+-- UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
+-- %xF4 %x80-8F 2( UTF8-tail )
+-- UTF8-tail = %x80-BF
+--
+
+local strbyte, strlen, strsub, type = string.byte, string.len, string.sub, type
+
+-- returns the number of bytes used by the UTF-8 character at byte i in s
+-- also doubles as a UTF-8 character validator
+local function utf8charbytes(s, i)
+ -- argument defaults
+ i = i or 1
+
+ -- argument checking
+ if type(s) ~= "string" then
+ error("bad argument #1 to 'utf8charbytes' (string expected, got ".. type(s).. ")")
+ end
+ if type(i) ~= "number" then
+ error("bad argument #2 to 'utf8charbytes' (number expected, got ".. type(i).. ")")
+ end
+
+ local c = strbyte(s, i)
+
+ -- determine bytes needed for character, based on RFC 3629
+ -- validate byte 1
+ if c > 0 and c <= 127 then
+ -- UTF8-1
+ return 1
+
+ elseif c >= 194 and c <= 223 then
+ -- UTF8-2
+ local c2 = strbyte(s, i + 1)
+
+ if not c2 then
+ error("UTF-8 string terminated early")
+ end
+
+ -- validate byte 2
+ if c2 < 128 or c2 > 191 then
+ error("Invalid UTF-8 character")
+ end
+
+ return 2
+
+ elseif c >= 224 and c <= 239 then
+ -- UTF8-3
+ local c2 = strbyte(s, i + 1)
+ local c3 = strbyte(s, i + 2)
+
+ if not c2 or not c3 then
+ error("UTF-8 string terminated early")
+ end
+
+ -- validate byte 2
+ if c == 224 and (c2 < 160 or c2 > 191) then
+ error("Invalid UTF-8 character")
+ elseif c == 237 and (c2 < 128 or c2 > 159) then
+ error("Invalid UTF-8 character")
+ elseif c2 < 128 or c2 > 191 then
+ error("Invalid UTF-8 character")
+ end
+
+ -- validate byte 3
+ if c3 < 128 or c3 > 191 then
+ error("Invalid UTF-8 character")
+ end
+
+ return 3
+
+ elseif c >= 240 and c <= 244 then
+ -- UTF8-4
+ local c2 = strbyte(s, i + 1)
+ local c3 = strbyte(s, i + 2)
+ local c4 = strbyte(s, i + 3)
+
+ if not c2 or not c3 or not c4 then
+ error("UTF-8 string terminated early")
+ end
+
+ -- validate byte 2
+ if c == 240 and (c2 < 144 or c2 > 191) then
+ error("Invalid UTF-8 character")
+ elseif c == 244 and (c2 < 128 or c2 > 143) then
+ error("Invalid UTF-8 character")
+ elseif c2 < 128 or c2 > 191 then
+ error("Invalid UTF-8 character")
+ end
+
+ -- validate byte 3
+ if c3 < 128 or c3 > 191 then
+ error("Invalid UTF-8 character")
+ end
+
+ -- validate byte 4
+ if c4 < 128 or c4 > 191 then
+ error("Invalid UTF-8 character")
+ end
+
+ return 4
+
+ else
+ error("Invalid UTF-8 character")
+ end
+end
+
+-- returns the number of characters in a UTF-8 string
+local function utf8len(s)
+ -- argument checking
+ if type(s) ~= "string" then
+ error("bad argument #1 to 'utf8len' (string expected, got ".. type(s).. ")")
+ end
+
+ local pos = 1
+ local bytes = strlen(s)
+ local len = 0
+
+ while pos <= bytes do
+ len = len + 1
+ pos = pos + utf8charbytes(s, pos)
+ end
+
+ return len
+end
+
+-- install in the string library
+if not string.utf8len then
+ string.utf8len = utf8len
+end
+
+-- functions identically to string.sub except that i and j are UTF-8 characters
+-- instead of bytes
+local function utf8sub(s, i, j)
+ -- argument defaults
+ j = j or -1
+
+ -- argument checking
+ if type(s) ~= "string" then
+ error("bad argument #1 to 'utf8sub' (string expected, got ".. type(s).. ")")
+ end
+ if type(i) ~= "number" then
+ error("bad argument #2 to 'utf8sub' (number expected, got ".. type(i).. ")")
+ end
+ if type(j) ~= "number" then
+ error("bad argument #3 to 'utf8sub' (number expected, got ".. type(j).. ")")
+ end
+
+ local pos = 1
+ local bytes = strlen(s)
+ local len = 0
+
+ -- only set l if i or j is negative
+ local l = (i >= 0 and j >= 0) or utf8len(s)
+ local startChar = (i >= 0) and i or l + i + 1
+ local endChar = (j >= 0) and j or l + j + 1
+
+ -- can't have start before end!
+ if startChar > endChar then
+ return ""
+ end
+
+ -- byte offsets to pass to string.sub
+ local startByte, endByte = 1, bytes
+
+ while pos <= bytes do
+ len = len + 1
+
+ if len == startChar then
+ startByte = pos
+ end
+
+ pos = pos + utf8charbytes(s, pos)
+
+ if len == endChar then
+ endByte = pos - 1
+ break
+ end
+ end
+
+ return strsub(s, startByte, endByte)
+end
+
+-- install in the string library
+if not string.utf8sub then
+ string.utf8sub = utf8sub
+end
+
+-- replace UTF-8 characters based on a mapping table
+local function utf8replace(s, mapping)
+ -- argument checking
+ if type(s) ~= "string" then
+ error("bad argument #1 to 'utf8replace' (string expected, got ".. type(s).. ")")
+ end
+ if type(mapping) ~= "table" then
+ error("bad argument #2 to 'utf8replace' (table expected, got ".. type(mapping).. ")")
+ end
+
+ local pos = 1
+ local bytes = strlen(s)
+ local charbytes
+ local newstr = ""
+
+ while pos <= bytes do
+ charbytes = utf8charbytes(s, pos)
+ local c = strsub(s, pos, pos + charbytes - 1)
+
+ newstr = newstr .. (mapping[c] or c)
+
+ pos = pos + charbytes
+ end
+
+ return newstr
+end
+
+-- identical to string.upper except it knows about unicode simple case conversions
+local function utf8upper(s)
+ return utf8replace(s, utf8_lc_uc)
+end
+
+-- install in the string library
+if not string.utf8upper and utf8_lc_uc then
+ string.utf8upper = utf8upper
+end
+
+-- identical to string.lower except it knows about unicode simple case conversions
+local function utf8lower(s)
+ return utf8replace(s, utf8_uc_lc)
+end
+
+-- install in the string library
+if not string.utf8lower and utf8_uc_lc then
+ string.utf8lower = utf8lower
+end
+
+-- identical to string.reverse except that it supports UTF-8
+local function utf8reverse(s)
+ -- argument checking
+ if type(s) ~= "string" then
+ error("bad argument #1 to 'utf8reverse' (string expected, got ".. type(s).. ")")
+ end
+
+ local bytes = strlen(s)
+ local pos = bytes
+ local charbytes
+ local newstr = ""
+ local c
+
+ while pos > 0 do
+ c = strbyte(s, pos)
+ while c >= 128 and c <= 191 do
+ pos = pos - 1
+ c = strbyte(pos)
+ end
+
+ charbytes = utf8charbytes(s, pos)
+
+ newstr = newstr .. strsub(s, pos, pos + charbytes - 1)
+
+ pos = pos - 1
+ end
+
+ return newstr
+end
+
+-- install in the string library
+if not string.utf8reverse then
+ string.utf8reverse = utf8reverse
+end
\ No newline at end of file
diff --git a/ElvUI/Libraries/UTF8/utf8data.lua b/ElvUI/Libraries/UTF8/utf8data.lua
new file mode 100644
index 0000000..655f719
--- /dev/null
+++ b/ElvUI/Libraries/UTF8/utf8data.lua
@@ -0,0 +1,1860 @@
+utf8_lc_uc = {
+ ["a"] = "A",
+ ["b"] = "B",
+ ["c"] = "C",
+ ["d"] = "D",
+ ["e"] = "E",
+ ["f"] = "F",
+ ["g"] = "G",
+ ["h"] = "H",
+ ["i"] = "I",
+ ["j"] = "J",
+ ["k"] = "K",
+ ["l"] = "L",
+ ["m"] = "M",
+ ["n"] = "N",
+ ["o"] = "O",
+ ["p"] = "P",
+ ["q"] = "Q",
+ ["r"] = "R",
+ ["s"] = "S",
+ ["t"] = "T",
+ ["u"] = "U",
+ ["v"] = "V",
+ ["w"] = "W",
+ ["x"] = "X",
+ ["y"] = "Y",
+ ["z"] = "Z",
+ ["µ"] = "Μ",
+ ["à"] = "À",
+ ["á"] = "Á",
+ ["â"] = "Â",
+ ["ã"] = "Ã",
+ ["ä"] = "Ä",
+ ["å"] = "Å",
+ ["æ"] = "Æ",
+ ["ç"] = "Ç",
+ ["è"] = "È",
+ ["é"] = "É",
+ ["ê"] = "Ê",
+ ["ë"] = "Ë",
+ ["ì"] = "Ì",
+ ["í"] = "Í",
+ ["î"] = "Î",
+ ["ï"] = "Ï",
+ ["ð"] = "Ð",
+ ["ñ"] = "Ñ",
+ ["ò"] = "Ò",
+ ["ó"] = "Ó",
+ ["ô"] = "Ô",
+ ["õ"] = "Õ",
+ ["ö"] = "Ö",
+ ["ø"] = "Ø",
+ ["ù"] = "Ù",
+ ["ú"] = "Ú",
+ ["û"] = "Û",
+ ["ü"] = "Ü",
+ ["ý"] = "Ý",
+ ["þ"] = "Þ",
+ ["ÿ"] = "Ÿ",
+ ["ā"] = "Ā",
+ ["ă"] = "Ă",
+ ["ą"] = "Ą",
+ ["ć"] = "Ć",
+ ["ĉ"] = "Ĉ",
+ ["ċ"] = "Ċ",
+ ["č"] = "Č",
+ ["ď"] = "Ď",
+ ["đ"] = "Đ",
+ ["ē"] = "Ē",
+ ["ĕ"] = "Ĕ",
+ ["ė"] = "Ė",
+ ["ę"] = "Ę",
+ ["ě"] = "Ě",
+ ["ĝ"] = "Ĝ",
+ ["ğ"] = "Ğ",
+ ["ġ"] = "Ġ",
+ ["ģ"] = "Ģ",
+ ["ĥ"] = "Ĥ",
+ ["ħ"] = "Ħ",
+ ["ĩ"] = "Ĩ",
+ ["ī"] = "Ī",
+ ["ĭ"] = "Ĭ",
+ ["į"] = "Į",
+ ["ı"] = "I",
+ ["ij"] = "IJ",
+ ["ĵ"] = "Ĵ",
+ ["ķ"] = "Ķ",
+ ["ĺ"] = "Ĺ",
+ ["ļ"] = "Ļ",
+ ["ľ"] = "Ľ",
+ ["ŀ"] = "Ŀ",
+ ["ł"] = "Ł",
+ ["ń"] = "Ń",
+ ["ņ"] = "Ņ",
+ ["ň"] = "Ň",
+ ["ŋ"] = "Ŋ",
+ ["ō"] = "Ō",
+ ["ŏ"] = "Ŏ",
+ ["ő"] = "Ő",
+ ["œ"] = "Œ",
+ ["ŕ"] = "Ŕ",
+ ["ŗ"] = "Ŗ",
+ ["ř"] = "Ř",
+ ["ś"] = "Ś",
+ ["ŝ"] = "Ŝ",
+ ["ş"] = "Ş",
+ ["š"] = "Š",
+ ["ţ"] = "Ţ",
+ ["ť"] = "Ť",
+ ["ŧ"] = "Ŧ",
+ ["ũ"] = "Ũ",
+ ["ū"] = "Ū",
+ ["ŭ"] = "Ŭ",
+ ["ů"] = "Ů",
+ ["ű"] = "Ű",
+ ["ų"] = "Ų",
+ ["ŵ"] = "Ŵ",
+ ["ŷ"] = "Ŷ",
+ ["ź"] = "Ź",
+ ["ż"] = "Ż",
+ ["ž"] = "Ž",
+ ["ſ"] = "S",
+ ["ƀ"] = "Ƀ",
+ ["ƃ"] = "Ƃ",
+ ["ƅ"] = "Ƅ",
+ ["ƈ"] = "Ƈ",
+ ["ƌ"] = "Ƌ",
+ ["ƒ"] = "Ƒ",
+ ["ƕ"] = "Ƕ",
+ ["ƙ"] = "Ƙ",
+ ["ƚ"] = "Ƚ",
+ ["ƞ"] = "Ƞ",
+ ["ơ"] = "Ơ",
+ ["ƣ"] = "Ƣ",
+ ["ƥ"] = "Ƥ",
+ ["ƨ"] = "Ƨ",
+ ["ƭ"] = "Ƭ",
+ ["ư"] = "Ư",
+ ["ƴ"] = "Ƴ",
+ ["ƶ"] = "Ƶ",
+ ["ƹ"] = "Ƹ",
+ ["ƽ"] = "Ƽ",
+ ["ƿ"] = "Ƿ",
+ ["Dž"] = "DŽ",
+ ["dž"] = "DŽ",
+ ["Lj"] = "LJ",
+ ["lj"] = "LJ",
+ ["Nj"] = "NJ",
+ ["nj"] = "NJ",
+ ["ǎ"] = "Ǎ",
+ ["ǐ"] = "Ǐ",
+ ["ǒ"] = "Ǒ",
+ ["ǔ"] = "Ǔ",
+ ["ǖ"] = "Ǖ",
+ ["ǘ"] = "Ǘ",
+ ["ǚ"] = "Ǚ",
+ ["ǜ"] = "Ǜ",
+ ["ǝ"] = "Ǝ",
+ ["ǟ"] = "Ǟ",
+ ["ǡ"] = "Ǡ",
+ ["ǣ"] = "Ǣ",
+ ["ǥ"] = "Ǥ",
+ ["ǧ"] = "Ǧ",
+ ["ǩ"] = "Ǩ",
+ ["ǫ"] = "Ǫ",
+ ["ǭ"] = "Ǭ",
+ ["ǯ"] = "Ǯ",
+ ["Dz"] = "DZ",
+ ["dz"] = "DZ",
+ ["ǵ"] = "Ǵ",
+ ["ǹ"] = "Ǹ",
+ ["ǻ"] = "Ǻ",
+ ["ǽ"] = "Ǽ",
+ ["ǿ"] = "Ǿ",
+ ["ȁ"] = "Ȁ",
+ ["ȃ"] = "Ȃ",
+ ["ȅ"] = "Ȅ",
+ ["ȇ"] = "Ȇ",
+ ["ȉ"] = "Ȉ",
+ ["ȋ"] = "Ȋ",
+ ["ȍ"] = "Ȍ",
+ ["ȏ"] = "Ȏ",
+ ["ȑ"] = "Ȑ",
+ ["ȓ"] = "Ȓ",
+ ["ȕ"] = "Ȕ",
+ ["ȗ"] = "Ȗ",
+ ["ș"] = "Ș",
+ ["ț"] = "Ț",
+ ["ȝ"] = "Ȝ",
+ ["ȟ"] = "Ȟ",
+ ["ȣ"] = "Ȣ",
+ ["ȥ"] = "Ȥ",
+ ["ȧ"] = "Ȧ",
+ ["ȩ"] = "Ȩ",
+ ["ȫ"] = "Ȫ",
+ ["ȭ"] = "Ȭ",
+ ["ȯ"] = "Ȯ",
+ ["ȱ"] = "Ȱ",
+ ["ȳ"] = "Ȳ",
+ ["ȼ"] = "Ȼ",
+ ["ɂ"] = "Ɂ",
+ ["ɇ"] = "Ɇ",
+ ["ɉ"] = "Ɉ",
+ ["ɋ"] = "Ɋ",
+ ["ɍ"] = "Ɍ",
+ ["ɏ"] = "Ɏ",
+ ["ɓ"] = "Ɓ",
+ ["ɔ"] = "Ɔ",
+ ["ɖ"] = "Ɖ",
+ ["ɗ"] = "Ɗ",
+ ["ə"] = "Ə",
+ ["ɛ"] = "Ɛ",
+ ["ɠ"] = "Ɠ",
+ ["ɣ"] = "Ɣ",
+ ["ɨ"] = "Ɨ",
+ ["ɩ"] = "Ɩ",
+ ["ɫ"] = "Ɫ",
+ ["ɯ"] = "Ɯ",
+ ["ɲ"] = "Ɲ",
+ ["ɵ"] = "Ɵ",
+ ["ɽ"] = "Ɽ",
+ ["ʀ"] = "Ʀ",
+ ["ʃ"] = "Ʃ",
+ ["ʈ"] = "Ʈ",
+ ["ʉ"] = "Ʉ",
+ ["ʊ"] = "Ʊ",
+ ["ʋ"] = "Ʋ",
+ ["ʌ"] = "Ʌ",
+ ["ʒ"] = "Ʒ",
+ ["ͅ"] = "Ι",
+ ["ͻ"] = "Ͻ",
+ ["ͼ"] = "Ͼ",
+ ["ͽ"] = "Ͽ",
+ ["ά"] = "Ά",
+ ["έ"] = "Έ",
+ ["ή"] = "Ή",
+ ["ί"] = "Ί",
+ ["α"] = "Α",
+ ["β"] = "Β",
+ ["γ"] = "Γ",
+ ["δ"] = "Δ",
+ ["ε"] = "Ε",
+ ["ζ"] = "Ζ",
+ ["η"] = "Η",
+ ["θ"] = "Θ",
+ ["ι"] = "Ι",
+ ["κ"] = "Κ",
+ ["λ"] = "Λ",
+ ["μ"] = "Μ",
+ ["ν"] = "Ν",
+ ["ξ"] = "Ξ",
+ ["ο"] = "Ο",
+ ["π"] = "Π",
+ ["ρ"] = "Ρ",
+ ["ς"] = "Σ",
+ ["σ"] = "Σ",
+ ["τ"] = "Τ",
+ ["υ"] = "Υ",
+ ["φ"] = "Φ",
+ ["χ"] = "Χ",
+ ["ψ"] = "Ψ",
+ ["ω"] = "Ω",
+ ["ϊ"] = "Ϊ",
+ ["ϋ"] = "Ϋ",
+ ["ό"] = "Ό",
+ ["ύ"] = "Ύ",
+ ["ώ"] = "Ώ",
+ ["ϐ"] = "Β",
+ ["ϑ"] = "Θ",
+ ["ϕ"] = "Φ",
+ ["ϖ"] = "Π",
+ ["ϙ"] = "Ϙ",
+ ["ϛ"] = "Ϛ",
+ ["ϝ"] = "Ϝ",
+ ["ϟ"] = "Ϟ",
+ ["ϡ"] = "Ϡ",
+ ["ϣ"] = "Ϣ",
+ ["ϥ"] = "Ϥ",
+ ["ϧ"] = "Ϧ",
+ ["ϩ"] = "Ϩ",
+ ["ϫ"] = "Ϫ",
+ ["ϭ"] = "Ϭ",
+ ["ϯ"] = "Ϯ",
+ ["ϰ"] = "Κ",
+ ["ϱ"] = "Ρ",
+ ["ϲ"] = "Ϲ",
+ ["ϵ"] = "Ε",
+ ["ϸ"] = "Ϸ",
+ ["ϻ"] = "Ϻ",
+ ["а"] = "А",
+ ["б"] = "Б",
+ ["в"] = "В",
+ ["г"] = "Г",
+ ["д"] = "Д",
+ ["е"] = "Е",
+ ["ж"] = "Ж",
+ ["з"] = "З",
+ ["и"] = "И",
+ ["й"] = "Й",
+ ["к"] = "К",
+ ["л"] = "Л",
+ ["м"] = "М",
+ ["н"] = "Н",
+ ["о"] = "О",
+ ["п"] = "П",
+ ["р"] = "Р",
+ ["с"] = "С",
+ ["т"] = "Т",
+ ["у"] = "У",
+ ["ф"] = "Ф",
+ ["х"] = "Х",
+ ["ц"] = "Ц",
+ ["ч"] = "Ч",
+ ["ш"] = "Ш",
+ ["щ"] = "Щ",
+ ["ъ"] = "Ъ",
+ ["ы"] = "Ы",
+ ["ь"] = "Ь",
+ ["э"] = "Э",
+ ["ю"] = "Ю",
+ ["я"] = "Я",
+ ["ѐ"] = "Ѐ",
+ ["ё"] = "Ё",
+ ["ђ"] = "Ђ",
+ ["ѓ"] = "Ѓ",
+ ["є"] = "Є",
+ ["ѕ"] = "Ѕ",
+ ["і"] = "І",
+ ["ї"] = "Ї",
+ ["ј"] = "Ј",
+ ["љ"] = "Љ",
+ ["њ"] = "Њ",
+ ["ћ"] = "Ћ",
+ ["ќ"] = "Ќ",
+ ["ѝ"] = "Ѝ",
+ ["ў"] = "Ў",
+ ["џ"] = "Џ",
+ ["ѡ"] = "Ѡ",
+ ["ѣ"] = "Ѣ",
+ ["ѥ"] = "Ѥ",
+ ["ѧ"] = "Ѧ",
+ ["ѩ"] = "Ѩ",
+ ["ѫ"] = "Ѫ",
+ ["ѭ"] = "Ѭ",
+ ["ѯ"] = "Ѯ",
+ ["ѱ"] = "Ѱ",
+ ["ѳ"] = "Ѳ",
+ ["ѵ"] = "Ѵ",
+ ["ѷ"] = "Ѷ",
+ ["ѹ"] = "Ѹ",
+ ["ѻ"] = "Ѻ",
+ ["ѽ"] = "Ѽ",
+ ["ѿ"] = "Ѿ",
+ ["ҁ"] = "Ҁ",
+ ["ҋ"] = "Ҋ",
+ ["ҍ"] = "Ҍ",
+ ["ҏ"] = "Ҏ",
+ ["ґ"] = "Ґ",
+ ["ғ"] = "Ғ",
+ ["ҕ"] = "Ҕ",
+ ["җ"] = "Җ",
+ ["ҙ"] = "Ҙ",
+ ["қ"] = "Қ",
+ ["ҝ"] = "Ҝ",
+ ["ҟ"] = "Ҟ",
+ ["ҡ"] = "Ҡ",
+ ["ң"] = "Ң",
+ ["ҥ"] = "Ҥ",
+ ["ҧ"] = "Ҧ",
+ ["ҩ"] = "Ҩ",
+ ["ҫ"] = "Ҫ",
+ ["ҭ"] = "Ҭ",
+ ["ү"] = "Ү",
+ ["ұ"] = "Ұ",
+ ["ҳ"] = "Ҳ",
+ ["ҵ"] = "Ҵ",
+ ["ҷ"] = "Ҷ",
+ ["ҹ"] = "Ҹ",
+ ["һ"] = "Һ",
+ ["ҽ"] = "Ҽ",
+ ["ҿ"] = "Ҿ",
+ ["ӂ"] = "Ӂ",
+ ["ӄ"] = "Ӄ",
+ ["ӆ"] = "Ӆ",
+ ["ӈ"] = "Ӈ",
+ ["ӊ"] = "Ӊ",
+ ["ӌ"] = "Ӌ",
+ ["ӎ"] = "Ӎ",
+ ["ӏ"] = "Ӏ",
+ ["ӑ"] = "Ӑ",
+ ["ӓ"] = "Ӓ",
+ ["ӕ"] = "Ӕ",
+ ["ӗ"] = "Ӗ",
+ ["ә"] = "Ә",
+ ["ӛ"] = "Ӛ",
+ ["ӝ"] = "Ӝ",
+ ["ӟ"] = "Ӟ",
+ ["ӡ"] = "Ӡ",
+ ["ӣ"] = "Ӣ",
+ ["ӥ"] = "Ӥ",
+ ["ӧ"] = "Ӧ",
+ ["ө"] = "Ө",
+ ["ӫ"] = "Ӫ",
+ ["ӭ"] = "Ӭ",
+ ["ӯ"] = "Ӯ",
+ ["ӱ"] = "Ӱ",
+ ["ӳ"] = "Ӳ",
+ ["ӵ"] = "Ӵ",
+ ["ӷ"] = "Ӷ",
+ ["ӹ"] = "Ӹ",
+ ["ӻ"] = "Ӻ",
+ ["ӽ"] = "Ӽ",
+ ["ӿ"] = "Ӿ",
+ ["ԁ"] = "Ԁ",
+ ["ԃ"] = "Ԃ",
+ ["ԅ"] = "Ԅ",
+ ["ԇ"] = "Ԇ",
+ ["ԉ"] = "Ԉ",
+ ["ԋ"] = "Ԋ",
+ ["ԍ"] = "Ԍ",
+ ["ԏ"] = "Ԏ",
+ ["ԑ"] = "Ԑ",
+ ["ԓ"] = "Ԓ",
+ ["ա"] = "Ա",
+ ["բ"] = "Բ",
+ ["գ"] = "Գ",
+ ["դ"] = "Դ",
+ ["ե"] = "Ե",
+ ["զ"] = "Զ",
+ ["է"] = "Է",
+ ["ը"] = "Ը",
+ ["թ"] = "Թ",
+ ["ժ"] = "Ժ",
+ ["ի"] = "Ի",
+ ["լ"] = "Լ",
+ ["խ"] = "Խ",
+ ["ծ"] = "Ծ",
+ ["կ"] = "Կ",
+ ["հ"] = "Հ",
+ ["ձ"] = "Ձ",
+ ["ղ"] = "Ղ",
+ ["ճ"] = "Ճ",
+ ["մ"] = "Մ",
+ ["յ"] = "Յ",
+ ["ն"] = "Ն",
+ ["շ"] = "Շ",
+ ["ո"] = "Ո",
+ ["չ"] = "Չ",
+ ["պ"] = "Պ",
+ ["ջ"] = "Ջ",
+ ["ռ"] = "Ռ",
+ ["ս"] = "Ս",
+ ["վ"] = "Վ",
+ ["տ"] = "Տ",
+ ["ր"] = "Ր",
+ ["ց"] = "Ց",
+ ["ւ"] = "Ւ",
+ ["փ"] = "Փ",
+ ["ք"] = "Ք",
+ ["օ"] = "Օ",
+ ["ֆ"] = "Ֆ",
+ ["ᵽ"] = "Ᵽ",
+ ["ḁ"] = "Ḁ",
+ ["ḃ"] = "Ḃ",
+ ["ḅ"] = "Ḅ",
+ ["ḇ"] = "Ḇ",
+ ["ḉ"] = "Ḉ",
+ ["ḋ"] = "Ḋ",
+ ["ḍ"] = "Ḍ",
+ ["ḏ"] = "Ḏ",
+ ["ḑ"] = "Ḑ",
+ ["ḓ"] = "Ḓ",
+ ["ḕ"] = "Ḕ",
+ ["ḗ"] = "Ḗ",
+ ["ḙ"] = "Ḙ",
+ ["ḛ"] = "Ḛ",
+ ["ḝ"] = "Ḝ",
+ ["ḟ"] = "Ḟ",
+ ["ḡ"] = "Ḡ",
+ ["ḣ"] = "Ḣ",
+ ["ḥ"] = "Ḥ",
+ ["ḧ"] = "Ḧ",
+ ["ḩ"] = "Ḩ",
+ ["ḫ"] = "Ḫ",
+ ["ḭ"] = "Ḭ",
+ ["ḯ"] = "Ḯ",
+ ["ḱ"] = "Ḱ",
+ ["ḳ"] = "Ḳ",
+ ["ḵ"] = "Ḵ",
+ ["ḷ"] = "Ḷ",
+ ["ḹ"] = "Ḹ",
+ ["ḻ"] = "Ḻ",
+ ["ḽ"] = "Ḽ",
+ ["ḿ"] = "Ḿ",
+ ["ṁ"] = "Ṁ",
+ ["ṃ"] = "Ṃ",
+ ["ṅ"] = "Ṅ",
+ ["ṇ"] = "Ṇ",
+ ["ṉ"] = "Ṉ",
+ ["ṋ"] = "Ṋ",
+ ["ṍ"] = "Ṍ",
+ ["ṏ"] = "Ṏ",
+ ["ṑ"] = "Ṑ",
+ ["ṓ"] = "Ṓ",
+ ["ṕ"] = "Ṕ",
+ ["ṗ"] = "Ṗ",
+ ["ṙ"] = "Ṙ",
+ ["ṛ"] = "Ṛ",
+ ["ṝ"] = "Ṝ",
+ ["ṟ"] = "Ṟ",
+ ["ṡ"] = "Ṡ",
+ ["ṣ"] = "Ṣ",
+ ["ṥ"] = "Ṥ",
+ ["ṧ"] = "Ṧ",
+ ["ṩ"] = "Ṩ",
+ ["ṫ"] = "Ṫ",
+ ["ṭ"] = "Ṭ",
+ ["ṯ"] = "Ṯ",
+ ["ṱ"] = "Ṱ",
+ ["ṳ"] = "Ṳ",
+ ["ṵ"] = "Ṵ",
+ ["ṷ"] = "Ṷ",
+ ["ṹ"] = "Ṹ",
+ ["ṻ"] = "Ṻ",
+ ["ṽ"] = "Ṽ",
+ ["ṿ"] = "Ṿ",
+ ["ẁ"] = "Ẁ",
+ ["ẃ"] = "Ẃ",
+ ["ẅ"] = "Ẅ",
+ ["ẇ"] = "Ẇ",
+ ["ẉ"] = "Ẉ",
+ ["ẋ"] = "Ẋ",
+ ["ẍ"] = "Ẍ",
+ ["ẏ"] = "Ẏ",
+ ["ẑ"] = "Ẑ",
+ ["ẓ"] = "Ẓ",
+ ["ẕ"] = "Ẕ",
+ ["ẛ"] = "Ṡ",
+ ["ạ"] = "Ạ",
+ ["ả"] = "Ả",
+ ["ấ"] = "Ấ",
+ ["ầ"] = "Ầ",
+ ["ẩ"] = "Ẩ",
+ ["ẫ"] = "Ẫ",
+ ["ậ"] = "Ậ",
+ ["ắ"] = "Ắ",
+ ["ằ"] = "Ằ",
+ ["ẳ"] = "Ẳ",
+ ["ẵ"] = "Ẵ",
+ ["ặ"] = "Ặ",
+ ["ẹ"] = "Ẹ",
+ ["ẻ"] = "Ẻ",
+ ["ẽ"] = "Ẽ",
+ ["ế"] = "Ế",
+ ["ề"] = "Ề",
+ ["ể"] = "Ể",
+ ["ễ"] = "Ễ",
+ ["ệ"] = "Ệ",
+ ["ỉ"] = "Ỉ",
+ ["ị"] = "Ị",
+ ["ọ"] = "Ọ",
+ ["ỏ"] = "Ỏ",
+ ["ố"] = "Ố",
+ ["ồ"] = "Ồ",
+ ["ổ"] = "Ổ",
+ ["ỗ"] = "Ỗ",
+ ["ộ"] = "Ộ",
+ ["ớ"] = "Ớ",
+ ["ờ"] = "Ờ",
+ ["ở"] = "Ở",
+ ["ỡ"] = "Ỡ",
+ ["ợ"] = "Ợ",
+ ["ụ"] = "Ụ",
+ ["ủ"] = "Ủ",
+ ["ứ"] = "Ứ",
+ ["ừ"] = "Ừ",
+ ["ử"] = "Ử",
+ ["ữ"] = "Ữ",
+ ["ự"] = "Ự",
+ ["ỳ"] = "Ỳ",
+ ["ỵ"] = "Ỵ",
+ ["ỷ"] = "Ỷ",
+ ["ỹ"] = "Ỹ",
+ ["ἀ"] = "Ἀ",
+ ["ἁ"] = "Ἁ",
+ ["ἂ"] = "Ἂ",
+ ["ἃ"] = "Ἃ",
+ ["ἄ"] = "Ἄ",
+ ["ἅ"] = "Ἅ",
+ ["ἆ"] = "Ἆ",
+ ["ἇ"] = "Ἇ",
+ ["ἐ"] = "Ἐ",
+ ["ἑ"] = "Ἑ",
+ ["ἒ"] = "Ἒ",
+ ["ἓ"] = "Ἓ",
+ ["ἔ"] = "Ἔ",
+ ["ἕ"] = "Ἕ",
+ ["ἠ"] = "Ἠ",
+ ["ἡ"] = "Ἡ",
+ ["ἢ"] = "Ἢ",
+ ["ἣ"] = "Ἣ",
+ ["ἤ"] = "Ἤ",
+ ["ἥ"] = "Ἥ",
+ ["ἦ"] = "Ἦ",
+ ["ἧ"] = "Ἧ",
+ ["ἰ"] = "Ἰ",
+ ["ἱ"] = "Ἱ",
+ ["ἲ"] = "Ἲ",
+ ["ἳ"] = "Ἳ",
+ ["ἴ"] = "Ἴ",
+ ["ἵ"] = "Ἵ",
+ ["ἶ"] = "Ἶ",
+ ["ἷ"] = "Ἷ",
+ ["ὀ"] = "Ὀ",
+ ["ὁ"] = "Ὁ",
+ ["ὂ"] = "Ὂ",
+ ["ὃ"] = "Ὃ",
+ ["ὄ"] = "Ὄ",
+ ["ὅ"] = "Ὅ",
+ ["ὑ"] = "Ὑ",
+ ["ὓ"] = "Ὓ",
+ ["ὕ"] = "Ὕ",
+ ["ὗ"] = "Ὗ",
+ ["ὠ"] = "Ὠ",
+ ["ὡ"] = "Ὡ",
+ ["ὢ"] = "Ὢ",
+ ["ὣ"] = "Ὣ",
+ ["ὤ"] = "Ὤ",
+ ["ὥ"] = "Ὥ",
+ ["ὦ"] = "Ὦ",
+ ["ὧ"] = "Ὧ",
+ ["ὰ"] = "Ὰ",
+ ["ά"] = "Ά",
+ ["ὲ"] = "Ὲ",
+ ["έ"] = "Έ",
+ ["ὴ"] = "Ὴ",
+ ["ή"] = "Ή",
+ ["ὶ"] = "Ὶ",
+ ["ί"] = "Ί",
+ ["ὸ"] = "Ὸ",
+ ["ό"] = "Ό",
+ ["ὺ"] = "Ὺ",
+ ["ύ"] = "Ύ",
+ ["ὼ"] = "Ὼ",
+ ["ώ"] = "Ώ",
+ ["ᾀ"] = "ᾈ",
+ ["ᾁ"] = "ᾉ",
+ ["ᾂ"] = "ᾊ",
+ ["ᾃ"] = "ᾋ",
+ ["ᾄ"] = "ᾌ",
+ ["ᾅ"] = "ᾍ",
+ ["ᾆ"] = "ᾎ",
+ ["ᾇ"] = "ᾏ",
+ ["ᾐ"] = "ᾘ",
+ ["ᾑ"] = "ᾙ",
+ ["ᾒ"] = "ᾚ",
+ ["ᾓ"] = "ᾛ",
+ ["ᾔ"] = "ᾜ",
+ ["ᾕ"] = "ᾝ",
+ ["ᾖ"] = "ᾞ",
+ ["ᾗ"] = "ᾟ",
+ ["ᾠ"] = "ᾨ",
+ ["ᾡ"] = "ᾩ",
+ ["ᾢ"] = "ᾪ",
+ ["ᾣ"] = "ᾫ",
+ ["ᾤ"] = "ᾬ",
+ ["ᾥ"] = "ᾭ",
+ ["ᾦ"] = "ᾮ",
+ ["ᾧ"] = "ᾯ",
+ ["ᾰ"] = "Ᾰ",
+ ["ᾱ"] = "Ᾱ",
+ ["ᾳ"] = "ᾼ",
+ ["ι"] = "Ι",
+ ["ῃ"] = "ῌ",
+ ["ῐ"] = "Ῐ",
+ ["ῑ"] = "Ῑ",
+ ["ῠ"] = "Ῠ",
+ ["ῡ"] = "Ῡ",
+ ["ῥ"] = "Ῥ",
+ ["ῳ"] = "ῼ",
+ ["ⅎ"] = "Ⅎ",
+ ["ⅰ"] = "Ⅰ",
+ ["ⅱ"] = "Ⅱ",
+ ["ⅲ"] = "Ⅲ",
+ ["ⅳ"] = "Ⅳ",
+ ["ⅴ"] = "Ⅴ",
+ ["ⅵ"] = "Ⅵ",
+ ["ⅶ"] = "Ⅶ",
+ ["ⅷ"] = "Ⅷ",
+ ["ⅸ"] = "Ⅸ",
+ ["ⅹ"] = "Ⅹ",
+ ["ⅺ"] = "Ⅺ",
+ ["ⅻ"] = "Ⅻ",
+ ["ⅼ"] = "Ⅼ",
+ ["ⅽ"] = "Ⅽ",
+ ["ⅾ"] = "Ⅾ",
+ ["ⅿ"] = "Ⅿ",
+ ["ↄ"] = "Ↄ",
+ ["ⓐ"] = "Ⓐ",
+ ["ⓑ"] = "Ⓑ",
+ ["ⓒ"] = "Ⓒ",
+ ["ⓓ"] = "Ⓓ",
+ ["ⓔ"] = "Ⓔ",
+ ["ⓕ"] = "Ⓕ",
+ ["ⓖ"] = "Ⓖ",
+ ["ⓗ"] = "Ⓗ",
+ ["ⓘ"] = "Ⓘ",
+ ["ⓙ"] = "Ⓙ",
+ ["ⓚ"] = "Ⓚ",
+ ["ⓛ"] = "Ⓛ",
+ ["ⓜ"] = "Ⓜ",
+ ["ⓝ"] = "Ⓝ",
+ ["ⓞ"] = "Ⓞ",
+ ["ⓟ"] = "Ⓟ",
+ ["ⓠ"] = "Ⓠ",
+ ["ⓡ"] = "Ⓡ",
+ ["ⓢ"] = "Ⓢ",
+ ["ⓣ"] = "Ⓣ",
+ ["ⓤ"] = "Ⓤ",
+ ["ⓥ"] = "Ⓥ",
+ ["ⓦ"] = "Ⓦ",
+ ["ⓧ"] = "Ⓧ",
+ ["ⓨ"] = "Ⓨ",
+ ["ⓩ"] = "Ⓩ",
+ ["ⰰ"] = "Ⰰ",
+ ["ⰱ"] = "Ⰱ",
+ ["ⰲ"] = "Ⰲ",
+ ["ⰳ"] = "Ⰳ",
+ ["ⰴ"] = "Ⰴ",
+ ["ⰵ"] = "Ⰵ",
+ ["ⰶ"] = "Ⰶ",
+ ["ⰷ"] = "Ⰷ",
+ ["ⰸ"] = "Ⰸ",
+ ["ⰹ"] = "Ⰹ",
+ ["ⰺ"] = "Ⰺ",
+ ["ⰻ"] = "Ⰻ",
+ ["ⰼ"] = "Ⰼ",
+ ["ⰽ"] = "Ⰽ",
+ ["ⰾ"] = "Ⰾ",
+ ["ⰿ"] = "Ⰿ",
+ ["ⱀ"] = "Ⱀ",
+ ["ⱁ"] = "Ⱁ",
+ ["ⱂ"] = "Ⱂ",
+ ["ⱃ"] = "Ⱃ",
+ ["ⱄ"] = "Ⱄ",
+ ["ⱅ"] = "Ⱅ",
+ ["ⱆ"] = "Ⱆ",
+ ["ⱇ"] = "Ⱇ",
+ ["ⱈ"] = "Ⱈ",
+ ["ⱉ"] = "Ⱉ",
+ ["ⱊ"] = "Ⱊ",
+ ["ⱋ"] = "Ⱋ",
+ ["ⱌ"] = "Ⱌ",
+ ["ⱍ"] = "Ⱍ",
+ ["ⱎ"] = "Ⱎ",
+ ["ⱏ"] = "Ⱏ",
+ ["ⱐ"] = "Ⱐ",
+ ["ⱑ"] = "Ⱑ",
+ ["ⱒ"] = "Ⱒ",
+ ["ⱓ"] = "Ⱓ",
+ ["ⱔ"] = "Ⱔ",
+ ["ⱕ"] = "Ⱕ",
+ ["ⱖ"] = "Ⱖ",
+ ["ⱗ"] = "Ⱗ",
+ ["ⱘ"] = "Ⱘ",
+ ["ⱙ"] = "Ⱙ",
+ ["ⱚ"] = "Ⱚ",
+ ["ⱛ"] = "Ⱛ",
+ ["ⱜ"] = "Ⱜ",
+ ["ⱝ"] = "Ⱝ",
+ ["ⱞ"] = "Ⱞ",
+ ["ⱡ"] = "Ⱡ",
+ ["ⱥ"] = "Ⱥ",
+ ["ⱦ"] = "Ⱦ",
+ ["ⱨ"] = "Ⱨ",
+ ["ⱪ"] = "Ⱪ",
+ ["ⱬ"] = "Ⱬ",
+ ["ⱶ"] = "Ⱶ",
+ ["ⲁ"] = "Ⲁ",
+ ["ⲃ"] = "Ⲃ",
+ ["ⲅ"] = "Ⲅ",
+ ["ⲇ"] = "Ⲇ",
+ ["ⲉ"] = "Ⲉ",
+ ["ⲋ"] = "Ⲋ",
+ ["ⲍ"] = "Ⲍ",
+ ["ⲏ"] = "Ⲏ",
+ ["ⲑ"] = "Ⲑ",
+ ["ⲓ"] = "Ⲓ",
+ ["ⲕ"] = "Ⲕ",
+ ["ⲗ"] = "Ⲗ",
+ ["ⲙ"] = "Ⲙ",
+ ["ⲛ"] = "Ⲛ",
+ ["ⲝ"] = "Ⲝ",
+ ["ⲟ"] = "Ⲟ",
+ ["ⲡ"] = "Ⲡ",
+ ["ⲣ"] = "Ⲣ",
+ ["ⲥ"] = "Ⲥ",
+ ["ⲧ"] = "Ⲧ",
+ ["ⲩ"] = "Ⲩ",
+ ["ⲫ"] = "Ⲫ",
+ ["ⲭ"] = "Ⲭ",
+ ["ⲯ"] = "Ⲯ",
+ ["ⲱ"] = "Ⲱ",
+ ["ⲳ"] = "Ⲳ",
+ ["ⲵ"] = "Ⲵ",
+ ["ⲷ"] = "Ⲷ",
+ ["ⲹ"] = "Ⲹ",
+ ["ⲻ"] = "Ⲻ",
+ ["ⲽ"] = "Ⲽ",
+ ["ⲿ"] = "Ⲿ",
+ ["ⳁ"] = "Ⳁ",
+ ["ⳃ"] = "Ⳃ",
+ ["ⳅ"] = "Ⳅ",
+ ["ⳇ"] = "Ⳇ",
+ ["ⳉ"] = "Ⳉ",
+ ["ⳋ"] = "Ⳋ",
+ ["ⳍ"] = "Ⳍ",
+ ["ⳏ"] = "Ⳏ",
+ ["ⳑ"] = "Ⳑ",
+ ["ⳓ"] = "Ⳓ",
+ ["ⳕ"] = "Ⳕ",
+ ["ⳗ"] = "Ⳗ",
+ ["ⳙ"] = "Ⳙ",
+ ["ⳛ"] = "Ⳛ",
+ ["ⳝ"] = "Ⳝ",
+ ["ⳟ"] = "Ⳟ",
+ ["ⳡ"] = "Ⳡ",
+ ["ⳣ"] = "Ⳣ",
+ ["ⴀ"] = "Ⴀ",
+ ["ⴁ"] = "Ⴁ",
+ ["ⴂ"] = "Ⴂ",
+ ["ⴃ"] = "Ⴃ",
+ ["ⴄ"] = "Ⴄ",
+ ["ⴅ"] = "Ⴅ",
+ ["ⴆ"] = "Ⴆ",
+ ["ⴇ"] = "Ⴇ",
+ ["ⴈ"] = "Ⴈ",
+ ["ⴉ"] = "Ⴉ",
+ ["ⴊ"] = "Ⴊ",
+ ["ⴋ"] = "Ⴋ",
+ ["ⴌ"] = "Ⴌ",
+ ["ⴍ"] = "Ⴍ",
+ ["ⴎ"] = "Ⴎ",
+ ["ⴏ"] = "Ⴏ",
+ ["ⴐ"] = "Ⴐ",
+ ["ⴑ"] = "Ⴑ",
+ ["ⴒ"] = "Ⴒ",
+ ["ⴓ"] = "Ⴓ",
+ ["ⴔ"] = "Ⴔ",
+ ["ⴕ"] = "Ⴕ",
+ ["ⴖ"] = "Ⴖ",
+ ["ⴗ"] = "Ⴗ",
+ ["ⴘ"] = "Ⴘ",
+ ["ⴙ"] = "Ⴙ",
+ ["ⴚ"] = "Ⴚ",
+ ["ⴛ"] = "Ⴛ",
+ ["ⴜ"] = "Ⴜ",
+ ["ⴝ"] = "Ⴝ",
+ ["ⴞ"] = "Ⴞ",
+ ["ⴟ"] = "Ⴟ",
+ ["ⴠ"] = "Ⴠ",
+ ["ⴡ"] = "Ⴡ",
+ ["ⴢ"] = "Ⴢ",
+ ["ⴣ"] = "Ⴣ",
+ ["ⴤ"] = "Ⴤ",
+ ["ⴥ"] = "Ⴥ",
+ ["a"] = "A",
+ ["b"] = "B",
+ ["c"] = "C",
+ ["d"] = "D",
+ ["e"] = "E",
+ ["f"] = "F",
+ ["g"] = "G",
+ ["h"] = "H",
+ ["i"] = "I",
+ ["j"] = "J",
+ ["k"] = "K",
+ ["l"] = "L",
+ ["m"] = "M",
+ ["n"] = "N",
+ ["o"] = "O",
+ ["p"] = "P",
+ ["q"] = "Q",
+ ["r"] = "R",
+ ["s"] = "S",
+ ["t"] = "T",
+ ["u"] = "U",
+ ["v"] = "V",
+ ["w"] = "W",
+ ["x"] = "X",
+ ["y"] = "Y",
+ ["z"] = "Z",
+ ["𐐨"] = "𐐀",
+ ["𐐩"] = "𐐁",
+ ["𐐪"] = "𐐂",
+ ["𐐫"] = "𐐃",
+ ["𐐬"] = "𐐄",
+ ["𐐭"] = "𐐅",
+ ["𐐮"] = "𐐆",
+ ["𐐯"] = "𐐇",
+ ["𐐰"] = "𐐈",
+ ["𐐱"] = "𐐉",
+ ["𐐲"] = "𐐊",
+ ["𐐳"] = "𐐋",
+ ["𐐴"] = "𐐌",
+ ["𐐵"] = "𐐍",
+ ["𐐶"] = "𐐎",
+ ["𐐷"] = "𐐏",
+ ["𐐸"] = "𐐐",
+ ["𐐹"] = "𐐑",
+ ["𐐺"] = "𐐒",
+ ["𐐻"] = "𐐓",
+ ["𐐼"] = "𐐔",
+ ["𐐽"] = "𐐕",
+ ["𐐾"] = "𐐖",
+ ["𐐿"] = "𐐗",
+ ["𐑀"] = "𐐘",
+ ["𐑁"] = "𐐙",
+ ["𐑂"] = "𐐚",
+ ["𐑃"] = "𐐛",
+ ["𐑄"] = "𐐜",
+ ["𐑅"] = "𐐝",
+ ["𐑆"] = "𐐞",
+ ["𐑇"] = "𐐟",
+ ["𐑈"] = "𐐠",
+ ["𐑉"] = "𐐡",
+ ["𐑊"] = "𐐢",
+ ["𐑋"] = "𐐣",
+ ["𐑌"] = "𐐤",
+ ["𐑍"] = "𐐥",
+ ["𐑎"] = "𐐦",
+ ["𐑏"] = "𐐧",
+}
+
+
+utf8_uc_lc = {
+ ["A"] = "a",
+ ["B"] = "b",
+ ["C"] = "c",
+ ["D"] = "d",
+ ["E"] = "e",
+ ["F"] = "f",
+ ["G"] = "g",
+ ["H"] = "h",
+ ["I"] = "i",
+ ["J"] = "j",
+ ["K"] = "k",
+ ["L"] = "l",
+ ["M"] = "m",
+ ["N"] = "n",
+ ["O"] = "o",
+ ["P"] = "p",
+ ["Q"] = "q",
+ ["R"] = "r",
+ ["S"] = "s",
+ ["T"] = "t",
+ ["U"] = "u",
+ ["V"] = "v",
+ ["W"] = "w",
+ ["X"] = "x",
+ ["Y"] = "y",
+ ["Z"] = "z",
+ ["À"] = "à",
+ ["Á"] = "á",
+ ["Â"] = "â",
+ ["Ã"] = "ã",
+ ["Ä"] = "ä",
+ ["Å"] = "å",
+ ["Æ"] = "æ",
+ ["Ç"] = "ç",
+ ["È"] = "è",
+ ["É"] = "é",
+ ["Ê"] = "ê",
+ ["Ë"] = "ë",
+ ["Ì"] = "ì",
+ ["Í"] = "í",
+ ["Î"] = "î",
+ ["Ï"] = "ï",
+ ["Ð"] = "ð",
+ ["Ñ"] = "ñ",
+ ["Ò"] = "ò",
+ ["Ó"] = "ó",
+ ["Ô"] = "ô",
+ ["Õ"] = "õ",
+ ["Ö"] = "ö",
+ ["Ø"] = "ø",
+ ["Ù"] = "ù",
+ ["Ú"] = "ú",
+ ["Û"] = "û",
+ ["Ü"] = "ü",
+ ["Ý"] = "ý",
+ ["Þ"] = "þ",
+ ["Ā"] = "ā",
+ ["Ă"] = "ă",
+ ["Ą"] = "ą",
+ ["Ć"] = "ć",
+ ["Ĉ"] = "ĉ",
+ ["Ċ"] = "ċ",
+ ["Č"] = "č",
+ ["Ď"] = "ď",
+ ["Đ"] = "đ",
+ ["Ē"] = "ē",
+ ["Ĕ"] = "ĕ",
+ ["Ė"] = "ė",
+ ["Ę"] = "ę",
+ ["Ě"] = "ě",
+ ["Ĝ"] = "ĝ",
+ ["Ğ"] = "ğ",
+ ["Ġ"] = "ġ",
+ ["Ģ"] = "ģ",
+ ["Ĥ"] = "ĥ",
+ ["Ħ"] = "ħ",
+ ["Ĩ"] = "ĩ",
+ ["Ī"] = "ī",
+ ["Ĭ"] = "ĭ",
+ ["Į"] = "į",
+ ["İ"] = "i",
+ ["IJ"] = "ij",
+ ["Ĵ"] = "ĵ",
+ ["Ķ"] = "ķ",
+ ["Ĺ"] = "ĺ",
+ ["Ļ"] = "ļ",
+ ["Ľ"] = "ľ",
+ ["Ŀ"] = "ŀ",
+ ["Ł"] = "ł",
+ ["Ń"] = "ń",
+ ["Ņ"] = "ņ",
+ ["Ň"] = "ň",
+ ["Ŋ"] = "ŋ",
+ ["Ō"] = "ō",
+ ["Ŏ"] = "ŏ",
+ ["Ő"] = "ő",
+ ["Œ"] = "œ",
+ ["Ŕ"] = "ŕ",
+ ["Ŗ"] = "ŗ",
+ ["Ř"] = "ř",
+ ["Ś"] = "ś",
+ ["Ŝ"] = "ŝ",
+ ["Ş"] = "ş",
+ ["Š"] = "š",
+ ["Ţ"] = "ţ",
+ ["Ť"] = "ť",
+ ["Ŧ"] = "ŧ",
+ ["Ũ"] = "ũ",
+ ["Ū"] = "ū",
+ ["Ŭ"] = "ŭ",
+ ["Ů"] = "ů",
+ ["Ű"] = "ű",
+ ["Ų"] = "ų",
+ ["Ŵ"] = "ŵ",
+ ["Ŷ"] = "ŷ",
+ ["Ÿ"] = "ÿ",
+ ["Ź"] = "ź",
+ ["Ż"] = "ż",
+ ["Ž"] = "ž",
+ ["Ɓ"] = "ɓ",
+ ["Ƃ"] = "ƃ",
+ ["Ƅ"] = "ƅ",
+ ["Ɔ"] = "ɔ",
+ ["Ƈ"] = "ƈ",
+ ["Ɖ"] = "ɖ",
+ ["Ɗ"] = "ɗ",
+ ["Ƌ"] = "ƌ",
+ ["Ǝ"] = "ǝ",
+ ["Ə"] = "ə",
+ ["Ɛ"] = "ɛ",
+ ["Ƒ"] = "ƒ",
+ ["Ɠ"] = "ɠ",
+ ["Ɣ"] = "ɣ",
+ ["Ɩ"] = "ɩ",
+ ["Ɨ"] = "ɨ",
+ ["Ƙ"] = "ƙ",
+ ["Ɯ"] = "ɯ",
+ ["Ɲ"] = "ɲ",
+ ["Ɵ"] = "ɵ",
+ ["Ơ"] = "ơ",
+ ["Ƣ"] = "ƣ",
+ ["Ƥ"] = "ƥ",
+ ["Ʀ"] = "ʀ",
+ ["Ƨ"] = "ƨ",
+ ["Ʃ"] = "ʃ",
+ ["Ƭ"] = "ƭ",
+ ["Ʈ"] = "ʈ",
+ ["Ư"] = "ư",
+ ["Ʊ"] = "ʊ",
+ ["Ʋ"] = "ʋ",
+ ["Ƴ"] = "ƴ",
+ ["Ƶ"] = "ƶ",
+ ["Ʒ"] = "ʒ",
+ ["Ƹ"] = "ƹ",
+ ["Ƽ"] = "ƽ",
+ ["DŽ"] = "dž",
+ ["Dž"] = "dž",
+ ["LJ"] = "lj",
+ ["Lj"] = "lj",
+ ["NJ"] = "nj",
+ ["Nj"] = "nj",
+ ["Ǎ"] = "ǎ",
+ ["Ǐ"] = "ǐ",
+ ["Ǒ"] = "ǒ",
+ ["Ǔ"] = "ǔ",
+ ["Ǖ"] = "ǖ",
+ ["Ǘ"] = "ǘ",
+ ["Ǚ"] = "ǚ",
+ ["Ǜ"] = "ǜ",
+ ["Ǟ"] = "ǟ",
+ ["Ǡ"] = "ǡ",
+ ["Ǣ"] = "ǣ",
+ ["Ǥ"] = "ǥ",
+ ["Ǧ"] = "ǧ",
+ ["Ǩ"] = "ǩ",
+ ["Ǫ"] = "ǫ",
+ ["Ǭ"] = "ǭ",
+ ["Ǯ"] = "ǯ",
+ ["DZ"] = "dz",
+ ["Dz"] = "dz",
+ ["Ǵ"] = "ǵ",
+ ["Ƕ"] = "ƕ",
+ ["Ƿ"] = "ƿ",
+ ["Ǹ"] = "ǹ",
+ ["Ǻ"] = "ǻ",
+ ["Ǽ"] = "ǽ",
+ ["Ǿ"] = "ǿ",
+ ["Ȁ"] = "ȁ",
+ ["Ȃ"] = "ȃ",
+ ["Ȅ"] = "ȅ",
+ ["Ȇ"] = "ȇ",
+ ["Ȉ"] = "ȉ",
+ ["Ȋ"] = "ȋ",
+ ["Ȍ"] = "ȍ",
+ ["Ȏ"] = "ȏ",
+ ["Ȑ"] = "ȑ",
+ ["Ȓ"] = "ȓ",
+ ["Ȕ"] = "ȕ",
+ ["Ȗ"] = "ȗ",
+ ["Ș"] = "ș",
+ ["Ț"] = "ț",
+ ["Ȝ"] = "ȝ",
+ ["Ȟ"] = "ȟ",
+ ["Ƞ"] = "ƞ",
+ ["Ȣ"] = "ȣ",
+ ["Ȥ"] = "ȥ",
+ ["Ȧ"] = "ȧ",
+ ["Ȩ"] = "ȩ",
+ ["Ȫ"] = "ȫ",
+ ["Ȭ"] = "ȭ",
+ ["Ȯ"] = "ȯ",
+ ["Ȱ"] = "ȱ",
+ ["Ȳ"] = "ȳ",
+ ["Ⱥ"] = "ⱥ",
+ ["Ȼ"] = "ȼ",
+ ["Ƚ"] = "ƚ",
+ ["Ⱦ"] = "ⱦ",
+ ["Ɂ"] = "ɂ",
+ ["Ƀ"] = "ƀ",
+ ["Ʉ"] = "ʉ",
+ ["Ʌ"] = "ʌ",
+ ["Ɇ"] = "ɇ",
+ ["Ɉ"] = "ɉ",
+ ["Ɋ"] = "ɋ",
+ ["Ɍ"] = "ɍ",
+ ["Ɏ"] = "ɏ",
+ ["Ά"] = "ά",
+ ["Έ"] = "έ",
+ ["Ή"] = "ή",
+ ["Ί"] = "ί",
+ ["Ό"] = "ό",
+ ["Ύ"] = "ύ",
+ ["Ώ"] = "ώ",
+ ["Α"] = "α",
+ ["Β"] = "β",
+ ["Γ"] = "γ",
+ ["Δ"] = "δ",
+ ["Ε"] = "ε",
+ ["Ζ"] = "ζ",
+ ["Η"] = "η",
+ ["Θ"] = "θ",
+ ["Ι"] = "ι",
+ ["Κ"] = "κ",
+ ["Λ"] = "λ",
+ ["Μ"] = "μ",
+ ["Ν"] = "ν",
+ ["Ξ"] = "ξ",
+ ["Ο"] = "ο",
+ ["Π"] = "π",
+ ["Ρ"] = "ρ",
+ ["Σ"] = "σ",
+ ["Τ"] = "τ",
+ ["Υ"] = "υ",
+ ["Φ"] = "φ",
+ ["Χ"] = "χ",
+ ["Ψ"] = "ψ",
+ ["Ω"] = "ω",
+ ["Ϊ"] = "ϊ",
+ ["Ϋ"] = "ϋ",
+ ["Ϙ"] = "ϙ",
+ ["Ϛ"] = "ϛ",
+ ["Ϝ"] = "ϝ",
+ ["Ϟ"] = "ϟ",
+ ["Ϡ"] = "ϡ",
+ ["Ϣ"] = "ϣ",
+ ["Ϥ"] = "ϥ",
+ ["Ϧ"] = "ϧ",
+ ["Ϩ"] = "ϩ",
+ ["Ϫ"] = "ϫ",
+ ["Ϭ"] = "ϭ",
+ ["Ϯ"] = "ϯ",
+ ["ϴ"] = "θ",
+ ["Ϸ"] = "ϸ",
+ ["Ϲ"] = "ϲ",
+ ["Ϻ"] = "ϻ",
+ ["Ͻ"] = "ͻ",
+ ["Ͼ"] = "ͼ",
+ ["Ͽ"] = "ͽ",
+ ["Ѐ"] = "ѐ",
+ ["Ё"] = "ё",
+ ["Ђ"] = "ђ",
+ ["Ѓ"] = "ѓ",
+ ["Є"] = "є",
+ ["Ѕ"] = "ѕ",
+ ["І"] = "і",
+ ["Ї"] = "ї",
+ ["Ј"] = "ј",
+ ["Љ"] = "љ",
+ ["Њ"] = "њ",
+ ["Ћ"] = "ћ",
+ ["Ќ"] = "ќ",
+ ["Ѝ"] = "ѝ",
+ ["Ў"] = "ў",
+ ["Џ"] = "џ",
+ ["А"] = "а",
+ ["Б"] = "б",
+ ["В"] = "в",
+ ["Г"] = "г",
+ ["Д"] = "д",
+ ["Е"] = "е",
+ ["Ж"] = "ж",
+ ["З"] = "з",
+ ["И"] = "и",
+ ["Й"] = "й",
+ ["К"] = "к",
+ ["Л"] = "л",
+ ["М"] = "м",
+ ["Н"] = "н",
+ ["О"] = "о",
+ ["П"] = "п",
+ ["Р"] = "р",
+ ["С"] = "с",
+ ["Т"] = "т",
+ ["У"] = "у",
+ ["Ф"] = "ф",
+ ["Х"] = "х",
+ ["Ц"] = "ц",
+ ["Ч"] = "ч",
+ ["Ш"] = "ш",
+ ["Щ"] = "щ",
+ ["Ъ"] = "ъ",
+ ["Ы"] = "ы",
+ ["Ь"] = "ь",
+ ["Э"] = "э",
+ ["Ю"] = "ю",
+ ["Я"] = "я",
+ ["Ѡ"] = "ѡ",
+ ["Ѣ"] = "ѣ",
+ ["Ѥ"] = "ѥ",
+ ["Ѧ"] = "ѧ",
+ ["Ѩ"] = "ѩ",
+ ["Ѫ"] = "ѫ",
+ ["Ѭ"] = "ѭ",
+ ["Ѯ"] = "ѯ",
+ ["Ѱ"] = "ѱ",
+ ["Ѳ"] = "ѳ",
+ ["Ѵ"] = "ѵ",
+ ["Ѷ"] = "ѷ",
+ ["Ѹ"] = "ѹ",
+ ["Ѻ"] = "ѻ",
+ ["Ѽ"] = "ѽ",
+ ["Ѿ"] = "ѿ",
+ ["Ҁ"] = "ҁ",
+ ["Ҋ"] = "ҋ",
+ ["Ҍ"] = "ҍ",
+ ["Ҏ"] = "ҏ",
+ ["Ґ"] = "ґ",
+ ["Ғ"] = "ғ",
+ ["Ҕ"] = "ҕ",
+ ["Җ"] = "җ",
+ ["Ҙ"] = "ҙ",
+ ["Қ"] = "қ",
+ ["Ҝ"] = "ҝ",
+ ["Ҟ"] = "ҟ",
+ ["Ҡ"] = "ҡ",
+ ["Ң"] = "ң",
+ ["Ҥ"] = "ҥ",
+ ["Ҧ"] = "ҧ",
+ ["Ҩ"] = "ҩ",
+ ["Ҫ"] = "ҫ",
+ ["Ҭ"] = "ҭ",
+ ["Ү"] = "ү",
+ ["Ұ"] = "ұ",
+ ["Ҳ"] = "ҳ",
+ ["Ҵ"] = "ҵ",
+ ["Ҷ"] = "ҷ",
+ ["Ҹ"] = "ҹ",
+ ["Һ"] = "һ",
+ ["Ҽ"] = "ҽ",
+ ["Ҿ"] = "ҿ",
+ ["Ӏ"] = "ӏ",
+ ["Ӂ"] = "ӂ",
+ ["Ӄ"] = "ӄ",
+ ["Ӆ"] = "ӆ",
+ ["Ӈ"] = "ӈ",
+ ["Ӊ"] = "ӊ",
+ ["Ӌ"] = "ӌ",
+ ["Ӎ"] = "ӎ",
+ ["Ӑ"] = "ӑ",
+ ["Ӓ"] = "ӓ",
+ ["Ӕ"] = "ӕ",
+ ["Ӗ"] = "ӗ",
+ ["Ә"] = "ә",
+ ["Ӛ"] = "ӛ",
+ ["Ӝ"] = "ӝ",
+ ["Ӟ"] = "ӟ",
+ ["Ӡ"] = "ӡ",
+ ["Ӣ"] = "ӣ",
+ ["Ӥ"] = "ӥ",
+ ["Ӧ"] = "ӧ",
+ ["Ө"] = "ө",
+ ["Ӫ"] = "ӫ",
+ ["Ӭ"] = "ӭ",
+ ["Ӯ"] = "ӯ",
+ ["Ӱ"] = "ӱ",
+ ["Ӳ"] = "ӳ",
+ ["Ӵ"] = "ӵ",
+ ["Ӷ"] = "ӷ",
+ ["Ӹ"] = "ӹ",
+ ["Ӻ"] = "ӻ",
+ ["Ӽ"] = "ӽ",
+ ["Ӿ"] = "ӿ",
+ ["Ԁ"] = "ԁ",
+ ["Ԃ"] = "ԃ",
+ ["Ԅ"] = "ԅ",
+ ["Ԇ"] = "ԇ",
+ ["Ԉ"] = "ԉ",
+ ["Ԋ"] = "ԋ",
+ ["Ԍ"] = "ԍ",
+ ["Ԏ"] = "ԏ",
+ ["Ԑ"] = "ԑ",
+ ["Ԓ"] = "ԓ",
+ ["Ա"] = "ա",
+ ["Բ"] = "բ",
+ ["Գ"] = "գ",
+ ["Դ"] = "դ",
+ ["Ե"] = "ե",
+ ["Զ"] = "զ",
+ ["Է"] = "է",
+ ["Ը"] = "ը",
+ ["Թ"] = "թ",
+ ["Ժ"] = "ժ",
+ ["Ի"] = "ի",
+ ["Լ"] = "լ",
+ ["Խ"] = "խ",
+ ["Ծ"] = "ծ",
+ ["Կ"] = "կ",
+ ["Հ"] = "հ",
+ ["Ձ"] = "ձ",
+ ["Ղ"] = "ղ",
+ ["Ճ"] = "ճ",
+ ["Մ"] = "մ",
+ ["Յ"] = "յ",
+ ["Ն"] = "ն",
+ ["Շ"] = "շ",
+ ["Ո"] = "ո",
+ ["Չ"] = "չ",
+ ["Պ"] = "պ",
+ ["Ջ"] = "ջ",
+ ["Ռ"] = "ռ",
+ ["Ս"] = "ս",
+ ["Վ"] = "վ",
+ ["Տ"] = "տ",
+ ["Ր"] = "ր",
+ ["Ց"] = "ց",
+ ["Ւ"] = "ւ",
+ ["Փ"] = "փ",
+ ["Ք"] = "ք",
+ ["Օ"] = "օ",
+ ["Ֆ"] = "ֆ",
+ ["Ⴀ"] = "ⴀ",
+ ["Ⴁ"] = "ⴁ",
+ ["Ⴂ"] = "ⴂ",
+ ["Ⴃ"] = "ⴃ",
+ ["Ⴄ"] = "ⴄ",
+ ["Ⴅ"] = "ⴅ",
+ ["Ⴆ"] = "ⴆ",
+ ["Ⴇ"] = "ⴇ",
+ ["Ⴈ"] = "ⴈ",
+ ["Ⴉ"] = "ⴉ",
+ ["Ⴊ"] = "ⴊ",
+ ["Ⴋ"] = "ⴋ",
+ ["Ⴌ"] = "ⴌ",
+ ["Ⴍ"] = "ⴍ",
+ ["Ⴎ"] = "ⴎ",
+ ["Ⴏ"] = "ⴏ",
+ ["Ⴐ"] = "ⴐ",
+ ["Ⴑ"] = "ⴑ",
+ ["Ⴒ"] = "ⴒ",
+ ["Ⴓ"] = "ⴓ",
+ ["Ⴔ"] = "ⴔ",
+ ["Ⴕ"] = "ⴕ",
+ ["Ⴖ"] = "ⴖ",
+ ["Ⴗ"] = "ⴗ",
+ ["Ⴘ"] = "ⴘ",
+ ["Ⴙ"] = "ⴙ",
+ ["Ⴚ"] = "ⴚ",
+ ["Ⴛ"] = "ⴛ",
+ ["Ⴜ"] = "ⴜ",
+ ["Ⴝ"] = "ⴝ",
+ ["Ⴞ"] = "ⴞ",
+ ["Ⴟ"] = "ⴟ",
+ ["Ⴠ"] = "ⴠ",
+ ["Ⴡ"] = "ⴡ",
+ ["Ⴢ"] = "ⴢ",
+ ["Ⴣ"] = "ⴣ",
+ ["Ⴤ"] = "ⴤ",
+ ["Ⴥ"] = "ⴥ",
+ ["Ḁ"] = "ḁ",
+ ["Ḃ"] = "ḃ",
+ ["Ḅ"] = "ḅ",
+ ["Ḇ"] = "ḇ",
+ ["Ḉ"] = "ḉ",
+ ["Ḋ"] = "ḋ",
+ ["Ḍ"] = "ḍ",
+ ["Ḏ"] = "ḏ",
+ ["Ḑ"] = "ḑ",
+ ["Ḓ"] = "ḓ",
+ ["Ḕ"] = "ḕ",
+ ["Ḗ"] = "ḗ",
+ ["Ḙ"] = "ḙ",
+ ["Ḛ"] = "ḛ",
+ ["Ḝ"] = "ḝ",
+ ["Ḟ"] = "ḟ",
+ ["Ḡ"] = "ḡ",
+ ["Ḣ"] = "ḣ",
+ ["Ḥ"] = "ḥ",
+ ["Ḧ"] = "ḧ",
+ ["Ḩ"] = "ḩ",
+ ["Ḫ"] = "ḫ",
+ ["Ḭ"] = "ḭ",
+ ["Ḯ"] = "ḯ",
+ ["Ḱ"] = "ḱ",
+ ["Ḳ"] = "ḳ",
+ ["Ḵ"] = "ḵ",
+ ["Ḷ"] = "ḷ",
+ ["Ḹ"] = "ḹ",
+ ["Ḻ"] = "ḻ",
+ ["Ḽ"] = "ḽ",
+ ["Ḿ"] = "ḿ",
+ ["Ṁ"] = "ṁ",
+ ["Ṃ"] = "ṃ",
+ ["Ṅ"] = "ṅ",
+ ["Ṇ"] = "ṇ",
+ ["Ṉ"] = "ṉ",
+ ["Ṋ"] = "ṋ",
+ ["Ṍ"] = "ṍ",
+ ["Ṏ"] = "ṏ",
+ ["Ṑ"] = "ṑ",
+ ["Ṓ"] = "ṓ",
+ ["Ṕ"] = "ṕ",
+ ["Ṗ"] = "ṗ",
+ ["Ṙ"] = "ṙ",
+ ["Ṛ"] = "ṛ",
+ ["Ṝ"] = "ṝ",
+ ["Ṟ"] = "ṟ",
+ ["Ṡ"] = "ṡ",
+ ["Ṣ"] = "ṣ",
+ ["Ṥ"] = "ṥ",
+ ["Ṧ"] = "ṧ",
+ ["Ṩ"] = "ṩ",
+ ["Ṫ"] = "ṫ",
+ ["Ṭ"] = "ṭ",
+ ["Ṯ"] = "ṯ",
+ ["Ṱ"] = "ṱ",
+ ["Ṳ"] = "ṳ",
+ ["Ṵ"] = "ṵ",
+ ["Ṷ"] = "ṷ",
+ ["Ṹ"] = "ṹ",
+ ["Ṻ"] = "ṻ",
+ ["Ṽ"] = "ṽ",
+ ["Ṿ"] = "ṿ",
+ ["Ẁ"] = "ẁ",
+ ["Ẃ"] = "ẃ",
+ ["Ẅ"] = "ẅ",
+ ["Ẇ"] = "ẇ",
+ ["Ẉ"] = "ẉ",
+ ["Ẋ"] = "ẋ",
+ ["Ẍ"] = "ẍ",
+ ["Ẏ"] = "ẏ",
+ ["Ẑ"] = "ẑ",
+ ["Ẓ"] = "ẓ",
+ ["Ẕ"] = "ẕ",
+ ["Ạ"] = "ạ",
+ ["Ả"] = "ả",
+ ["Ấ"] = "ấ",
+ ["Ầ"] = "ầ",
+ ["Ẩ"] = "ẩ",
+ ["Ẫ"] = "ẫ",
+ ["Ậ"] = "ậ",
+ ["Ắ"] = "ắ",
+ ["Ằ"] = "ằ",
+ ["Ẳ"] = "ẳ",
+ ["Ẵ"] = "ẵ",
+ ["Ặ"] = "ặ",
+ ["Ẹ"] = "ẹ",
+ ["Ẻ"] = "ẻ",
+ ["Ẽ"] = "ẽ",
+ ["Ế"] = "ế",
+ ["Ề"] = "ề",
+ ["Ể"] = "ể",
+ ["Ễ"] = "ễ",
+ ["Ệ"] = "ệ",
+ ["Ỉ"] = "ỉ",
+ ["Ị"] = "ị",
+ ["Ọ"] = "ọ",
+ ["Ỏ"] = "ỏ",
+ ["Ố"] = "ố",
+ ["Ồ"] = "ồ",
+ ["Ổ"] = "ổ",
+ ["Ỗ"] = "ỗ",
+ ["Ộ"] = "ộ",
+ ["Ớ"] = "ớ",
+ ["Ờ"] = "ờ",
+ ["Ở"] = "ở",
+ ["Ỡ"] = "ỡ",
+ ["Ợ"] = "ợ",
+ ["Ụ"] = "ụ",
+ ["Ủ"] = "ủ",
+ ["Ứ"] = "ứ",
+ ["Ừ"] = "ừ",
+ ["Ử"] = "ử",
+ ["Ữ"] = "ữ",
+ ["Ự"] = "ự",
+ ["Ỳ"] = "ỳ",
+ ["Ỵ"] = "ỵ",
+ ["Ỷ"] = "ỷ",
+ ["Ỹ"] = "ỹ",
+ ["Ἀ"] = "ἀ",
+ ["Ἁ"] = "ἁ",
+ ["Ἂ"] = "ἂ",
+ ["Ἃ"] = "ἃ",
+ ["Ἄ"] = "ἄ",
+ ["Ἅ"] = "ἅ",
+ ["Ἆ"] = "ἆ",
+ ["Ἇ"] = "ἇ",
+ ["Ἐ"] = "ἐ",
+ ["Ἑ"] = "ἑ",
+ ["Ἒ"] = "ἒ",
+ ["Ἓ"] = "ἓ",
+ ["Ἔ"] = "ἔ",
+ ["Ἕ"] = "ἕ",
+ ["Ἠ"] = "ἠ",
+ ["Ἡ"] = "ἡ",
+ ["Ἢ"] = "ἢ",
+ ["Ἣ"] = "ἣ",
+ ["Ἤ"] = "ἤ",
+ ["Ἥ"] = "ἥ",
+ ["Ἦ"] = "ἦ",
+ ["Ἧ"] = "ἧ",
+ ["Ἰ"] = "ἰ",
+ ["Ἱ"] = "ἱ",
+ ["Ἲ"] = "ἲ",
+ ["Ἳ"] = "ἳ",
+ ["Ἴ"] = "ἴ",
+ ["Ἵ"] = "ἵ",
+ ["Ἶ"] = "ἶ",
+ ["Ἷ"] = "ἷ",
+ ["Ὀ"] = "ὀ",
+ ["Ὁ"] = "ὁ",
+ ["Ὂ"] = "ὂ",
+ ["Ὃ"] = "ὃ",
+ ["Ὄ"] = "ὄ",
+ ["Ὅ"] = "ὅ",
+ ["Ὑ"] = "ὑ",
+ ["Ὓ"] = "ὓ",
+ ["Ὕ"] = "ὕ",
+ ["Ὗ"] = "ὗ",
+ ["Ὠ"] = "ὠ",
+ ["Ὡ"] = "ὡ",
+ ["Ὢ"] = "ὢ",
+ ["Ὣ"] = "ὣ",
+ ["Ὤ"] = "ὤ",
+ ["Ὥ"] = "ὥ",
+ ["Ὦ"] = "ὦ",
+ ["Ὧ"] = "ὧ",
+ ["ᾈ"] = "ᾀ",
+ ["ᾉ"] = "ᾁ",
+ ["ᾊ"] = "ᾂ",
+ ["ᾋ"] = "ᾃ",
+ ["ᾌ"] = "ᾄ",
+ ["ᾍ"] = "ᾅ",
+ ["ᾎ"] = "ᾆ",
+ ["ᾏ"] = "ᾇ",
+ ["ᾘ"] = "ᾐ",
+ ["ᾙ"] = "ᾑ",
+ ["ᾚ"] = "ᾒ",
+ ["ᾛ"] = "ᾓ",
+ ["ᾜ"] = "ᾔ",
+ ["ᾝ"] = "ᾕ",
+ ["ᾞ"] = "ᾖ",
+ ["ᾟ"] = "ᾗ",
+ ["ᾨ"] = "ᾠ",
+ ["ᾩ"] = "ᾡ",
+ ["ᾪ"] = "ᾢ",
+ ["ᾫ"] = "ᾣ",
+ ["ᾬ"] = "ᾤ",
+ ["ᾭ"] = "ᾥ",
+ ["ᾮ"] = "ᾦ",
+ ["ᾯ"] = "ᾧ",
+ ["Ᾰ"] = "ᾰ",
+ ["Ᾱ"] = "ᾱ",
+ ["Ὰ"] = "ὰ",
+ ["Ά"] = "ά",
+ ["ᾼ"] = "ᾳ",
+ ["Ὲ"] = "ὲ",
+ ["Έ"] = "έ",
+ ["Ὴ"] = "ὴ",
+ ["Ή"] = "ή",
+ ["ῌ"] = "ῃ",
+ ["Ῐ"] = "ῐ",
+ ["Ῑ"] = "ῑ",
+ ["Ὶ"] = "ὶ",
+ ["Ί"] = "ί",
+ ["Ῠ"] = "ῠ",
+ ["Ῡ"] = "ῡ",
+ ["Ὺ"] = "ὺ",
+ ["Ύ"] = "ύ",
+ ["Ῥ"] = "ῥ",
+ ["Ὸ"] = "ὸ",
+ ["Ό"] = "ό",
+ ["Ὼ"] = "ὼ",
+ ["Ώ"] = "ώ",
+ ["ῼ"] = "ῳ",
+ ["Ω"] = "ω",
+ ["K"] = "k",
+ ["Å"] = "å",
+ ["Ⅎ"] = "ⅎ",
+ ["Ⅰ"] = "ⅰ",
+ ["Ⅱ"] = "ⅱ",
+ ["Ⅲ"] = "ⅲ",
+ ["Ⅳ"] = "ⅳ",
+ ["Ⅴ"] = "ⅴ",
+ ["Ⅵ"] = "ⅵ",
+ ["Ⅶ"] = "ⅶ",
+ ["Ⅷ"] = "ⅷ",
+ ["Ⅸ"] = "ⅸ",
+ ["Ⅹ"] = "ⅹ",
+ ["Ⅺ"] = "ⅺ",
+ ["Ⅻ"] = "ⅻ",
+ ["Ⅼ"] = "ⅼ",
+ ["Ⅽ"] = "ⅽ",
+ ["Ⅾ"] = "ⅾ",
+ ["Ⅿ"] = "ⅿ",
+ ["Ↄ"] = "ↄ",
+ ["Ⓐ"] = "ⓐ",
+ ["Ⓑ"] = "ⓑ",
+ ["Ⓒ"] = "ⓒ",
+ ["Ⓓ"] = "ⓓ",
+ ["Ⓔ"] = "ⓔ",
+ ["Ⓕ"] = "ⓕ",
+ ["Ⓖ"] = "ⓖ",
+ ["Ⓗ"] = "ⓗ",
+ ["Ⓘ"] = "ⓘ",
+ ["Ⓙ"] = "ⓙ",
+ ["Ⓚ"] = "ⓚ",
+ ["Ⓛ"] = "ⓛ",
+ ["Ⓜ"] = "ⓜ",
+ ["Ⓝ"] = "ⓝ",
+ ["Ⓞ"] = "ⓞ",
+ ["Ⓟ"] = "ⓟ",
+ ["Ⓠ"] = "ⓠ",
+ ["Ⓡ"] = "ⓡ",
+ ["Ⓢ"] = "ⓢ",
+ ["Ⓣ"] = "ⓣ",
+ ["Ⓤ"] = "ⓤ",
+ ["Ⓥ"] = "ⓥ",
+ ["Ⓦ"] = "ⓦ",
+ ["Ⓧ"] = "ⓧ",
+ ["Ⓨ"] = "ⓨ",
+ ["Ⓩ"] = "ⓩ",
+ ["Ⰰ"] = "ⰰ",
+ ["Ⰱ"] = "ⰱ",
+ ["Ⰲ"] = "ⰲ",
+ ["Ⰳ"] = "ⰳ",
+ ["Ⰴ"] = "ⰴ",
+ ["Ⰵ"] = "ⰵ",
+ ["Ⰶ"] = "ⰶ",
+ ["Ⰷ"] = "ⰷ",
+ ["Ⰸ"] = "ⰸ",
+ ["Ⰹ"] = "ⰹ",
+ ["Ⰺ"] = "ⰺ",
+ ["Ⰻ"] = "ⰻ",
+ ["Ⰼ"] = "ⰼ",
+ ["Ⰽ"] = "ⰽ",
+ ["Ⰾ"] = "ⰾ",
+ ["Ⰿ"] = "ⰿ",
+ ["Ⱀ"] = "ⱀ",
+ ["Ⱁ"] = "ⱁ",
+ ["Ⱂ"] = "ⱂ",
+ ["Ⱃ"] = "ⱃ",
+ ["Ⱄ"] = "ⱄ",
+ ["Ⱅ"] = "ⱅ",
+ ["Ⱆ"] = "ⱆ",
+ ["Ⱇ"] = "ⱇ",
+ ["Ⱈ"] = "ⱈ",
+ ["Ⱉ"] = "ⱉ",
+ ["Ⱊ"] = "ⱊ",
+ ["Ⱋ"] = "ⱋ",
+ ["Ⱌ"] = "ⱌ",
+ ["Ⱍ"] = "ⱍ",
+ ["Ⱎ"] = "ⱎ",
+ ["Ⱏ"] = "ⱏ",
+ ["Ⱐ"] = "ⱐ",
+ ["Ⱑ"] = "ⱑ",
+ ["Ⱒ"] = "ⱒ",
+ ["Ⱓ"] = "ⱓ",
+ ["Ⱔ"] = "ⱔ",
+ ["Ⱕ"] = "ⱕ",
+ ["Ⱖ"] = "ⱖ",
+ ["Ⱗ"] = "ⱗ",
+ ["Ⱘ"] = "ⱘ",
+ ["Ⱙ"] = "ⱙ",
+ ["Ⱚ"] = "ⱚ",
+ ["Ⱛ"] = "ⱛ",
+ ["Ⱜ"] = "ⱜ",
+ ["Ⱝ"] = "ⱝ",
+ ["Ⱞ"] = "ⱞ",
+ ["Ⱡ"] = "ⱡ",
+ ["Ɫ"] = "ɫ",
+ ["Ᵽ"] = "ᵽ",
+ ["Ɽ"] = "ɽ",
+ ["Ⱨ"] = "ⱨ",
+ ["Ⱪ"] = "ⱪ",
+ ["Ⱬ"] = "ⱬ",
+ ["Ⱶ"] = "ⱶ",
+ ["Ⲁ"] = "ⲁ",
+ ["Ⲃ"] = "ⲃ",
+ ["Ⲅ"] = "ⲅ",
+ ["Ⲇ"] = "ⲇ",
+ ["Ⲉ"] = "ⲉ",
+ ["Ⲋ"] = "ⲋ",
+ ["Ⲍ"] = "ⲍ",
+ ["Ⲏ"] = "ⲏ",
+ ["Ⲑ"] = "ⲑ",
+ ["Ⲓ"] = "ⲓ",
+ ["Ⲕ"] = "ⲕ",
+ ["Ⲗ"] = "ⲗ",
+ ["Ⲙ"] = "ⲙ",
+ ["Ⲛ"] = "ⲛ",
+ ["Ⲝ"] = "ⲝ",
+ ["Ⲟ"] = "ⲟ",
+ ["Ⲡ"] = "ⲡ",
+ ["Ⲣ"] = "ⲣ",
+ ["Ⲥ"] = "ⲥ",
+ ["Ⲧ"] = "ⲧ",
+ ["Ⲩ"] = "ⲩ",
+ ["Ⲫ"] = "ⲫ",
+ ["Ⲭ"] = "ⲭ",
+ ["Ⲯ"] = "ⲯ",
+ ["Ⲱ"] = "ⲱ",
+ ["Ⲳ"] = "ⲳ",
+ ["Ⲵ"] = "ⲵ",
+ ["Ⲷ"] = "ⲷ",
+ ["Ⲹ"] = "ⲹ",
+ ["Ⲻ"] = "ⲻ",
+ ["Ⲽ"] = "ⲽ",
+ ["Ⲿ"] = "ⲿ",
+ ["Ⳁ"] = "ⳁ",
+ ["Ⳃ"] = "ⳃ",
+ ["Ⳅ"] = "ⳅ",
+ ["Ⳇ"] = "ⳇ",
+ ["Ⳉ"] = "ⳉ",
+ ["Ⳋ"] = "ⳋ",
+ ["Ⳍ"] = "ⳍ",
+ ["Ⳏ"] = "ⳏ",
+ ["Ⳑ"] = "ⳑ",
+ ["Ⳓ"] = "ⳓ",
+ ["Ⳕ"] = "ⳕ",
+ ["Ⳗ"] = "ⳗ",
+ ["Ⳙ"] = "ⳙ",
+ ["Ⳛ"] = "ⳛ",
+ ["Ⳝ"] = "ⳝ",
+ ["Ⳟ"] = "ⳟ",
+ ["Ⳡ"] = "ⳡ",
+ ["Ⳣ"] = "ⳣ",
+ ["A"] = "a",
+ ["B"] = "b",
+ ["C"] = "c",
+ ["D"] = "d",
+ ["E"] = "e",
+ ["F"] = "f",
+ ["G"] = "g",
+ ["H"] = "h",
+ ["I"] = "i",
+ ["J"] = "j",
+ ["K"] = "k",
+ ["L"] = "l",
+ ["M"] = "m",
+ ["N"] = "n",
+ ["O"] = "o",
+ ["P"] = "p",
+ ["Q"] = "q",
+ ["R"] = "r",
+ ["S"] = "s",
+ ["T"] = "t",
+ ["U"] = "u",
+ ["V"] = "v",
+ ["W"] = "w",
+ ["X"] = "x",
+ ["Y"] = "y",
+ ["Z"] = "z",
+ ["𐐀"] = "𐐨",
+ ["𐐁"] = "𐐩",
+ ["𐐂"] = "𐐪",
+ ["𐐃"] = "𐐫",
+ ["𐐄"] = "𐐬",
+ ["𐐅"] = "𐐭",
+ ["𐐆"] = "𐐮",
+ ["𐐇"] = "𐐯",
+ ["𐐈"] = "𐐰",
+ ["𐐉"] = "𐐱",
+ ["𐐊"] = "𐐲",
+ ["𐐋"] = "𐐳",
+ ["𐐌"] = "𐐴",
+ ["𐐍"] = "𐐵",
+ ["𐐎"] = "𐐶",
+ ["𐐏"] = "𐐷",
+ ["𐐐"] = "𐐸",
+ ["𐐑"] = "𐐹",
+ ["𐐒"] = "𐐺",
+ ["𐐓"] = "𐐻",
+ ["𐐔"] = "𐐼",
+ ["𐐕"] = "𐐽",
+ ["𐐖"] = "𐐾",
+ ["𐐗"] = "𐐿",
+ ["𐐘"] = "𐑀",
+ ["𐐙"] = "𐑁",
+ ["𐐚"] = "𐑂",
+ ["𐐛"] = "𐑃",
+ ["𐐜"] = "𐑄",
+ ["𐐝"] = "𐑅",
+ ["𐐞"] = "𐑆",
+ ["𐐟"] = "𐑇",
+ ["𐐠"] = "𐑈",
+ ["𐐡"] = "𐑉",
+ ["𐐢"] = "𐑊",
+ ["𐐣"] = "𐑋",
+ ["𐐤"] = "𐑌",
+ ["𐐥"] = "𐑍",
+ ["𐐦"] = "𐑎",
+ ["𐐧"] = "𐑏",
+}
+
diff --git a/ElvUI/Libraries/oUF/LICENSE b/ElvUI/Libraries/oUF/LICENSE
new file mode 100644
index 0000000..b8e3658
--- /dev/null
+++ b/ElvUI/Libraries/oUF/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2006-2017 Trond A Ekseth
+Copyright (c) 2016-2017 Val Voronov
+Copyright (c) 2016-2017 Adrian L Lange
+Copyright (c) 2016-2017 Rainrider
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/ElvUI/Libraries/oUF/blizzard.lua b/ElvUI/Libraries/oUF/blizzard.lua
new file mode 100644
index 0000000..dd46de3
--- /dev/null
+++ b/ElvUI/Libraries/oUF/blizzard.lua
@@ -0,0 +1,112 @@
+local parent, ns = ...
+local oUF = ns.oUF
+
+-- sourced from Blizzard_ArenaUI/Blizzard_ArenaUI.lua
+local MAX_ARENA_ENEMIES = MAX_ARENA_ENEMIES or 5
+
+-- sourced from FrameXML/TargetFrame.lua
+local MAX_BOSS_FRAMES = MAX_BOSS_FRAMES or 4
+
+-- sourced from FrameXML/PartyMemberFrame.lua
+local MAX_PARTY_MEMBERS = MAX_PARTY_MEMBERS or 4
+
+local hiddenParent = CreateFrame('Frame', nil, UIParent)
+hiddenParent:SetAllPoints()
+hiddenParent:Hide()
+
+local function handleFrame(baseName)
+ local frame
+ if(type(baseName) == 'string') then
+ frame = _G[baseName]
+ else
+ frame = baseName
+ end
+
+ if(frame) then
+ frame:UnregisterAllEvents()
+ frame:Hide()
+
+ -- Keep frame hidden without causing taint
+ frame:SetParent(hiddenParent)
+
+ local health = frame.healthBar or frame.healthbar
+ if(health) then
+ health:UnregisterAllEvents()
+ end
+
+ local power = frame.manabar
+ if(power) then
+ power:UnregisterAllEvents()
+ end
+
+ local spell = frame.castBar or frame.spellbar
+ if(spell) then
+ spell:UnregisterAllEvents()
+ end
+
+ local buffFrame = frame.BuffFrame
+ if(buffFrame) then
+ buffFrame:UnregisterAllEvents()
+ end
+ end
+end
+
+function oUF:DisableBlizzard(unit)
+ if(not unit) then return end
+
+ if(unit == 'player') then
+ handleFrame(PlayerFrame)
+
+ -- For the damn vehicle support:
+ PlayerFrame:RegisterEvent('PLAYER_ENTERING_WORLD')
+ PlayerFrame:RegisterEvent('UNIT_ENTERING_VEHICLE')
+ PlayerFrame:RegisterEvent('UNIT_ENTERED_VEHICLE')
+ PlayerFrame:RegisterEvent('UNIT_EXITING_VEHICLE')
+ PlayerFrame:RegisterEvent('UNIT_EXITED_VEHICLE')
+
+ -- User placed frames don't animate
+ PlayerFrame:SetUserPlaced(true)
+ PlayerFrame:SetDontSavePosition(true)
+ elseif(unit == 'pet') then
+ handleFrame(PetFrame)
+ elseif(unit == 'target') then
+ handleFrame(TargetFrame)
+ handleFrame(ComboFrame)
+ elseif(unit == 'focus') then
+ handleFrame(FocusFrame)
+ handleFrame(TargetofFocusFrame)
+ elseif(unit == 'targettarget') then
+ handleFrame(TargetFrameToT)
+ elseif(unit:match('boss%d?$')) then
+ local id = unit:match('boss(%d)')
+ if(id) then
+ handleFrame('Boss' .. id .. 'TargetFrame')
+ else
+ for i = 1, MAX_BOSS_FRAMES do
+ handleFrame(string.format('Boss%dTargetFrame', i))
+ end
+ end
+ elseif(unit:match('party%d?$')) then
+ local id = unit:match('party(%d)')
+ if(id) then
+ handleFrame('PartyMemberFrame' .. id)
+ else
+ for i = 1, MAX_PARTY_MEMBERS do
+ handleFrame(string.format('PartyMemberFrame%d', i))
+ end
+ end
+ elseif(unit:match('arena%d?$')) then
+ local id = unit:match('arena(%d)')
+ if(id) then
+ handleFrame('ArenaEnemyFrame' .. id)
+ else
+ for i = 1, MAX_ARENA_ENEMIES do
+ handleFrame(string.format('ArenaEnemyFrame%d', i))
+ end
+ end
+
+ -- Blizzard_ArenaUI should not be loaded
+ Arena_LoadUI = function() end
+ SetCVar('showArenaEnemyFrames', '0', 'SHOW_ARENA_ENEMY_FRAMES_TEXT')
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/colors.lua b/ElvUI/Libraries/oUF/colors.lua
new file mode 100644
index 0000000..e3446c4
--- /dev/null
+++ b/ElvUI/Libraries/oUF/colors.lua
@@ -0,0 +1,212 @@
+local parent, ns = ...
+local oUF = ns.oUF
+local Private = oUF.Private
+
+local frame_metatable = Private.frame_metatable
+
+local colors = {
+ smooth = {
+ 1, 0, 0,
+ 1, 1, 0,
+ 0, 1, 0
+ },
+ health = {49 / 255, 207 / 255, 37 / 255},
+ disconnected = {.6, .6, .6},
+ tapped = {.6, .6, .6},
+ threshold_20 = {1, 0, 0},
+ threshold_35 = {1, 0, 0.8},
+ threshold_50 = {1, 0.5, 0},
+ threshold_75 = {1, 1, 0},
+ runes = {
+ {1, 0, 0}, -- blood
+ {0, 0.5, 0}, -- unholy
+ {0, 1, 1}, -- frost
+ {0.9, 0.1, 1}, -- death
+ },
+ class = {},
+ debuff = {},
+ reaction = {},
+ power = {},
+ threat = {},
+}
+
+for debuffType, color in next, DebuffTypeColor do
+ colors.debuff[debuffType] = {color.r, color.g, color.b}
+end
+
+for eclass, color in next, FACTION_BAR_COLORS do
+ colors.reaction[eclass] = {color.r, color.g, color.b}
+end
+
+for power, color in next, PowerBarColor do
+ if (type(power) == 'string') then
+ if(type(select(2, next(color))) == 'table') then
+ colors.power[power] = {}
+
+ for index, color in next, color do
+ colors.power[power][index] = {color.r, color.g, color.b}
+ end
+ else
+ colors.power[power] = {color.r, color.g, color.b, atlas = color.atlas}
+ end
+ end
+end
+
+-- sourced from FrameXML/Constants.lua
+colors.power[0] = colors.power.MANA
+colors.power[1] = colors.power.RAGE
+colors.power[2] = colors.power.FOCUS
+colors.power[3] = colors.power.ENERGY
+colors.power[4] = colors.power.HAPPINESS
+colors.power[5] = colors.power.RUNES
+colors.power[6] = colors.power.RUNIC_POWER
+
+for i = 0, 3 do
+ colors.threat[i] = {GetThreatStatusColor(i)}
+end
+
+local function colorsAndPercent(a, b, ...)
+ if(a <= 0 or b == 0) then
+ return nil, ...
+ elseif(a >= b) then
+ return nil, select(-3, ...)
+ end
+
+ local num = select('#', ...) / 3
+ local segment, relperc = math.modf((a / b) * (num - 1))
+ return relperc, select((segment * 3) + 1, ...)
+end
+
+-- http://www.wowwiki.com/ColorGradient
+--[[ Colors: oUF:RGBColorGradient(a, b, ...)
+Used to convert a percent value (the quotient of `a` and `b`) into a gradient from 2 or more RGB colors. If more than 2
+colors are passed, the gradient will be between the two colors which perc lies in an evenly divided range. A RGB color
+is a sequence of 3 consecutive RGB percent values (in the range [0-1]). If `a` is negative or `b` is zero then the first
+RGB color (the first 3 RGB values passed to the function) is returned. If `a` is bigger than or equal to `b`, then the
+last 3 RGB values are returned.
+
+* self - the global oUF object
+* a - value used as numerator to calculate the percentage (number)
+* b - value used as denominator to calculate the percentage (number)
+* ... - a list of RGB percent values. At least 6 values should be passed (number [0-1])
+--]]
+function oUF:RGBColorGradient(...)
+ local relperc, r1, g1, b1, r2, g2, b2 = colorsAndPercent(...)
+ if(relperc) then
+ return r1 + (r2 - r1) * relperc, g1 + (g2 - g1) * relperc, b1 + (b2 - b1) * relperc
+ else
+ return r1, g1, b1
+ end
+end
+
+-- HCY functions are based on http://www.chilliant.com/rgb2hsv.html
+local function getY(r, g, b)
+ return 0.299 * r + 0.587 * g + 0.114 * b
+end
+
+local function rgbToHCY(r, g, b)
+ local min, max = math.min(r, g, b), math.max(r, g, b)
+ local chroma = max - min
+ local hue
+ if(chroma > 0) then
+ if(r == max) then
+ hue = ((g - b) / chroma) % 6
+ elseif(g == max) then
+ hue = (b - r) / chroma + 2
+ elseif(b == max) then
+ hue = (r - g) / chroma + 4
+ end
+ hue = hue / 6
+ end
+ return hue, chroma, getY(r, g, b)
+end
+
+local function hcyToRGB(hue, chroma, luma)
+ local r, g, b = 0, 0, 0
+ if(hue and luma > 0) then
+ local h2 = hue * 6
+ local x = chroma * (1 - math.abs(h2 % 2 - 1))
+ if(h2 < 1) then
+ r, g, b = chroma, x, 0
+ elseif(h2 < 2) then
+ r, g, b = x, chroma, 0
+ elseif(h2 < 3) then
+ r, g, b = 0, chroma, x
+ elseif(h2 < 4) then
+ r, g, b = 0, x, chroma
+ elseif(h2 < 5) then
+ r, g, b = x, 0, chroma
+ else
+ r, g, b = chroma, 0, x
+ end
+
+ local y = getY(r, g, b)
+ if(luma < y) then
+ chroma = chroma * (luma / y)
+ elseif(y < 1) then
+ chroma = chroma * (1 - luma) / (1 - y)
+ end
+
+ r = (r - y) * chroma + luma
+ g = (g - y) * chroma + luma
+ b = (b - y) * chroma + luma
+ end
+ return r, g, b
+end
+
+--[[ Colors: oUF:HCYColorGradient(a, b, ...)
+Used to convert a percent value (the quotient of `a` and `b`) into a gradient from 2 or more HCY colors. If more than 2
+colors are passed, the gradient will be between the two colors which perc lies in an evenly divided range. A HCY color
+is a sequence of 3 consecutive values in the range [0-1]. If `a` is negative or `b` is zero then the first
+HCY color (the first 3 HCY values passed to the function) is returned. If `a` is bigger than or equal to `b`, then the
+last 3 HCY values are returned.
+
+* self - the global oUF object
+* a - value used as numerator to calculate the percentage (number)
+* b - value used as denominator to calculate the percentage (number)
+* ... - a list of HCY color values. At least 6 values should be passed (number [0-1])
+--]]
+function oUF:HCYColorGradient(...)
+ local relperc, r1, g1, b1, r2, g2, b2 = colorsAndPercent(...)
+ if(not relperc) then
+ return r1, g1, b1
+ end
+
+ local h1, c1, y1 = rgbToHCY(r1, g1, b1)
+ local h2, c2, y2 = rgbToHCY(r2, g2, b2)
+ local c = c1 + (c2 - c1) * relperc
+ local y = y1 + (y2 - y1) * relperc
+
+ if(h1 and h2) then
+ local dh = h2 - h1
+ if(dh < -0.5) then
+ dh = dh + 1
+ elseif(dh > 0.5) then
+ dh = dh - 1
+ end
+
+ return hcyToRGB((h1 + dh * relperc) % 1, c, y)
+ else
+ return hcyToRGB(h1 or h2, c, y)
+ end
+
+end
+
+--[[ Colors: oUF:ColorGradient(a, b, ...) or frame:ColorGradient(a, b, ...)
+Used as a proxy to call the proper gradient function depending on the user's preference. If `oUF.useHCYColorGradient` is
+set to true, `:HCYColorGradient` will be called, else `:RGBColorGradient`.
+
+* self - the global oUF object or a unit frame
+* a - value used as numerator to calculate the percentage (number)
+* b - value used as denominator to calculate the percentage (number)
+* ... - a list of color values. At least 6 values should be passed (number [0-1])
+--]]
+function oUF:ColorGradient(...)
+ return (oUF.useHCYColorGradient and oUF.HCYColorGradient or oUF.RGBColorGradient)(self, ...)
+end
+
+oUF.colors = colors
+oUF.useHCYColorGradient = false
+
+frame_metatable.__index.colors = colors
+frame_metatable.__index.ColorGradient = oUF.ColorGradient
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/additionalpower.lua b/ElvUI/Libraries/oUF/elements/additionalpower.lua
new file mode 100644
index 0000000..bc272d1
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/additionalpower.lua
@@ -0,0 +1,259 @@
+--[[
+# Element: Additional Power Bar
+
+Handles the visibility and updating of a status bar that displays the player's additional power, such as Mana for druids.
+
+## Widget
+
+AdditionalPower - A `StatusBar` that is used to display the player's additional power.
+
+## Sub-Widgets
+
+.bg - A `Texture` used as a background. Inherits the widget's color.
+
+## Notes
+
+A default texture will be applied if the widget is a StatusBar and doesn't have a texture set.
+
+## Options
+
+.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
+
+The following options are listed by priority. The first check that returns true decides the color of the bar.
+
+.colorPower - Use `self.colors.power[token]` to color the bar based on the player's additional power type
+ (boolean)
+.colorClass - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
+ second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass.html) (boolean)
+.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth gradient based on the player's current
+ additional power percentage (boolean)
+
+## Sub-Widget Options
+
+.multiplier - Used to tint the background based on the widget's R, G and B values. Defaults to 1 (number)[0-1]
+
+## Examples
+
+ -- Position and size
+ local AdditionalPower = CreateFrame('StatusBar', nil, self)
+ AdditionalPower:SetSize(20, 20)
+ AdditionalPower:SetPoint('TOP')
+ AdditionalPower:SetPoint('LEFT')
+ AdditionalPower:SetPoint('RIGHT')
+
+ -- Add a background
+ local Background = AdditionalPower:CreateTexture(nil, 'BACKGROUND')
+ Background:SetAllPoints(AdditionalPower)
+ Background:SetTexture(1, 1, 1, .5)
+
+ -- Register it with oUF
+ AdditionalPower.bg = Background
+ self.AdditionalPower = AdditionalPower
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+-- ElvUI block
+local unpack = unpack
+local UnitIsPlayer = UnitIsPlayer
+local UnitClass = UnitClass
+local UnitPower = UnitPower
+local UnitPowerMax = UnitPowerMax
+local UnitHasVehicleUI = UnitHasVehicleUI
+local UnitPowerType = UnitPowerType
+-- end block
+
+-- sourced from FrameXML/AlternatePowerBar.lua
+local ADDITIONAL_POWER_BAR_NAME = ADDITIONAL_POWER_BAR_NAME or 'MANA'
+local ADDITIONAL_POWER_BAR_INDEX = ADDITIONAL_POWER_BAR_INDEX or 0
+
+local function UpdateColor(self, event, unit, powertype)
+ if(not (unit and unit == 'player') and powertype == ADDITIONAL_POWER_BAR_NAME) then return end
+ local element = self.AdditionalPower
+
+ local r, g, b, t
+ if(element.colorPower) then
+ t = self.colors.power[ADDITIONAL_POWER_BAR_INDEX]
+ elseif(element.colorClass and UnitIsPlayer(unit)) then
+ t = oUF.herocolor
+ elseif(element.colorSmooth) then
+ r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth))
+ end
+
+ if(t) then
+ r, g, b = t[1], t[2], t[3]
+ end
+
+ if(b) then
+ element:SetStatusBarColor(r, g, b)
+
+ local bg = element.bg
+ if(bg) then
+ local mu = bg.multiplier or 1
+ bg:SetVertexColor(r * mu, g * mu, b * mu)
+ end
+ end
+
+ if(element.PostUpdateColor) then
+ element:PostUpdateColor(unit, r, g, b)
+ end
+end
+
+local function ColorPath(self, ...)
+ --[[ Override: AdditionalPower.UpdateColor(self, event, unit, ...)
+ Used to completely override the internal function for updating the widgets' colors.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ * ... - the arguments accompanying the event
+ --]]
+ (self.AdditionalPower.UpdateColor or UpdateColor) (self, ...)
+end
+
+local function Update(self, event, unit, powertype)
+ if(not (unit and unit == 'player') and powertype == ADDITIONAL_POWER_BAR_NAME) then return end
+
+ local element = self.AdditionalPower
+ --[[ Callback: AdditionalPower:PreUpdate(unit)
+ Called before the element has been updated.
+
+ * self - the AdditionalPower element
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate(unit)
+ end
+
+ local cur = UnitPower('player', ADDITIONAL_POWER_BAR_INDEX)
+ local max = UnitPowerMax('player', ADDITIONAL_POWER_BAR_INDEX)
+
+ element:SetMinMaxValues(0, max)
+ element:SetValue(cur)
+
+ element.cur = cur
+ element.max = max
+
+ --[[ Callback: AdditionalPower:PostUpdate(unit, cur, max)
+ Called after the element has been updated.
+
+ * self - the AdditionalPower element
+ * unit - the unit for which the update has been triggered (string)
+ * cur - the current value of the player's additional power (number)
+ * max - the maximum value of the player's additional power (number)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(unit, cur, max, event) -- ElvUI adds event
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: AdditionalPower.Override(self, event, unit, ...)
+ Used to completely override the element's update process.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ * ... - the arguments accompanying the event
+ --]]
+ (self.AdditionalPower.Override or Update) (self, ...)
+
+ ColorPath(self, ...)
+end
+
+local function ElementEnable(self)
+ local element = self.AdditionalPower
+
+ self:RegisterEvent('UNIT_MANA', Path)
+ self:RegisterEvent('UNIT_MAXMANA', Path)
+
+ element:Show()
+
+ -- ElvUI block
+ if element.PostUpdateVisibility then
+ element:PostUpdateVisibility(true, not element.isEnabled)
+ end
+
+ element.isEnabled = true
+ -- end block
+
+ Path(self, 'ElementEnable', 'player', ADDITIONAL_POWER_BAR_NAME)
+end
+
+local function ElementDisable(self)
+ self:UnregisterEvent('UNIT_MAXMANA', Path)
+ self:UnregisterEvent('UNIT_MANA', Path)
+
+ self.AdditionalPower:Hide()
+
+ -- ElvUI block
+ local element = self.AdditionalPower
+ if element.PostUpdateVisibility then
+ element:PostUpdateVisibility(false, element.isEnabled)
+ end
+
+ element.isEnabled = nil
+ -- end block
+
+ Path(self, 'ElementDisable', 'player', ADDITIONAL_POWER_BAR_NAME)
+end
+
+local function Visibility(self, event, unit)
+ local element = self.AdditionalPower
+ local shouldEnable
+
+ if(not UnitHasVehicleUI('player')) then
+ if((UnitPowerType('player') ~= ADDITIONAL_POWER_BAR_INDEX) and (UnitPowerMax('player', ADDITIONAL_POWER_BAR_INDEX) ~= 0)) then
+ shouldEnable = true
+ end
+ end
+
+ if(shouldEnable) then
+ ElementEnable(self)
+ else
+ ElementDisable(self)
+ end
+end
+
+local function VisibilityPath(self, ...)
+ --[[ Override: AdditionalPower.OverrideVisibility(self, event, unit)
+ Used to completely override the element's visibility update process.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ --]]
+ (self.AdditionalPower.OverrideVisibility or Visibility) (self, ...)
+end
+
+local function ForceUpdate(element)
+ VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+local function Enable(self, unit)
+ local element = self.AdditionalPower
+ if(element and unit == 'player') then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
+
+ if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then
+ element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.AdditionalPower
+ if(element) then
+ ElementDisable(self)
+
+ self:UnregisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
+ end
+end
+
+oUF:AddElement('AdditionalPower', VisibilityPath, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/assistantindicator.lua b/ElvUI/Libraries/oUF/elements/assistantindicator.lua
new file mode 100644
index 0000000..dfa0376
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/assistantindicator.lua
@@ -0,0 +1,103 @@
+--[[
+# Element: Assistant Indicator
+
+Toggles the visibility of an indicator based on the unit's raid assistant status.
+
+## Widget
+
+AssistantIndicator - Any UI widget.
+
+## Notes
+
+A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
+
+## Examples
+
+ -- Position and size
+ local AssistantIndicator = self:CreateTexture(nil, 'OVERLAY')
+ AssistantIndicator:SetSize(16, 16)
+ AssistantIndicator:SetPoint('TOP', self)
+
+ -- Register it with oUF
+ self.AssistantIndicator = AssistantIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local UnitInRaid = UnitInRaid
+local UnitIsPartyLeader = UnitIsPartyLeader
+local UnitIsRaidOfficer = UnitIsRaidOfficer
+
+local function Update(self, event)
+ local element = self.AssistantIndicator
+
+ --[[ Callback: AssistantIndicator:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the AssistantIndicator element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local unit = self.unit
+ local isAssistant = UnitInRaid(unit) and UnitIsRaidOfficer(unit) and not UnitIsPartyLeader(unit)
+ if(isAssistant) then
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ --[[ Callback: AssistantIndicator:PostUpdate(isAssistant)
+ Called after the element has been updated.
+
+ * self - the AssistantIndicator element
+ * isAssistant - indicates whether the unit is a raid assistant (boolean)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(isAssistant)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: AssistantIndicator.Override(self, event, ...)
+ Used to completely override the element's update process.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * ... - the arguments accompanying the event (string)
+ --]]
+ return (self.AssistantIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate')
+end
+
+local function Enable(self)
+ local element = self.AssistantIndicator
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path, true)
+
+ if(element:IsObjectType('Texture') and not element:GetTexture()) then
+ element:SetTexture([[Interface\GroupFrame\UI-Group-AssistantIcon]])
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.AssistantIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
+ end
+end
+
+oUF:AddElement('AssistantIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/auras.lua b/ElvUI/Libraries/oUF/elements/auras.lua
new file mode 100644
index 0000000..b7472b7
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/auras.lua
@@ -0,0 +1,611 @@
+--[[
+# Element: Auras
+
+Handles creation and updating of aura icons.
+
+## Widget
+
+Auras - A Frame to hold `Button`s representing both buffs and debuffs.
+Buffs - A Frame to hold `Button`s representing buffs.
+Debuffs - A Frame to hold `Button`s representing debuffs.
+
+## Notes
+
+At least one of the above widgets must be present for the element to work.
+
+## Options
+
+.disableMouse - Disables mouse events (boolean)
+.disableCooldown - Disables the cooldown spiral (boolean)
+.size - Aura icon size. Defaults to 16 (number)
+.onlyShowPlayer - Shows only auras created by player/vehicle (boolean)
+.showStealableBuffs - Displays the stealable texture on buffs that can be stolen (boolean)
+.spacing - Spacing between each icon. Defaults to 0 (number)
+.['spacing-x'] - Horizontal spacing between each icon. Takes priority over `spacing` (number)
+.['spacing-y'] - Vertical spacing between each icon. Takes priority over `spacing` (number)
+.['growth-x'] - Horizontal growth direction. Defaults to 'RIGHT' (string)
+.['growth-y'] - Vertical growth direction. Defaults to 'UP' (string)
+.initialAnchor - Anchor point for the icons. Defaults to 'BOTTOMLEFT' (string)
+.filter - Custom filter list for auras to display. Defaults to 'HELPFUL' for buffs and 'HARMFUL' for
+ debuffs (string)
+.tooltipAnchor - Anchor point for the tooltip. Defaults to 'ANCHOR_BOTTOMRIGHT', however, if a frame has anchoring
+ restrictions it will be set to 'ANCHOR_CURSOR' (string)
+
+## Options Auras
+
+.numBuffs - The maximum number of buffs to display. Defaults to 32 (number)
+.numDebuffs - The maximum number of debuffs to display. Defaults to 40 (number)
+.numTotal - The maximum number of auras to display. Prioritizes buffs over debuffs. Defaults to the sum of
+ .numBuffs and .numDebuffs (number)
+.gap - Controls the creation of an invisible icon between buffs and debuffs. Defaults to false (boolean)
+.buffFilter - Custom filter list for buffs to display. Takes priority over `filter` (string)
+.debuffFilter - Custom filter list for debuffs to display. Takes priority over `filter` (string)
+
+## Options Buffs
+
+.num - Number of buffs to display. Defaults to 32 (number)
+
+## Options Debuffs
+
+.num - Number of debuffs to display. Defaults to 40 (number)
+
+## Attributes
+
+button.caster - the unit who cast the aura (string)
+button.filter - the filter list used to determine the visibility of the aura (string)
+button.isDebuff - indicates if the button holds a debuff (boolean)
+button.isPlayer - indicates if the aura caster is the player or their vehicle (boolean)
+
+## Examples
+
+ -- Position and size
+ local Buffs = CreateFrame('Frame', nil, self)
+ Buffs:SetPoint('RIGHT', self, 'LEFT')
+ Buffs:SetSize(16 * 2, 16 * 16)
+
+ -- Register with oUF
+ self.Buffs = Buffs
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local VISIBLE = 1
+local HIDDEN = 0
+
+-- ElvUI changed block
+local CREATED = 2
+local pcall = pcall
+local tinsert = tinsert
+local CreateFrame = CreateFrame
+local GetSpellInfo = GetSpellInfo
+local UnitAura = UnitAura
+local UnitIsUnit = UnitIsUnit
+local floor, min = math.floor, math.min
+-- GLOBALS: GameTooltip
+-- end block
+
+local function UpdateTooltip(self)
+ GameTooltip:SetUnitAura(self:GetParent().__owner.unit, self:GetID(), self.filter)
+end
+
+local function onEnter(self)
+ if(not self:IsVisible()) then return end
+
+ GameTooltip:SetOwner(self, self:GetParent().tooltipAnchor)
+ self:UpdateTooltip()
+end
+
+local function onLeave()
+ GameTooltip:Hide()
+end
+
+local function createAuraIcon(element, index)
+ local button = CreateFrame('Button', '$parentButton' .. index, element)
+ button:RegisterForClicks('RightButtonUp')
+
+ local cd = CreateFrame('Cooldown', '$parentCooldown', button, 'CooldownFrameTemplate')
+ cd:SetFrameLevel(button:GetFrameLevel() + 1)
+ cd:SetAllPoints()
+
+ local icon = button:CreateTexture(nil, 'BORDER')
+ icon:SetAllPoints()
+
+ local countFrame = CreateFrame('Frame', '$parentCount', button)
+ countFrame:SetAllPoints(button)
+ countFrame:SetFrameLevel(cd:GetFrameLevel() + 1)
+
+ local count = countFrame:CreateFontString(nil, 'OVERLAY', 'NumberFontNormal')
+ count:SetPoint('BOTTOMRIGHT', countFrame, 'BOTTOMRIGHT', -1, 0)
+
+ local overlay = button:CreateTexture(nil, 'OVERLAY')
+ overlay:SetTexture([[Interface\Buttons\UI-Debuff-Overlays]])
+ overlay:SetAllPoints()
+ overlay:SetTexCoord(.296875, .5703125, 0, .515625)
+ button.overlay = overlay
+
+ local stealable = button:CreateTexture(nil, 'OVERLAY')
+ stealable:SetTexture([[Interface\TargetingFrame\UI-TargetingFrame-Stealable]])
+ stealable:SetPoint('TOPLEFT', -3, 3)
+ stealable:SetPoint('BOTTOMRIGHT', 3, -3)
+ stealable:SetBlendMode('ADD')
+ button.stealable = stealable
+
+ button.UpdateTooltip = UpdateTooltip
+ button:SetScript('OnEnter', onEnter)
+ button:SetScript('OnLeave', onLeave)
+
+ button.icon = icon
+ button.count = count
+ button.cd = cd
+
+ --[[ Callback: Auras:PostCreateIcon(button)
+ Called after a new aura button has been created.
+
+ * self - the widget holding the aura buttons
+ * button - the newly created aura button (Button)
+ --]]
+ if(element.PostCreateIcon) then element:PostCreateIcon(button) end
+
+ return button
+end
+
+local function customFilter(element, unit, button, name)
+ if((element.onlyShowPlayer and button.isPlayer) or (not element.onlyShowPlayer and name)) then
+ return true
+ end
+end
+
+local function updateIcon(element, unit, index, offset, filter, isDebuff, visible)
+ local name, rank, texture, count, debuffType, duration, expiration, caster, isStealable, shouldConsolidate, spellID = UnitAura(unit, index, filter)
+
+ -- count may be nil sometimes
+ count = count or 0
+
+ -- ElvUI block
+ if element.forceShow or element.forceCreate then
+ spellID = 47540
+ name, rank, texture = GetSpellInfo(spellID)
+ if element.forceShow then
+ count, debuffType, duration, expiration, caster, isStealable, shouldConsolidate = 5, 'Magic', 0, 60, 'player', nil, nil
+ end
+ end
+ -- end Block
+
+ if(name) then
+ local position = visible + offset + 1
+ local button = element[position]
+ if(not button) then
+ --[[ Override: Auras:CreateIcon(position)
+ Used to create the aura button at a given position.
+
+ * self - the widget holding the aura buttons
+ * position - the position at which the aura button is to be created (number)
+
+ ## Returns
+
+ * button - the button used to represent the aura (Button)
+ --]]
+ button = (element.CreateIcon or createAuraIcon) (element, position)
+
+ tinsert(element, button)
+ element.createdIcons = element.createdIcons + 1
+ end
+
+ button.caster = caster
+ button.filter = filter
+ button.isDebuff = isDebuff
+ button.isPlayer = caster == 'player' or caster == 'vehicle'
+
+ --[[ Override: Auras:CustomFilter(unit, button, ...)
+ Defines a custom filter that controls if the aura button should be shown.
+
+ * self - the widget holding the aura buttons
+ * unit - the unit on which the aura is cast (string)
+ * button - the button displaying the aura (Button)
+ * ... - the return values from [UnitAura](http://wowprogramming.com/docs/api/UnitAura.html)
+
+ ## Returns
+
+ * show - indicates whether the aura button should be shown (boolean)
+ --]]
+
+ -- ElvUI changed block
+ local show = not element.forceCreate
+ if not (element.forceShow or element.forceCreate) then
+ show = (element.CustomFilter or customFilter) (element, unit, button, name, rank, texture, count, debuffType, duration, expiration, caster, isStealable, shouldConsolidate, spellID)
+ end
+ -- end block
+
+ if(show) then
+ -- We might want to consider delaying the creation of an actual cooldown
+ -- object to this point, but I think that will just make things needlessly
+ -- complicated.
+ if(button.cd and not element.disableCooldown) then
+ if(duration and duration > 0) then
+ button.cd:SetCooldown(expiration - duration, duration)
+ button.cd:Show()
+ else
+ button.cd:Hide()
+ end
+ end
+
+ if(button.overlay) then
+ if((isDebuff and element.showDebuffType) or (not isDebuff and element.showBuffType) or element.showType) then
+ local color = element.__owner.colors.debuff[debuffType] or element.__owner.colors.debuff.none
+
+ button.overlay:SetVertexColor(color[1], color[2], color[3])
+ button.overlay:Show()
+ else
+ button.overlay:Hide()
+ end
+ end
+
+ if(button.stealable) then
+ if(not isDebuff and isStealable and element.showStealableBuffs and not UnitIsUnit('player', unit)) then
+ button.stealable:Show()
+ else
+ button.stealable:Hide()
+ end
+ end
+
+ if(button.icon) then button.icon:SetTexture(texture) end
+ if(button.count) then button.count:SetText(count > 1 and count) end
+
+ local size = element.size or 16
+ button:SetSize(size, size)
+
+ button:EnableMouse(not element.disableMouse)
+ button:SetID(index)
+ button:Show()
+
+ --[[ Callback: Auras:PostUpdateIcon(unit, button, index, position)
+ Called after the aura button has been updated.
+
+ * self - the widget holding the aura buttons
+ * unit - the unit on which the aura is cast (string)
+ * button - the updated aura button (Button)
+ * index - the index of the aura (number)
+ * position - the actual position of the aura button (number)
+ * duration - the aura duration in seconds (number?)
+ * expiration - the point in time when the aura will expire. Comparable to GetTime() (number)
+ * debuffType - the debuff type of the aura (string?)['Curse', 'Disease', 'Magic', 'Poison']
+ * isStealable - whether the aura can be stolen or purged (boolean)
+ --]]
+ if(element.PostUpdateIcon) then
+ element:PostUpdateIcon(unit, button, index, position, duration, expiration, debuffType, isStealable)
+ end
+
+ return VISIBLE
+ -- ElvUI changed block
+ elseif element.forceCreate then
+ local size = element.size or 16
+ button:SetSize(size, size)
+ button:Hide()
+
+ if element.PostUpdateIcon then
+ element:PostUpdateIcon(unit, button, index, position, duration, expiration, debuffType, isStealable)
+ end
+
+ return CREATED
+ -- end block
+ else
+ return HIDDEN
+ end
+ end
+end
+
+local function SetPosition(element, from, to)
+ local sizex = (element.size or 16) + (element['spacing-x'] or element.spacing or 0)
+ local sizey = (element.size or 16) + (element['spacing-y'] or element.spacing or 0)
+ local anchor = element.initialAnchor or 'BOTTOMLEFT'
+ local growthx = (element['growth-x'] == 'LEFT' and -1) or 1
+ local growthy = (element['growth-y'] == 'DOWN' and -1) or 1
+ local cols = floor(element:GetWidth() / sizex + 0.5)
+
+ for i = from, to do
+ local button = element[i]
+
+ -- Bail out if the to range is out of scope.
+ if(not button) then break end
+ local col = (i - 1) % cols
+ local row = floor((i - 1) / cols)
+
+ button:ClearAllPoints()
+ button:SetPoint(anchor, element, anchor, col * sizex * growthx, row * sizey * growthy)
+ end
+end
+
+local function filterIcons(element, unit, filter, limit, isDebuff, offset, dontHide)
+ if(not offset) then offset = 0 end
+ local index = 1
+ local visible = 0
+ local hidden = 0
+ -- ElvUI changed block
+ local created = 0
+ -- end block
+ while(visible < limit) do
+ local result = updateIcon(element, unit, index, offset, filter, isDebuff, visible)
+ if(not result) then
+ break
+ elseif(result == VISIBLE) then
+ visible = visible + 1
+ elseif(result == HIDDEN) then
+ hidden = hidden + 1
+ -- ElvUI changed block
+ elseif result == CREATED then
+ visible = visible + 1
+ created = created + 1
+ -- end block
+ end
+
+ index = index + 1
+ end
+
+ -- ElvUI changed block
+ visible = visible - created
+ -- end block
+
+ if(not dontHide) then
+ for i = visible + offset + 1, #element do
+ element[i]:Hide()
+ end
+ end
+
+ return visible, hidden
+end
+
+local function UpdateAuras(self, event, unit)
+ if(self.unit ~= unit) then return end
+
+ local auras = self.Auras
+ if(auras) then
+ --[[ Callback: Auras:PreUpdate(unit)
+ Called before the element has been updated.
+
+ * self - the widget holding the aura buttons
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(auras.PreUpdate) then auras:PreUpdate(unit) end
+
+ local numBuffs = auras.numBuffs or 32
+ local numDebuffs = auras.numDebuffs or 40
+ local max = auras.numTotal or numBuffs + numDebuffs
+
+ local visibleBuffs = filterIcons(auras, unit, auras.buffFilter or auras.filter or 'HELPFUL', min(numBuffs, max), nil, 0, true)
+
+ local hasGap
+ if(visibleBuffs ~= 0 and auras.gap) then
+ hasGap = true
+ visibleBuffs = visibleBuffs + 1
+
+ local button = auras[visibleBuffs]
+ if(not button) then
+ button = (auras.CreateIcon or createAuraIcon) (auras, visibleBuffs)
+ tinsert(auras, button)
+ auras.createdIcons = auras.createdIcons + 1
+ end
+
+ -- Prevent the button from displaying anything.
+ if(button.cd) then button.cd:Hide() end
+ if(button.icon) then button.icon:SetTexture() end
+ if(button.overlay) then button.overlay:Hide() end
+ if(button.stealable) then button.stealable:Hide() end
+ if(button.count) then button.count:SetText() end
+
+ button:EnableMouse(false)
+ button:Show()
+
+ --[[ Callback: Auras:PostUpdateGapIcon(unit, gapButton, visibleBuffs)
+ Called after an invisible aura button has been created. Only used by Auras when the `gap` option is enabled.
+
+ * self - the widget holding the aura buttons
+ * unit - the unit that has the invisible aura button (string)
+ * gapButton - the invisible aura button (Button)
+ * visibleBuffs - the number of currently visible aura buttons (number)
+ --]]
+ if(auras.PostUpdateGapIcon) then
+ auras:PostUpdateGapIcon(unit, button, visibleBuffs)
+ end
+ end
+
+ local visibleDebuffs = filterIcons(auras, unit, auras.debuffFilter or auras.filter or 'HARMFUL', min(numDebuffs, max - visibleBuffs), true, visibleBuffs)
+ auras.visibleDebuffs = visibleDebuffs
+
+ if(hasGap and visibleDebuffs == 0) then
+ auras[visibleBuffs]:Hide()
+ visibleBuffs = visibleBuffs - 1
+ end
+
+ auras.visibleBuffs = visibleBuffs
+ auras.visibleAuras = auras.visibleBuffs + auras.visibleDebuffs
+
+ local fromRange, toRange
+ --[[ Callback: Auras:PreSetPosition(max)
+ Called before the aura buttons have been (re-)anchored.
+
+ * self - the widget holding the aura buttons
+ * max - the maximum possible number of aura buttons (number)
+
+ ## Returns
+
+ * from - the offset of the first aura button to be (re-)anchored (number)
+ * to - the offset of the last aura button to be (re-)anchored (number)
+ --]]
+ if(auras.PreSetPosition) then
+ fromRange, toRange = auras:PreSetPosition(max)
+ end
+
+ if(fromRange or auras.createdIcons > auras.anchoredIcons) then
+ --[[ Override: Auras:SetPosition(from, to)
+ Used to (re-)anchor the aura buttons.
+ Called when new aura buttons have been created or if :PreSetPosition is defined.
+
+ * self - the widget that holds the aura buttons
+ * from - the offset of the first aura button to be (re-)anchored (number)
+ * to - the offset of the last aura button to be (re-)anchored (number)
+ --]]
+ (auras.SetPosition or SetPosition) (auras, fromRange or auras.anchoredIcons + 1, toRange or auras.createdIcons)
+ auras.anchoredIcons = auras.createdIcons
+ end
+
+ --[[ Callback: Auras:PostUpdate(unit)
+ Called after the element has been updated.
+
+ * self - the widget holding the aura buttons
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(auras.PostUpdate) then auras:PostUpdate(unit) end
+ end
+
+ local buffs = self.Buffs
+ if(buffs) then
+ if(buffs.PreUpdate) then buffs:PreUpdate(unit) end
+
+ local numBuffs = buffs.num or 32
+ local visibleBuffs = filterIcons(buffs, unit, buffs.filter or 'HELPFUL', numBuffs)
+ buffs.visibleBuffs = visibleBuffs
+
+ local fromRange, toRange
+ if(buffs.PreSetPosition) then
+ fromRange, toRange = buffs:PreSetPosition(numBuffs)
+ end
+
+ if(fromRange or buffs.createdIcons > buffs.anchoredIcons) then
+ (buffs.SetPosition or SetPosition) (buffs, fromRange or buffs.anchoredIcons + 1, toRange or buffs.createdIcons)
+ buffs.anchoredIcons = buffs.createdIcons
+ end
+
+ if(buffs.PostUpdate) then buffs:PostUpdate(unit) end
+ end
+
+ local debuffs = self.Debuffs
+ if(debuffs) then
+ if(debuffs.PreUpdate) then debuffs:PreUpdate(unit) end
+
+ local numDebuffs = debuffs.num or 40
+ local visibleDebuffs = filterIcons(debuffs, unit, debuffs.filter or 'HARMFUL', numDebuffs, true)
+ debuffs.visibleDebuffs = visibleDebuffs
+
+ local fromRange, toRange
+ if(debuffs.PreSetPosition) then
+ fromRange, toRange = debuffs:PreSetPosition(numDebuffs)
+ end
+
+ if(fromRange or debuffs.createdIcons > debuffs.anchoredIcons) then
+ (debuffs.SetPosition or SetPosition) (debuffs, fromRange or debuffs.anchoredIcons + 1, toRange or debuffs.createdIcons)
+ debuffs.anchoredIcons = debuffs.createdIcons
+ end
+
+ if(debuffs.PostUpdate) then debuffs:PostUpdate(unit) end
+ end
+end
+
+local function Update(self, event, unit)
+ if(self.unit ~= unit) then return end
+
+ UpdateAuras(self, event, unit)
+
+ -- Assume no event means someone wants to re-anchor things. This is usually
+ -- done by UpdateAllElements and :ForceUpdate.
+ if(event == 'ForceUpdate' or not event) then
+ local buffs = self.Buffs
+ if(buffs) then
+ (buffs.SetPosition or SetPosition) (buffs, 1, buffs.createdIcons)
+ end
+
+ local debuffs = self.Debuffs
+ if(debuffs) then
+ (debuffs.SetPosition or SetPosition) (debuffs, 1, debuffs.createdIcons)
+ end
+
+ local auras = self.Auras
+ if(auras) then
+ (auras.SetPosition or SetPosition) (auras, 1, auras.createdIcons)
+ end
+ end
+end
+
+local function ForceUpdate(element)
+ return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+local function Enable(self)
+ if(self.Buffs or self.Debuffs or self.Auras) then
+ self:RegisterEvent('UNIT_AURA', UpdateAuras)
+
+ local buffs = self.Buffs
+ if(buffs) then
+ buffs.__owner = self
+ buffs.ForceUpdate = ForceUpdate
+
+ buffs.createdIcons = buffs.createdIcons or 0
+ buffs.anchoredIcons = 0
+
+ -- Avoid parenting GameTooltip to frames with anchoring restrictions,
+ -- otherwise it'll inherit said restrictions which will cause issues
+ -- with its further positioning, clamping, etc
+ if(not pcall(self.GetCenter, self)) then
+ buffs.tooltipAnchor = 'ANCHOR_CURSOR'
+ else
+ buffs.tooltipAnchor = buffs.tooltipAnchor or 'ANCHOR_BOTTOMRIGHT'
+ end
+
+ buffs:Show()
+ end
+
+ local debuffs = self.Debuffs
+ if(debuffs) then
+ debuffs.__owner = self
+ debuffs.ForceUpdate = ForceUpdate
+
+ debuffs.createdIcons = debuffs.createdIcons or 0
+ debuffs.anchoredIcons = 0
+
+ -- Avoid parenting GameTooltip to frames with anchoring restrictions,
+ -- otherwise it'll inherit said restrictions which will cause issues
+ -- with its further positioning, clamping, etc
+ if(not pcall(self.GetCenter, self)) then
+ debuffs.tooltipAnchor = 'ANCHOR_CURSOR'
+ else
+ debuffs.tooltipAnchor = debuffs.tooltipAnchor or 'ANCHOR_BOTTOMRIGHT'
+ end
+
+ debuffs:Show()
+ end
+
+ local auras = self.Auras
+ if(auras) then
+ auras.__owner = self
+ auras.ForceUpdate = ForceUpdate
+
+ auras.createdIcons = auras.createdIcons or 0
+ auras.anchoredIcons = 0
+
+ -- Avoid parenting GameTooltip to frames with anchoring restrictions,
+ -- otherwise it'll inherit said restrictions which will cause issues
+ -- with its further positioning, clamping, etc
+ if(not pcall(self.GetCenter, self)) then
+ auras.tooltipAnchor = 'ANCHOR_CURSOR'
+ else
+ auras.tooltipAnchor = auras.tooltipAnchor or 'ANCHOR_BOTTOMRIGHT'
+ end
+
+ auras:Show()
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ if(self.Buffs or self.Debuffs or self.Auras) then
+ self:UnregisterEvent('UNIT_AURA', UpdateAuras)
+
+ if(self.Buffs) then self.Buffs:Hide() end
+ if(self.Debuffs) then self.Debuffs:Hide() end
+ if(self.Auras) then self.Auras:Hide() end
+ end
+end
+
+oUF:AddElement('Auras', Update, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/castbar.lua b/ElvUI/Libraries/oUF/elements/castbar.lua
new file mode 100644
index 0000000..fea5633
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/castbar.lua
@@ -0,0 +1,544 @@
+--[[
+# Element: Castbar
+
+Handles the visibility and updating of spell castbars.
+
+## Widget
+
+Castbar - A `StatusBar` to represent spell cast/channel progress.
+
+## Sub-Widgets
+
+.Icon - A `Texture` to represent spell icon.
+.SafeZone - A `Texture` to represent latency.
+.Shield - A `Texture` to represent if it's possible to interrupt or spell steal.
+.Spark - A `Texture` to represent the castbar's edge.
+.Text - A `FontString` to represent spell name.
+.Time - A `FontString` to represent spell duration.
+
+## Notes
+
+A default texture will be applied to the StatusBar and Texture widgets if they don't have a texture or a color set.
+
+## Options
+
+.timeToHold - Indicates for how many seconds the castbar should be visible after a _FAILED or _INTERRUPTED
+ event. Defaults to 0 (number)
+.hideTradeSkills - Makes the element ignore casts related to crafting professions (boolean)
+
+## Attributes
+
+.castID - A globally unique identifier of the currently cast spell (string?)
+.casting - Indicates whether the current spell is an ordinary cast (boolean)
+.channeling - Indicates whether the current spell is a channeled cast (boolean)
+.notInterruptible - Indicates whether the current spell is interruptible (boolean)
+
+## Examples
+
+ -- Position and size
+ local Castbar = CreateFrame('StatusBar', nil, self)
+ Castbar:SetSize(20, 20)
+ Castbar:SetPoint('TOP')
+ Castbar:SetPoint('LEFT')
+ Castbar:SetPoint('RIGHT')
+
+ -- Add a background
+ local Background = Castbar:CreateTexture(nil, 'BACKGROUND')
+ Background:SetAllPoints(Castbar)
+ Background:SetTexture(1, 1, 1, .5)
+
+ -- Add a spark
+ local Spark = Castbar:CreateTexture(nil, 'OVERLAY')
+ Spark:SetSize(20, 20)
+ Spark:SetBlendMode('ADD')
+ Spark:SetPoint('CENTER', Castbar:GetStatusBarTexture(), 'RIGHT', 0, 0)
+
+ -- Add a timer
+ local Time = Castbar:CreateFontString(nil, 'OVERLAY', 'GameFontNormalSmall')
+ Time:SetPoint('RIGHT', Castbar)
+
+ -- Add spell text
+ local Text = Castbar:CreateFontString(nil, 'OVERLAY', 'GameFontNormalSmall')
+ Text:SetPoint('LEFT', Castbar)
+
+ -- Add spell icon
+ local Icon = Castbar:CreateTexture(nil, 'OVERLAY')
+ Icon:SetSize(20, 20)
+ Icon:SetPoint('TOPLEFT', Castbar, 'TOPLEFT')
+
+ -- Add Shield
+ local Shield = Castbar:CreateTexture(nil, 'OVERLAY')
+ Shield:SetSize(20, 20)
+ Shield:SetPoint('CENTER', Castbar)
+
+ -- Add safezone
+ local SafeZone = Castbar:CreateTexture(nil, 'OVERLAY')
+
+ -- Register it with oUF
+ Castbar.bg = Background
+ Castbar.Spark = Spark
+ Castbar.Time = Time
+ Castbar.Text = Text
+ Castbar.Icon = Icon
+ Castbar.Shield = Shield
+ Castbar.SafeZone = SafeZone
+ self.Castbar = Castbar
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local select = select
+local GetNetStats = GetNetStats
+local GetTime = GetTime
+local UnitCastingInfo = UnitCastingInfo
+local UnitChannelInfo = UnitChannelInfo
+local tradeskillCurrent, tradeskillTotal, mergeTradeskill = 0, 0, false -- ElvUI
+
+local DEFAULT_ICON = [[Interface\ICONS\INV_Misc_QuestionMark]]
+
+local function resetAttributes(self)
+ self.castID = nil
+ self.casting = nil
+ self.channeling = nil
+ self.notInterruptible = nil
+ self.spellName = nil -- ElvUI
+end
+
+-- ElvUI block
+local UNIT_SPELLCAST_SENT = function (self, event, unit, _, _, target)
+ local castbar = self.Castbar
+ castbar.curTarget = (target and target ~= "") and target or nil
+end
+-- end block
+
+local function CastStart(self, event, unit)
+ if(self.unit ~= unit) then return end
+
+ local element = self.Castbar
+ local name, _, _, texture, startTime, endTime, isTradeSkill, castID, notInterruptible = UnitCastingInfo(unit)
+ event = 'UNIT_SPELLCAST_START'
+ if(not name) then
+ name, _, _, texture, startTime, endTime, isTradeSkill, notInterruptible = UnitChannelInfo(unit)
+ event = 'UNIT_SPELLCAST_CHANNEL_START'
+ end
+
+ if(not name or (isTradeSkill and element.hideTradeSkills)) then
+ resetAttributes(element)
+ element:Hide()
+
+ return
+ end
+
+ endTime = endTime / 1000
+ startTime = startTime / 1000
+
+ element.max = endTime - startTime
+ element.startTime = startTime
+ element.delay = 0
+ element.casting = event == 'UNIT_SPELLCAST_START'
+ element.channeling = event == 'UNIT_SPELLCAST_CHANNEL_START'
+ element.notInterruptible = notInterruptible
+ element.holdTime = 0
+ element.castID = castID
+ element.spellName = name -- ElvUI
+
+ if(element.casting) then
+ element.duration = GetTime() - startTime
+ else
+ element.duration = endTime - GetTime()
+ end
+
+ if(mergeTradeskill and isTradeSkill and self.unit == 'player') then
+ element.duration = element.duration + (element.max * tradeskillCurrent)
+ element.max = element.max * tradeskillTotal
+ element.holdTime = 1
+ element.tradeSkillCastId = castID
+
+ if(unit == "player") then
+ tradeskillCurrent = tradeskillCurrent + 1
+ end
+ end
+
+ element:SetMinMaxValues(0, element.max)
+ element:SetValue(element.duration)
+
+ if(element.Icon) then element.Icon:SetTexture(texture or DEFAULT_ICON) end
+ if(element.Shield) then element.Shield:SetShown(notInterruptible) end
+ if(element.Spark) then element.Spark:Show() end
+ if(element.Text) then element.Text:SetText(name) end
+ if(element.Time) then element.Time:SetText() end
+
+ local safeZone = element.SafeZone
+ if(safeZone) then
+ local isHoriz = element:GetOrientation() == 'HORIZONTAL'
+
+ safeZone:ClearAllPoints()
+ safeZone:SetPoint(isHoriz and 'TOP' or 'LEFT')
+ safeZone:SetPoint(isHoriz and 'BOTTOM' or 'RIGHT')
+
+ if(element.casting) then
+ safeZone:SetPoint(isHoriz and 'RIGHT' or 'TOP')
+ else
+ safeZone:SetPoint(isHoriz and 'LEFT' or 'BOTTOM')
+ end
+
+ local ratio = (select(3, GetNetStats()) / 1000) / element.max
+ if(ratio > 1) then
+ ratio = 1
+ end
+
+ safeZone[isHoriz and 'SetWidth' or 'SetHeight'](safeZone, element[isHoriz and 'GetWidth' or 'GetHeight'](element) * ratio)
+ end
+
+ --[[ Callback: Castbar:PostCastStart(unit)
+ Called after the element has been updated upon a spell cast start.
+
+ * self - the Castbar widget
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PostCastStart) then
+ element:PostCastStart(unit)
+ end
+
+ element:Show()
+end
+
+local function CastUpdate(self, event, unit, _, _, castID)
+ if(self.unit ~= unit) then return end
+
+ local element = self.Castbar
+ if(not element:IsShown() or element.castID and element.castID ~= castID) then
+ return
+ end
+
+ local name, startTime, endTime, _
+ if(event == 'UNIT_SPELLCAST_DELAYED') then
+ name, _, _, _, startTime, endTime = UnitCastingInfo(unit)
+ else
+ name, _, _, _, startTime, endTime = UnitChannelInfo(unit)
+ end
+
+ if(not name) then return end
+
+ endTime = endTime / 1000
+ startTime = startTime / 1000
+
+ local delta
+ if(element.casting) then
+ delta = startTime - element.startTime
+
+ element.duration = GetTime() - startTime
+ else
+ delta = element.startTime - startTime
+
+ element.duration = endTime - GetTime()
+ end
+
+ if(delta < 0) then
+ delta = 0
+ end
+
+ element.max = endTime - startTime
+ element.startTime = startTime
+ element.delay = element.delay + delta
+
+ element:SetMinMaxValues(0, element.max)
+ element:SetValue(element.duration)
+
+ --[[ Callback: Castbar:PostCastUpdate(unit)
+ Called after the element has been updated when a spell cast has been updated.
+
+ * self - the Castbar widget
+ * unit - the unit that the update has been triggered (string)
+ --]]
+ if(element.PostCastUpdate) then
+ return element:PostCastUpdate(unit)
+ end
+end
+
+local function CastStop(self, event, unit, _, _, castID)
+ if(self.unit ~= unit) then return end
+
+ local element = self.Castbar
+ if(not element:IsShown() or element.castID and element.castID ~= castID) then
+ return
+ end
+
+ -- ElvUI block
+ if(mergeTradeskill and self.unit == 'player') then
+ if(tradeskillCurrent == tradeskillTotal) then
+ mergeTradeskill = false
+ end
+ end
+ -- end block
+
+ resetAttributes(element)
+
+ --[[ Callback: Castbar:PostCastStop(unit)
+ Called after the element has been updated when a spell cast has stopped.
+
+ * self - the Castbar widget
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PostCastStop) then
+ return element:PostCastStop(unit)
+ end
+end
+
+local function CastFail(self, event, unit, _, _, castID)
+ if(self.unit ~= unit) then return end
+
+ local element = self.Castbar
+ if(not element:IsShown() or element.castID ~= castID) then
+ return
+ end
+
+ if(element.Text) then
+ element.Text:SetText(event == 'UNIT_SPELLCAST_FAILED' and FAILED or INTERRUPTED)
+ end
+
+ if(element.Spark) then element.Spark:Hide() end
+
+ element.holdTime = element.timeToHold or 0
+
+ -- ElvUI block
+ if(mergeTradeskill and self.unit == 'player') then
+ mergeTradeskill = false
+ element.tradeSkillCastId = nil
+ end
+ -- end block
+
+ resetAttributes(element)
+ element:SetValue(element.max)
+
+ --[[ Callback: Castbar:PostCastFail(unit)
+ Called after the element has been updated upon a failed spell cast.
+
+ * self - the Castbar widget
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PostCastFail) then
+ return element:PostCastFail(unit)
+ end
+end
+
+local function CastInterruptible(self, event, unit)
+ if(self.unit ~= unit) then return end
+
+ local element = self.Castbar
+ if(not element:IsShown()) then return end
+
+ element.notInterruptible = event == 'UNIT_SPELLCAST_NOT_INTERRUPTIBLE'
+
+ if(element.Shield) then element.Shield:SetShown(element.notInterruptible) end
+
+ --[[ Callback: Castbar:PostCastInterruptible(unit)
+ Called after the element has been updated when a spell cast has become interruptible or uninterruptible.
+
+ * self - the Castbar widget
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PostCastInterruptible) then
+ return element:PostCastInterruptible(unit)
+ end
+end
+
+local function onUpdate(self, elapsed)
+ if(self.casting or self.channeling) then
+ local isCasting = self.casting
+ if(isCasting) then
+ self.duration = self.duration + elapsed
+ if(self.duration >= self.max) then
+
+ resetAttributes(self)
+ self:Hide()
+
+ if(self.PostCastStop) then
+ self:PostCastStop(self.__owner.unit)
+ end
+
+ return
+ end
+ else
+ self.duration = self.duration - elapsed
+ if(self.duration <= 0) then
+
+ resetAttributes(self)
+ self:Hide()
+
+ if(self.PostCastStop) then
+ self:PostCastStop(self.__owner.unit)
+ end
+
+ return
+ end
+ end
+
+ if(self.Time) then
+ if(self.delay ~= 0) then
+ if(self.CustomDelayText) then
+ self:CustomDelayText(self.duration)
+ else
+ self.Time:SetFormattedText('%.1f|cffff0000%s%.2f|r', self.duration, isCasting and '+' or '-', self.delay)
+ end
+ else
+ if(self.CustomTimeText) then
+ self:CustomTimeText(self.duration)
+ else
+ self.Time:SetFormattedText('%.1f', self.duration)
+ end
+ end
+ end
+
+ self:SetValue(self.duration)
+ elseif(self.holdTime > 0) then
+ self.holdTime = self.holdTime - elapsed
+ else
+ resetAttributes(self)
+ self:Hide()
+ end
+end
+
+local function Update(...)
+ CastStart(...)
+end
+
+local function ForceUpdate(element)
+ return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+local function Enable(self, unit)
+ local element = self.Castbar
+ if(element and unit and not unit:match('%wtarget$')) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('UNIT_SPELLCAST_START', CastStart)
+ self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_START', CastStart)
+ self:RegisterEvent('UNIT_SPELLCAST_STOP', CastStop)
+ self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_STOP', CastStop)
+ self:RegisterEvent('UNIT_SPELLCAST_DELAYED', CastUpdate)
+ self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_UPDATE', CastUpdate)
+ self:RegisterEvent('UNIT_SPELLCAST_FAILED', CastFail)
+ self:RegisterEvent('UNIT_SPELLCAST_INTERRUPTED', CastFail)
+ self:RegisterEvent('UNIT_SPELLCAST_INTERRUPTIBLE', CastInterruptible)
+ self:RegisterEvent('UNIT_SPELLCAST_NOT_INTERRUPTIBLE', CastInterruptible)
+
+ -- ElvUI block
+ self:RegisterEvent('UNIT_SPELLCAST_SENT', UNIT_SPELLCAST_SENT, true)
+ -- end block
+
+ element.holdTime = 0
+
+ element:SetScript('OnUpdate', element.OnUpdate or onUpdate)
+
+ if(self.unit == 'player' and not (self.hasChildren or self.isChild)) then
+ CastingBarFrame_SetUnit(CastingBarFrame, nil)
+ CastingBarFrame_SetUnit(PetCastingBarFrame, nil)
+ end
+
+ if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then
+ element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
+ end
+
+ local spark = element.Spark
+ if(spark and spark:IsObjectType('Texture') and not spark:GetTexture()) then
+ spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
+ end
+
+ local shield = element.Shield
+ if(shield and shield:IsObjectType('Texture') and not shield:GetTexture()) then
+ shield:SetTexture([[Interface\CastingBar\UI-CastingBar-Small-Shield]])
+ end
+
+ local safeZone = element.SafeZone
+ if(safeZone and safeZone:IsObjectType('Texture') and not safeZone:GetTexture()) then
+ safeZone:SetColorTexture(1, 0, 0)
+ end
+
+ element:Hide()
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.Castbar
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('UNIT_SPELLCAST_START', CastStart)
+ self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_START', CastStart)
+ self:UnregisterEvent('UNIT_SPELLCAST_DELAYED', CastUpdate)
+ self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_UPDATE', CastUpdate)
+ self:UnregisterEvent('UNIT_SPELLCAST_STOP', CastStop)
+ self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_STOP', CastStop)
+ self:UnregisterEvent('UNIT_SPELLCAST_FAILED', CastFail)
+ self:UnregisterEvent('UNIT_SPELLCAST_INTERRUPTED', CastFail)
+ self:UnregisterEvent('UNIT_SPELLCAST_INTERRUPTIBLE', CastInterruptible)
+ self:UnregisterEvent('UNIT_SPELLCAST_NOT_INTERRUPTIBLE', CastInterruptible)
+
+ element:SetScript('OnUpdate', nil)
+
+ if(self.unit == 'player' and not (self.hasChildren or self.isChild)) then
+ CastingBarFrame_OnLoad(CastingBarFrame, 'player', true, false)
+ CastingBarFrame_SetUnit(CastingBarFrame, 'player', true, false)
+ PetCastingBarFrame_OnLoad(PetCastingBarFrame)
+ CastingBarFrame_SetUnit(PetCastingBarFrame, 'pet', false, false)
+ end
+ end
+end
+
+-- ElvUI block
+hooksecurefunc('DoTradeSkill', function(_, num)
+ tradeskillCurrent = 0
+ tradeskillTotal = num or 1
+ mergeTradeskill = true
+end)
+-- end block
+
+oUF:AddElement('Castbar', Update, Enable, Disable)
+
+function CastingBarFrame_SetUnit(self, unit, showTradeSkills, showShield)
+ if(self.unit ~= unit) then
+ self.unit = unit
+ self.showTradeSkills = showTradeSkills
+ self.showShield = showShield
+
+ self.casting = nil
+ self.channeling = nil
+ self.holdTime = 0
+ self.fadeOut = nil
+
+ if(unit) then
+ self:RegisterEvent("UNIT_SPELLCAST_START")
+ self:RegisterEvent("UNIT_SPELLCAST_STOP")
+ self:RegisterEvent("UNIT_SPELLCAST_FAILED")
+ self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
+ self:RegisterEvent("UNIT_SPELLCAST_DELAYED")
+ self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
+ self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
+ self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
+ self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE")
+ self:RegisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE")
+ self:RegisterEvent("PLAYER_ENTERING_WORLD")
+
+ CastingBarFrame_OnEvent(self, "PLAYER_ENTERING_WORLD")
+ else
+ self:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED")
+ self:UnregisterEvent("UNIT_SPELLCAST_DELAYED")
+ self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START")
+ self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
+ self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
+ self:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE")
+ self:UnregisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE")
+ self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+ self:UnregisterEvent("UNIT_SPELLCAST_START")
+ self:UnregisterEvent("UNIT_SPELLCAST_STOP")
+ self:UnregisterEvent("UNIT_SPELLCAST_FAILED")
+
+ self:Hide()
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/combatindicator.lua b/ElvUI/Libraries/oUF/elements/combatindicator.lua
new file mode 100644
index 0000000..b68075c
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/combatindicator.lua
@@ -0,0 +1,102 @@
+--[[
+# Element: Combat Indicator
+
+Toggles the visibility of an indicator based on the player's combat status.
+
+## Widget
+
+CombatIndicator - Any UI widget.
+
+## Notes
+
+A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
+
+## Examples
+
+ -- Position and size
+ local CombatIndicator = self:CreateTexture(nil, 'OVERLAY')
+ CombatIndicator:SetSize(16, 16)
+ CombatIndicator:SetPoint('TOP', self)
+
+ -- Register it with oUF
+ self.CombatIndicator = CombatIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local UnitAffectingCombat = UnitAffectingCombat
+
+local function Update(self, event)
+ local element = self.CombatIndicator
+
+ --[[ Callback: CombatIndicator:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the CombatIndicator element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local inCombat = UnitAffectingCombat('player')
+ if(inCombat) then
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ --[[ Callback: CombatIndicator:PostUpdate(inCombat)
+ Called after the element has been updated.
+
+ * self - the CombatIndicator element
+ * inCombat - indicates if the player is affecting combat (boolean)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(inCombat)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: CombatIndicator.Override(self, event)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ --]]
+ return (self.CombatIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate')
+end
+
+local function Enable(self, unit)
+ local element = self.CombatIndicator
+ if(element and unit == 'player') then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('PLAYER_REGEN_DISABLED', Path, true)
+ self:RegisterEvent('PLAYER_REGEN_ENABLED', Path, true)
+
+ if(element:IsObjectType('Texture') and not element:GetTexture()) then
+ element:SetTexture([[Interface\CharacterFrame\UI-StateIcon]])
+ element:SetTexCoord(.5, 1, 0, .49)
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.CombatIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('PLAYER_REGEN_DISABLED', Path)
+ self:UnregisterEvent('PLAYER_REGEN_ENABLED', Path)
+ end
+end
+
+oUF:AddElement('CombatIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/combopoints.lua b/ElvUI/Libraries/oUF/elements/combopoints.lua
new file mode 100644
index 0000000..e7c47ac
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/combopoints.lua
@@ -0,0 +1,127 @@
+--[[
+# Element: ComboPoints
+
+Handles the visibility and updating of the player's combo points.
+
+## Widget
+
+ComboPoints - An `table` consisting of as many Textures as the theoretical maximum return of [GetComboPoints](http://wowprogramming.com/docs/api/GetComboPoints).
+
+## Notes
+
+A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
+
+## Examples
+
+ local ComboPoints = {}
+ for index = 1, 10 do
+ local Bar = CreateFrame('StatusBar', nil, self)
+
+ -- Position and size.
+ Bar:SetSize(16, 16)
+ Bar:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', (index - 1) * Bar:GetWidth(), 0)
+
+ ComboPoints[index] = Bar
+ end
+
+ -- Register with oUF
+ self.ComboPoints = ComboPoints
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local GetComboPoints = GetComboPoints
+local UnitHasVehicleUI = UnitHasVehicleUI
+
+local MAX_COMBO_POINTS = MAX_COMBO_POINTS
+
+local function Update(self, event, unit)
+ if(unit == 'pet') then return end
+
+ local element = self.ComboPoints
+
+ --[[ Callback: ComboPoints:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the ComboPoints element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local cp
+ if(UnitHasVehicleUI('player')) then
+ cp = GetComboPoints('vehicle', 'target')
+ else
+ cp = GetComboPoints('player', 'target')
+ end
+
+ for i = 1, MAX_COMBO_POINTS do
+ if(i <= cp) then
+ element[i]:Show()
+ else
+ element[i]:Hide()
+ end
+ end
+
+ --[[ Callback: ComboPoints:PostUpdate(role)
+ Called after the element has been updated.
+
+ * self - the ComboPoints element
+ * cpoint - the current amount of combo points (number)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(cp)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: ComboPoints.Override(self, event, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * ... - the arguments accompanying the event
+ --]]
+ return (self.ComboPoints.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+local function Enable(self)
+ local element = self.ComboPoints
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('UNIT_COMBO_POINTS', Path, true)
+ self:RegisterEvent('PLAYER_TARGET_CHANGED', Path, true)
+
+ for index = 1, MAX_COMBO_POINTS do
+ local cp = element[index]
+ if(cp:IsObjectType('Texture') and not cp:GetTexture()) then
+ cp:SetTexture([[Interface\ComboFrame\ComboPoint]])
+ cp:SetTexCoord(0, 0.375, 0, 1)
+ end
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.ComboPoints
+ if(element) then
+ for index = 1, MAX_COMBO_POINTS do
+ element[index]:Hide()
+ end
+
+ self:UnregisterEvent('UNIT_COMBO_POINTS', Path)
+ self:UnregisterEvent('PLAYER_TARGET_CHANGED', Path)
+ end
+end
+
+oUF:AddElement('ComboPoints', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/grouproleindicator.lua b/ElvUI/Libraries/oUF/elements/grouproleindicator.lua
new file mode 100644
index 0000000..b1315ea
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/grouproleindicator.lua
@@ -0,0 +1,107 @@
+--[[
+# Element: Group Role Indicator
+
+Toggles the visibility of an indicator based on the unit's current group role (tank, healer or damager).
+
+## Widget
+
+GroupRoleIndicator - A `Texture` used to display the group role icon.
+
+## Notes
+
+A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
+
+## Examples
+
+ -- Position and size
+ local GroupRoleIndicator = self:CreateTexture(nil, 'OVERLAY')
+ GroupRoleIndicator:SetSize(16, 16)
+ GroupRoleIndicator:SetPoint('LEFT', self)
+
+ -- Register it with oUF
+ self.GroupRoleIndicator = GroupRoleIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local UnitGroupRolesAssigned = UnitGroupRolesAssigned
+
+local function Update(self, event)
+ local element = self.GroupRoleIndicator
+
+ --[[ Callback: GroupRoleIndicator:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the GroupRoleIndicator element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local isTank, isHealer, isDamage = UnitGroupRolesAssigned(self.unit)
+ if(isTank or isHealer or isDamage) then
+ local role = isTank and "tank" or isHealer and "healer" or isDamage and "dps"
+ element:SetTexture("Interface\\AddOns\\ElvUI\\media\\textures\\" .. role)
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ --[[ Callback: GroupRoleIndicator:PostUpdate(role)
+ Called after the element has been updated.
+
+ * self - the GroupRoleIndicator element
+ * isTank, isHealer, isDamage - the role as returned by [UnitGroupRolesAssigned](http://wowprogramming.com/docs/api/UnitGroupRolesAssigned)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(isTank, isHealer, isDamage)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: GroupRoleIndicator.Override(self, event, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * ... - the arguments accompanying the event
+ --]]
+ return (self.GroupRoleIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate')
+end
+
+local function Enable(self)
+ local element = self.GroupRoleIndicator
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ if(self.unit == 'player') then
+ self:RegisterEvent('PLAYER_ROLES_ASSIGNED', Path, true)
+ else
+ self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path, true)
+ end
+
+ if(element:IsObjectType('Texture') and not element:GetTexture()) then
+ element:SetTexture([[Interface\LFGFrame\UI-LFG-ICON-PORTRAITROLES]])
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.GroupRoleIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('PLAYER_ROLES_ASSIGNED', Path)
+ self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
+ end
+end
+
+oUF:AddElement('GroupRoleIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/happinessindicator.lua b/ElvUI/Libraries/oUF/elements/happinessindicator.lua
new file mode 100644
index 0000000..f611398
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/happinessindicator.lua
@@ -0,0 +1,116 @@
+--[[
+# Element: HappinessIndicator
+
+Handles the visibility and updating of player pet happiness.
+
+## Widget
+
+HappinessIndicator - A `Texture` used to display the current happiness level.
+The element works by changing the texture's vertex color.
+
+## Notes
+
+A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
+
+## Examples
+
+ -- Position and size
+ local HappinessIndicator = self:CreateTexture(nil, 'OVERLAY')
+ HappinessIndicator:SetSize(16, 16)
+ HappinessIndicator:SetPoint('TOPRIGHT', self)
+
+ -- Register it with oUF
+ self.HappinessIndicator = HappinessIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local GetPetHappiness = GetPetHappiness
+local HasPetUI = HasPetUI
+
+local function Update(self, event, unit)
+ if(not unit or self.unit ~= unit) then return end
+
+ local element = self.HappinessIndicator
+
+ --[[ Callback: HappinessIndicator:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the ComboPoints element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local _, hunterPet = HasPetUI()
+ local happiness, damagePercentage = GetPetHappiness()
+
+ if(hunterPet and happiness) then
+ if(happiness == 1) then
+ element:SetTexCoord(0.375, 0.5625, 0, 0.359375)
+ elseif(happiness == 2) then
+ element:SetTexCoord(0.1875, 0.375, 0, 0.359375)
+ elseif(happiness == 3) then
+ element:SetTexCoord(0, 0.1875, 0, 0.359375)
+ end
+
+ element:Show()
+ else
+ return element:Hide()
+ end
+
+ --[[ Callback: HappinessIndicator:PostUpdate(role)
+ Called after the element has been updated.
+
+ * self - the ComboPoints element
+ * unit - the unit for which the update has been triggered (string)
+ * happiness - the numerical happiness value of the pet (1 = unhappy, 2 = content, 3 = happy) (number)
+ * damagePercentage - damage modifier, happiness affects this (unhappy = 75%, content = 100%, happy = 125%) (number)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(unit, happiness, damagePercentage)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: HappinessIndicator.Override(self, event, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * ... - the arguments accompanying the event
+ --]]
+ return (self.HappinessIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+local function Enable(self)
+ local element = self.HappinessIndicator
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('UNIT_HAPPINESS', Path)
+
+ if(element:IsObjectType('Texture') and not element:GetTexture()) then
+ element:SetTexture([[Interface\PetPaperDollFrame\UI-PetHappiness]])
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.HappinessIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('UNIT_HAPPINESS', Path)
+ end
+end
+
+oUF:AddElement('HappinessIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/health.lua b/ElvUI/Libraries/oUF/elements/health.lua
new file mode 100644
index 0000000..e40b948
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/health.lua
@@ -0,0 +1,380 @@
+--[[
+# Element: Health Bar
+
+Handles the updating of a status bar that displays the unit's health.
+
+## Widget
+
+Health - A `StatusBar` used to represent the unit's health.
+
+## Sub-Widgets
+
+.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
+
+## Notes
+
+A default texture will be applied if the widget is a StatusBar and doesn't have a texture set.
+
+## Options
+
+.frequentUpdates - Indicates whether to use OnUpdate script instead of UNIT_HEALTH to update the
+ bar (boolean)
+.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
+.considerSelectionInCombatHostile - Indicates whether selection should be considered hostile while the unit is in
+ combat with the player (boolean)
+
+The following options are listed by priority. The first check that returns true decides the color of the bar.
+
+.colorDisconnected - Use `self.colors.disconnected` to color the bar if the unit is offline (boolean)
+.colorTapping - Use `self.colors.tapping` to color the bar if the unit isn't tapped by the player (boolean)
+.colorHappiness - Use `self.colors.happiness` to color the bar if the unit is pet based on pet happiness (boolean)
+.colorThreat - Use `self.colors.threat[threat]` to color the bar based on the unit's threat status. `threat` is
+ defined by the first return of [UnitThreatSituation](https://wow.gamepedia.com/API_UnitThreatSituation) (boolean)
+.colorClass - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
+ second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass.html) (boolean)
+.colorClassNPC - Use `self.colors.class[class]` to color the bar if the unit is a NPC (boolean)
+.colorClassPet - Use `self.colors.class[class]` to color the bar if the unit is player controlled, but not a player
+ (boolean)
+.colorReaction - Use `self.colors.reaction[reaction]` to color the bar based on the player's reaction towards the
+ unit. `reaction` is defined by the return value of
+ [UnitReaction](http://wowprogramming.com/docs/api/UnitReaction.html) (boolean)
+.colorSmooth - Use `smoothGradient` if present or `self.colors.smooth` to color the bar with a smooth gradient
+ based on the player's current health percentage (boolean)
+.colorHealth - Use `self.colors.health` to color the bar. This flag is used to reset the bar color back to default
+ if none of the above conditions are met (boolean)
+
+## Sub-Widgets Options
+
+.multiplier - Used to tint the background based on the main widgets R, G and B values. Defaults to 1 (number)[0-1]
+
+## Attributes
+
+.disconnected - Indicates whether the unit is disconnected (boolean)
+
+## Examples
+
+ -- Position and size
+ local Health = CreateFrame('StatusBar', nil, self)
+ Health:SetHeight(20)
+ Health:SetPoint('TOP')
+ Health:SetPoint('LEFT')
+ Health:SetPoint('RIGHT')
+
+ -- Add a background
+ local Background = Health:CreateTexture(nil, 'BACKGROUND')
+ Background:SetAllPoints(Health)
+ Background:SetTexture(1, 1, 1, .5)
+
+ -- Options
+ Health.frequentUpdates = true
+ Health.colorTapping = true
+ Health.colorDisconnected = true
+ Health.colorClass = true
+ Health.colorReaction = true
+ Health.colorHealth = true
+
+ -- Make the background darker.
+ Background.multiplier = .5
+
+ -- Register it with oUF
+ Health.bg = Background
+ self.Health = Health
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+local Private = oUF.Private
+
+local function UpdateColor(self, event, unit)
+ if(not unit or self.unit ~= unit) then return end
+ local element = self.Health
+
+ local r, g, b, t
+ if(element.colorDisconnected and element.disconnected) then
+ t = self.colors.disconnected
+ elseif(element.colorTapping and not UnitPlayerControlled(unit) and (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) and not UnitIsTappedByAllThreatList(unit))) then
+ t = self.colors.tapped
+ elseif(element.colorHappiness and UnitIsUnit(unit, 'pet') and GetPetHappiness()) then
+ t = self.colors.happiness[GetPetHappiness()]
+ elseif(element.colorThreat and not UnitPlayerControlled(unit) and UnitThreatSituation('player', unit)) then
+ t = self.colors.threat[UnitThreatSituation('player', unit)]
+ elseif(element.colorClass and UnitIsPlayer(unit)) or
+ (element.colorClassNPC and not UnitIsPlayer(unit)) or
+ (element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
+ t = oUF.herocolor
+ elseif(element.colorReaction and UnitReaction(unit, 'player')) then
+ t = self.colors.reaction[UnitReaction(unit, 'player')]
+ elseif(element.colorSmooth) then
+ r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth))
+ elseif(element.colorHealth) then
+ t = self.colors.health
+ end
+
+ if(t) then
+ r, g, b = t[1], t[2], t[3]
+ end
+
+ if(b) then
+ element:SetStatusBarColor(r, g, b)
+
+ local bg = element.bg
+ if(bg) then
+ local mu = bg.multiplier or 1
+ bg:SetVertexColor(r * mu, g * mu, b * mu)
+ end
+ end
+
+ if(element.PostUpdateColor) then
+ element:PostUpdateColor(unit, r, g, b)
+ end
+end
+
+local function ColorPath(self, ...)
+ --[[ Override: Health.UpdateColor(self, event, unit)
+ Used to completely override the internal function for updating the widgets' colors.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ --]]
+ (self.Health.UpdateColor or UpdateColor) (self, ...)
+end
+
+local function Update(self, event, unit)
+ if(not unit or self.unit ~= unit) then return end
+ local element = self.Health
+
+ --[[ Callback: Health:PreUpdate(unit)
+ Called before the element has been updated.
+
+ * self - the Health element
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate(unit)
+ end
+
+ local cur, max = UnitHealth(unit), UnitHealthMax(unit)
+ local disconnected = not UnitIsConnected(unit)
+
+ element:SetMinMaxValues(0, max)
+
+ if(disconnected) then
+ element:SetValue(max)
+ else
+ if(cur == 0) then
+ cur = 0.0001
+ end
+
+ element:SetValue(cur)
+ end
+
+ element.cur = cur
+ element.max = max
+ element.disconnected = disconnected
+
+ --[[ Callback: Health:PostUpdate(unit, cur, max)
+ Called after the element has been updated.
+
+ * self - the Health element
+ * unit - the unit for which the update has been triggered (string)
+ * cur - the unit's current health value (number)
+ * max - the unit's maximum possible health value (number)
+ --]]
+ if(element.PostUpdate) then
+ element:PostUpdate(unit, cur, max)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: Health.Override(self, event, unit)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ --]]
+ (self.Health.Override or Update) (self, ...);
+
+ ColorPath(self, ...)
+end
+
+local function ForceUpdate(element)
+ Path(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+--[[ Health:SetColorDisconnected(state)
+Used to toggle coloring if the unit is offline.
+
+* self - the Health element
+* state - the desired state (boolean)
+--]]
+local function SetColorDisconnected(element, state)
+ if(element.colorDisconnected ~= state) then
+ element.colorDisconnected = state
+ if(element.colorDisconnected) then
+ element.__owner:RegisterEvent('UNIT_CONNECTION', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_CONNECTION', ColorPath)
+ end
+ end
+end
+
+--[[ Health:SetColorHappiness(state)
+Used to toggle coloring by the unit's happiness.
+
+* self - the Health element
+* state - the desired state (boolean)
+--]]
+local function SetColorHappiness(element, state)
+ if(element.colorHappiness ~= state) then
+ element.colorHappiness = state
+ if(element.colorHappiness) then
+ element.__owner:RegisterEvent('UNIT_HAPPINESS', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
+ end
+ end
+end
+
+--[[ Health:SetColorTapping(state)
+Used to toggle coloring if the unit isn't tapped by the player.
+
+* self - the Health element
+* state - the desired state (boolean)
+--]]
+local function SetColorTapping(element, state)
+ if(element.colorTapping ~= state) then
+ element.colorTapping = state
+ if(element.colorTapping) then
+ element.__owner:RegisterEvent('UNIT_FACTION', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_FACTION', ColorPath)
+ end
+ end
+end
+
+--[[ Health:SetColorThreat(state)
+Used to toggle coloring by the unit's threat status.
+
+* self - the Health element
+* state - the desired state (boolean)
+--]]
+local function SetColorThreat(element, state)
+ if(element.colorThreat ~= state) then
+ element.colorThreat = state
+ if(element.colorThreat) then
+ element.__owner:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ end
+ end
+end
+
+local function onHealthUpdate(self)
+ if(self.disconnected) then return end
+
+ local unit = self.__owner.unit
+ local health = UnitHealth(unit)
+
+ if(health ~= self.health) then
+ self.health = health
+
+ return Path(self.__owner, 'OnHealthUpdate', unit)
+ end
+end
+
+--[[ Health:SetFrequentUpdates(state)
+Used to toggle frequent updates.
+
+* self - the Health element
+* state - the desired state (boolean)
+--]]
+local function SetFrequentUpdates(element, state)
+ if(element.frequentUpdates ~= state) then
+ element.frequentUpdates = state
+ if(element.frequentUpdates) then
+ element:SetScript('OnUpdate', onHealthUpdate)
+
+ local unit = element.__owner.unit
+ if((unit == 'party' or unit:match('party%d?$')) and not element:IsEventRegistered("UNIT_HEALTH")) then
+ element:RegisterEvent('UNIT_HEALTH', Path)
+ elseif(element:IsEventRegistered('UNIT_HEALTH')) then
+ element:UnregisterEvent('UNIT_HEALTH', Path)
+ end
+ else
+ element:SetScript('OnUpdate', nil)
+ element.__owner:RegisterEvent('UNIT_HEALTH', Path)
+ end
+ end
+end
+
+local function Enable(self, unit)
+ local element = self.Health
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+ element.SetColorDisconnected = SetColorDisconnected
+ element.SetColorHappiness = SetColorHappiness
+ element.SetColorTapping = SetColorTapping
+ element.SetColorThreat = SetColorThreat
+ element.SetFrequentUpdates = SetFrequentUpdates
+
+ if(element.colorDisconnected) then
+ self:RegisterEvent('UNIT_CONNECTION', ColorPath)
+ end
+
+ if(element.colorHappiness) then
+ self:RegisterEvent('UNIT_HAPPINESS', ColorPath)
+ end
+
+ if(element.colorTapping) then
+ self:RegisterEvent('UNIT_FACTION', ColorPath)
+ end
+
+ if(element.colorThreat) then
+ self:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ end
+
+ if(element.frequentUpdates and (unit and not unit:match('%w+target$'))) then
+ element:SetScript('OnUpdate', onHealthUpdate)
+
+ -- The party frames need this to handle disconnect states correctly.
+ if(unit == 'party') then
+ self:RegisterEvent('UNIT_HEALTH', Path)
+ end
+ else
+ self:RegisterEvent('UNIT_HEALTH', Path)
+ end
+
+ self:RegisterEvent('UNIT_MAXHEALTH', Path)
+
+ if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then
+ element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
+ end
+
+ element:Show()
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.Health
+ if(element) then
+ element:Hide()
+
+ if(element:GetScript('OnUpdate')) then
+ element:SetScript('OnUpdate', nil)
+ end
+
+ self:UnregisterEvent('UNIT_HEALTH', Path)
+ self:UnregisterEvent('UNIT_MAXHEALTH', Path)
+ self:UnregisterEvent('UNIT_CONNECTION', ColorPath)
+ self:UnregisterEvent('UNIT_FACTION', ColorPath)
+ self:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
+ self:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ end
+end
+
+oUF:AddElement('Health', Path, Enable, Disable)
diff --git a/ElvUI/Libraries/oUF/elements/leaderindicator.lua b/ElvUI/Libraries/oUF/elements/leaderindicator.lua
new file mode 100644
index 0000000..bd50100
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/leaderindicator.lua
@@ -0,0 +1,107 @@
+--[[
+# Element: Leader Indicator
+
+Toggles the visibility of an indicator based on the unit's leader status.
+
+## Widget
+
+LeaderIndicator - Any UI widget.
+
+## Notes
+
+A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
+
+## Examples
+
+ -- Position and size
+ local LeaderIndicator = self:CreateTexture(nil, 'OVERLAY')
+ LeaderIndicator:SetSize(16, 16)
+ LeaderIndicator:SetPoint('BOTTOM', self, 'TOP')
+
+ -- Register it with oUF
+ self.LeaderIndicator = LeaderIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local UnitInParty = UnitInParty
+local UnitInRaid = UnitInRaid
+local UnitIsPartyLeader = UnitIsPartyLeader
+
+local function Update(self, event)
+ local element = self.LeaderIndicator
+
+ --[[ Callback: LeaderIndicator:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the LeaderIndicator element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local unit = self.unit
+ local isLeader = (UnitInParty(unit) or UnitInRaid(unit)) and UnitIsPartyLeader(unit)
+ if(isLeader) then
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ --[[ Callback: LeaderIndicator:PostUpdate(isLeader)
+ Called after the element has been updated.
+
+ * self - the LeaderIndicator element
+ * isLeader - indicates whether the element is shown (boolean)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(isLeader)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: LeaderIndicator.Override(self, event, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * ... - the arguments accompanying the event
+ --]]
+ return (self.LeaderIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate')
+end
+
+local function Enable(self)
+ local element = self.LeaderIndicator
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('PARTY_LEADER_CHANGED', Path, true)
+ self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path, true)
+ self:RegisterEvent('RAID_ROSTER_UPDATE', Path, true)
+
+ if(element:IsObjectType('Texture') and not element:GetTexture()) then
+ element:SetTexture([[Interface\GroupFrame\UI-Group-LeaderIcon]])
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.LeaderIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('PARTY_LEADER_CHANGED', Path)
+ self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
+ self:UnregisterEvent('RAID_ROSTER_UPDATE', Path)
+ end
+end
+
+oUF:AddElement('LeaderIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/masterlooterindicator.lua b/ElvUI/Libraries/oUF/elements/masterlooterindicator.lua
new file mode 100644
index 0000000..a10375e
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/masterlooterindicator.lua
@@ -0,0 +1,124 @@
+--[[
+# Element: Master Looter Indicator
+
+Toggles the visibility of an indicator based on the unit's master looter status.
+
+## Widget
+
+MasterLooterIndicator - Any UI widget.
+
+## Notes
+
+A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
+
+## Examples
+
+ -- Position and size
+ local MasterLooterIndicator = self:CreateTexture(nil, 'OVERLAY')
+ MasterLooterIndicator:SetSize(16, 16)
+ MasterLooterIndicator:SetPoint('TOPRIGHT', self)
+
+ -- Register it with oUF
+ self.MasterLooterIndicator = MasterLooterIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local GetLootMethod = GetLootMethod
+local UnitInParty = UnitInParty
+local UnitInRaid = UnitInRaid
+local UnitIsUnit = UnitIsUnit
+
+local function Update(self, event)
+ local unit = self.unit
+ local element = self.MasterLooterIndicator
+
+ --[[ Callback: MasterLooterIndicator:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the MasterLooterIndicator element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local isShown = false
+ if(UnitInParty(unit) or UnitInRaid(unit)) then
+ local method, partyIndex, raidIndex = GetLootMethod()
+ if(method == 'master') then
+ local mlUnit
+ if(partyIndex) then
+ if(partyIndex == 0) then
+ mlUnit = 'player'
+ else
+ mlUnit = 'party' .. partyIndex
+ end
+ elseif(raidIndex) then
+ mlUnit = 'raid' .. raidIndex
+ end
+
+ isShown = mlUnit and UnitIsUnit(unit, mlUnit)
+ end
+ end
+
+ if isShown then
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ --[[ Callback: MasterLooterIndicator:PostUpdate(isShown)
+ Called after the element has been updated.
+
+ * self - the MasterLooterIndicator element
+ * isShown - indicates whether the element is shown (boolean)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(isShown)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: MasterLooterIndicator.Override(self, event, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * ... - the arguments accompanying the event
+ --]]
+ return (self.MasterLooterIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate')
+end
+
+local function Enable(self, unit)
+ local element = self.MasterLooterIndicator
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('PARTY_LOOT_METHOD_CHANGED', Path, true)
+ self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path, true)
+
+ if(element:IsObjectType('Texture') and not element:GetTexture()) then
+ element:SetTexture([[Interface\GroupFrame\UI-Group-MasterLooter]])
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.MasterLooterIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('PARTY_LOOT_METHOD_CHANGED', Path)
+ self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
+ end
+end
+
+oUF:AddElement('MasterLooterIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/portrait.lua b/ElvUI/Libraries/oUF/elements/portrait.lua
new file mode 100644
index 0000000..2ca381a
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/portrait.lua
@@ -0,0 +1,148 @@
+--[[
+# Element: Portraits
+
+Handles the updating of the unit's portrait.
+
+## Widget
+
+Portrait - A `PlayerModel` or a `Texture` used to represent the unit's portrait.
+
+## Notes
+
+A question mark model will be used if the widget is a PlayerModel and the client doesn't have the model information for
+the unit.
+
+## Examples
+
+ -- 3D Portrait
+ -- Position and size
+ local Portrait = CreateFrame('PlayerModel', nil, self)
+ Portrait:SetSize(32, 32)
+ Portrait:SetPoint('RIGHT', self, 'LEFT')
+
+ -- Register it with oUF
+ self.Portrait = Portrait
+
+ -- 2D Portrait
+ local Portrait = self:CreateTexture(nil, 'OVERLAY')
+ Portrait:SetSize(32, 32)
+ Portrait:SetPoint('RIGHT', self, 'LEFT')
+
+ -- Register it with oUF
+ self.Portrait = Portrait
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local SetPortraitTexture = SetPortraitTexture
+local UnitExists = UnitExists
+local UnitGUID = UnitGUID
+local UnitIsConnected = UnitIsConnected
+local UnitIsUnit = UnitIsUnit
+local UnitIsVisible = UnitIsVisible
+
+local function Update(self, event, unit)
+ if(not unit or not UnitIsUnit(self.unit, unit)) then return end
+
+ local element = self.Portrait
+
+ --[[ Callback: Portrait:PreUpdate(unit)
+ Called before the element has been updated.
+
+ * self - the Portrait element
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PreUpdate) then element:PreUpdate(unit) end
+
+ local guid = UnitGUID(unit)
+ local isAvailable = UnitIsConnected(unit) and UnitIsVisible(unit)
+ if(event ~= 'OnUpdate' or element.guid ~= guid or element.state ~= isAvailable) then
+ if(element:IsObjectType('PlayerModel')) then
+ if(not isAvailable) then
+ element:SetModelScale(4.25)
+ element:SetCamera(0)
+ element:SetPosition(0, 0, -1.5)
+ element:SetModel([[Interface\Buttons\TalkToMeQuestionMark.m2]])
+ elseif(element.guid ~= guid or event == 'UNIT_MODEL_CHANGED') then
+ element:ClearModel()
+ element:SetUnit(unit)
+ element:SetModelScale(1)
+ element:SetCamera(0)
+ element:SetPosition(0, 0, 0)
+ else
+ element:SetCamera(0)
+ end
+ else
+ SetPortraitTexture(element, unit)
+ end
+
+ element.guid = guid
+ element.state = isAvailable
+ end
+
+ --[[ Callback: Portrait:PostUpdate(unit)
+ Called after the element has been updated.
+
+ * self - the Portrait element
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(unit)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: Portrait.Override(self, event, unit)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ --]]
+ return (self.Portrait.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+local function Enable(self, unit)
+ local element = self.Portrait
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('UNIT_PORTRAIT_UPDATE', Path)
+ self:RegisterEvent('UNIT_MODEL_CHANGED', Path)
+ self:RegisterEvent('UNIT_CONNECTION', Path)
+
+ -- The quest log uses PARTY_MEMBER_{ENABLE,DISABLE} to handle updating of
+ -- party members overlapping quests. This will probably be enough to handle
+ -- model updating.
+ --
+ -- DISABLE isn't used as it fires when we most likely don't have the
+ -- information we want.
+ if(unit == 'party') then
+ self:RegisterEvent('PARTY_MEMBER_ENABLE', Path)
+ end
+
+ element:Show()
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.Portrait
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('UNIT_PORTRAIT_UPDATE', Path)
+ self:UnregisterEvent('UNIT_MODEL_CHANGED', Path)
+ self:UnregisterEvent('PARTY_MEMBER_ENABLE', Path)
+ self:UnregisterEvent('UNIT_CONNECTION', Path)
+ end
+end
+
+oUF:AddElement('Portrait', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/power.lua b/ElvUI/Libraries/oUF/elements/power.lua
new file mode 100644
index 0000000..d6ef391
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/power.lua
@@ -0,0 +1,427 @@
+--[[
+# Element: Power Bar
+
+Handles the updating of a status bar that displays the unit's power.
+
+## Widget
+
+Power - A `StatusBar` used to represent the unit's power.
+
+## Sub-Widgets
+
+.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
+
+## Notes
+
+A default texture will be applied if the widget is a StatusBar and doesn't have a texture or a color set.
+
+## Options
+
+.frequentUpdates - Indicates whether to use OnUpdate script instead of UNIT_POWER to update the bar. Only valid for the
+ player and pet units (boolean)
+.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
+
+The following options are listed by priority. The first check that returns true decides the color of the bar.
+
+.colorTapping - Use `self.colors.tapping` to color the bar if the unit isn't tapped by the player (boolean)
+.colorDisconnected - Use `self.colors.disconnected` to color the bar if the unit is offline (boolean)
+.colorHappiness - Use `self.colors.happiness` to color the bar if the unit is pet based on pet happiness (boolean)
+.colorPower - Use `self.colors.power[token]` to color the bar based on the unit's power type. This method will
+ fall-back to `:GetAlternativeColor()` if it can't find a color matching the token. If this function
+ isn't defined, then it will attempt to color based upon the alternative power colors returned by
+ [UnitPowerType](http://wowprogramming.com/docs/api/UnitPowerType). Finally, if these aren't
+ defined, then it will attempt to color the bar based upon `self.colors.power[type]` (boolean)
+.colorClass - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
+ second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass) (boolean)
+.colorClassNPC - Use `self.colors.class[class]` to color the bar if the unit is a NPC (boolean)
+.colorClassPet - Use `self.colors.class[class]` to color the bar if the unit is player controlled, but not a player
+ (boolean)
+.colorReaction - Use `self.colors.reaction[reaction]` to color the bar based on the player's reaction towards the
+ unit. `reaction` is defined by the return value of
+ [UnitReaction](http://wowprogramming.com/docs/api/UnitReaction) (boolean)
+.colorSmooth - Use `smoothGradient` if present or `self.colors.smooth` to color the bar with a smooth gradient
+ based on the player's current power percentage (boolean)
+
+## Sub-Widget Options
+
+.multiplier - A multiplier used to tint the background based on the main widgets R, G and B values. Defaults to 1
+ (number)[0-1]
+
+## Attributes
+
+.disconnected - Indicates whether the unit is disconnected (boolean)
+.tapped - Indicates whether the unit is tapped by the player (boolean)
+
+## Examples
+
+ -- Position and size
+ local Power = CreateFrame('StatusBar', nil, self)
+ Power:SetHeight(20)
+ Power:SetPoint('BOTTOM')
+ Power:SetPoint('LEFT')
+ Power:SetPoint('RIGHT')
+
+ -- Add a background
+ local Background = Power:CreateTexture(nil, 'BACKGROUND')
+ Background:SetAllPoints(Power)
+ Background:SetTexture(1, 1, 1, .5)
+
+ -- Options
+ Power.frequentUpdates = true
+ Power.colorTapping = true
+ Power.colorDisconnected = true
+ Power.colorPower = true
+ Power.colorClass = true
+ Power.colorReaction = true
+
+ -- Make the background darker.
+ Background.multiplier = .5
+
+ -- Register it with oUF
+ Power.bg = Background
+ self.Power = Power
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local unpack = unpack
+
+local GetPetHappiness = GetPetHappiness
+local UnitIsConnected = UnitIsConnected
+local UnitIsPlayer = UnitIsPlayer
+local UnitIsTapped = UnitIsTapped
+local UnitIsTappedByPlayer = UnitIsTappedByPlayer
+local UnitIsUnit = UnitIsUnit
+local UnitPlayerControlled = UnitPlayerControlled
+local UnitPower = UnitPower
+local UnitPowerMax = UnitPowerMax
+local UnitPowerType = UnitPowerType
+local UnitReaction = UnitReaction
+
+local function UpdateColor(self, event, unit)
+ if(self.unit ~= unit) then return end
+ local element = self.Power
+
+ local ptype, ptoken, altR, altG, altB = UnitPowerType(unit)
+ local r, g, b, t
+ if(element.colorDisconnected and element.disconnected) then
+ t = self.colors.disconnected
+ elseif(element.colorTapping and not UnitPlayerControlled(unit) and (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) and not UnitIsTappedByAllThreatList(unit))) then
+ t = self.colors.tapped
+ elseif(element.colorThreat and not UnitPlayerControlled(unit) and UnitThreatSituation('player', unit)) then
+ t = self.colors.threat[UnitThreatSituation('player', unit)]
+ elseif(element.colorHappiness and UnitIsUnit(unit, 'pet') and GetPetHappiness()) then
+ t = self.colors.happiness[GetPetHappiness()]
+ elseif(element.colorPower) then
+ t = self.colors.power[ptoken or ptype]
+ if(not t) then
+ if(element.GetAlternativeColor) then
+ r, g, b = element:GetAlternativeColor(unit, ptype, ptoken, altR, altG, altB)
+ elseif(altR) then
+ r, g, b = altR, altG, altB
+ end
+ end
+ elseif(element.colorClass and UnitIsPlayer(unit)) or
+ (element.colorClassNPC and not UnitIsPlayer(unit)) or
+ (element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
+ t = oUF.herocolor
+ elseif(element.colorReaction and UnitReaction(unit, 'player')) then
+ t = self.colors.reaction[UnitReaction(unit, 'player')]
+ elseif(element.colorSmooth) then
+ r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth))
+ end
+
+ if(t) then
+ r, g, b = t[1], t[2], t[3]
+ end
+
+ element:SetStatusBarTexture(element.texture)
+
+ if(b) then
+ element:SetStatusBarColor(r, g, b)
+ end
+
+ local bg = element.bg
+ if(bg and b) then
+ local mu = bg.multiplier or 1
+ bg:SetVertexColor(r * mu, g * mu, b * mu)
+ end
+
+ if(element.PostUpdateColor) then
+ element:PostUpdateColor(unit, r, g, b)
+ end
+end
+
+local function ColorPath(self, ...)
+ --[[ Override: Power.UpdateColor(self, event, unit)
+ Used to completely override the internal function for updating the widgets' colors.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ --]]
+ (self.Power.UpdateColor or UpdateColor) (self, ...)
+end
+
+local function Update(self, event, unit)
+ if(self.unit ~= unit) then return end
+ local element = self.Power
+
+ --[[ Callback: Power:PreUpdate(unit)
+ Called before the element has been updated.
+
+ * self - the Power element
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate(unit)
+ end
+
+ local cur, max = UnitPower(unit), UnitPowerMax(unit)
+ local disconnected = not UnitIsConnected(unit)
+ if max == 0 then
+ max = 1
+ end
+
+ element:SetMinMaxValues(0, max)
+
+ if(disconnected) then
+ element:SetValue(max)
+ else
+ element:SetValue(cur)
+ end
+
+ element.cur = cur
+ element.max = max
+ element.disconnected = disconnected
+
+ --[[ Callback: Power:PostUpdate(unit, cur, max)
+ Called after the element has been updated.
+
+ * self - the Power element
+ * unit - the unit for which the update has been triggered (string)
+ * cur - the unit's current power value (number)
+ * max - the unit's maximum possible power value (number)
+ --]]
+ if(element.PostUpdate) then
+ element:PostUpdate(unit, cur, max)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: Power.Override(self, event, unit, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ * ... - the arguments accompanying the event
+ --]]
+ (self.Power.Override or Update) (self, ...);
+
+ ColorPath(self, ...)
+end
+
+local function ForceUpdate(element)
+ Path(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+--[[ Power:SetColorDisconnected(state)
+Used to toggle coloring if the unit is offline.
+
+* self - the Power element
+* state - the desired state (boolean)
+--]]
+local function SetColorDisconnected(element, state)
+ if(element.colorDisconnected ~= state) then
+ element.colorDisconnected = state
+ if(element.colorDisconnected) then
+ element.__owner:RegisterEvent('UNIT_CONNECTION', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_CONNECTION', ColorPath)
+ end
+ end
+end
+
+--[[ Power:SetColorTapping(state)
+Used to toggle coloring if the unit isn't tapped by the player.
+
+* self - the Power element
+* state - the desired state (boolean)
+--]]
+local function SetColorTapping(element, state)
+ if(element.colorTapping ~= state) then
+ element.colorTapping = state
+ if(element.colorTapping) then
+ element.__owner:RegisterEvent('UNIT_FACTION', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_FACTION', ColorPath)
+ end
+ end
+end
+
+--[[ Power:SetColorThreat(state)
+Used to toggle coloring by the unit's threat status.
+
+* self - the Power element
+* state - the desired state (boolean)
+--]]
+local function SetColorThreat(element, state)
+ if(element.colorThreat ~= state) then
+ element.colorThreat = state
+ if(element.colorThreat) then
+ element.__owner:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ end
+ end
+end
+
+--[[ Power:SetColorHappiness(state)
+Used to toggle coloring by the unit's happiness status.
+
+* self - the Power element
+* state - the desired state (boolean)
+--]]
+local function SetColorHappiness(element, state)
+ if(element.colorHappiness ~= state) then
+ element.colorHappiness = state
+ if(element.colorHappiness) then
+ element.__owner:RegisterEvent('UNIT_HAPPINESS', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
+ end
+ end
+end
+
+
+local function onPowerUpdate(self)
+ if(self.disconnected) then return end
+
+ local unit = self.__owner.unit
+ local power = UnitPower(unit)
+
+ if(power ~= self.power) then
+ self.power = power
+
+ return Path(self.__owner, 'OnPowerUpdate', unit)
+ end
+end
+
+--[[ Power:SetFrequentUpdates(state)
+Used to toggle frequent updates.
+
+* self - the Power element
+* state - the desired state (boolean)
+--]]
+local function SetFrequentUpdates(element, state)
+ --if(not unit or (unit ~= 'player' and unit ~= 'pet')) then return end
+
+ if(element.frequentUpdates ~= state) then
+ element.frequentUpdates = state
+ if(element.frequentUpdates and not element:GetScript('OnUpdate')) then
+ element:SetScript('OnUpdate', onPowerUpdate)
+
+ element.__owner:UnregisterEvent('UNIT_MANA', Path)
+ element.__owner:UnregisterEvent('UNIT_RAGE', Path)
+ element.__owner:UnregisterEvent('UNIT_FOCUS', Path)
+ element.__owner:UnregisterEvent('UNIT_ENERGY', Path)
+ element.__owner:UnregisterEvent('UNIT_RUNIC_POWER', Path)
+ elseif(not element.frequentUpdates and element:GetScript('OnUpdate')) then
+ element:SetScript('OnUpdate', nil)
+
+ element.__owner:RegisterEvent('UNIT_MANA', Path)
+ element.__owner:RegisterEvent('UNIT_RAGE', Path)
+ element.__owner:RegisterEvent('UNIT_FOCUS', Path)
+ element.__owner:RegisterEvent('UNIT_ENERGY', Path)
+ element.__owner:RegisterEvent('UNIT_RUNIC_POWER', Path)
+ end
+ end
+end
+
+local function Enable(self, unit)
+ local element = self.Power
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+ element.SetColorDisconnected = SetColorDisconnected
+ element.SetColorTapping = SetColorTapping
+ element.SetColorThreat = SetColorThreat
+ element.SetColorHappiness = SetColorHappiness
+ element.SetFrequentUpdates = SetFrequentUpdates
+
+ if(element.colorDisconnected) then
+ self:RegisterEvent('UNIT_CONNECTION', ColorPath)
+ end
+
+ if(element.colorTapping) then
+ self:RegisterEvent('UNIT_FACTION', ColorPath)
+ end
+
+ if(element.colorThreat) then
+ self:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ end
+
+ if(element.colorHappiness) then
+ self:RegisterEvent('UNIT_HAPPINESS', ColorPath)
+ end
+
+ if(element.frequentUpdates and (unit == 'player' or unit == 'pet')) then
+ element:SetScript('OnUpdate', onPowerUpdate)
+ else
+ self:RegisterEvent('UNIT_MANA', Path)
+ self:RegisterEvent('UNIT_RAGE', Path)
+ self:RegisterEvent('UNIT_FOCUS', Path)
+ self:RegisterEvent('UNIT_ENERGY', Path)
+ self:RegisterEvent('UNIT_RUNIC_POWER', Path)
+ end
+
+ self:RegisterEvent('UNIT_MAXMANA', Path)
+ self:RegisterEvent('UNIT_MAXRAGE', Path)
+ self:RegisterEvent('UNIT_MAXFOCUS', Path)
+ self:RegisterEvent('UNIT_MAXENERGY', Path)
+ self:RegisterEvent('UNIT_MAXRUNIC_POWER', Path)
+ self:RegisterEvent('UNIT_DISPLAYPOWER', Path)
+
+ if(element:IsObjectType('StatusBar')) then
+ element.texture = element:GetStatusBarTexture() and element:GetStatusBarTexture():GetTexture() or [[Interface\TargetingFrame\UI-StatusBar]]
+ element:SetStatusBarTexture(element.texture)
+ end
+
+ element:Show()
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.Power
+ if(element) then
+ element:Hide()
+
+ if(element:GetScript('OnUpdate')) then
+ element:SetScript('OnUpdate', nil)
+ else
+ self:UnregisterEvent('UNIT_MANA', Path)
+ self:UnregisterEvent('UNIT_RAGE', Path)
+ self:UnregisterEvent('UNIT_FOCUS', Path)
+ self:UnregisterEvent('UNIT_ENERGY', Path)
+ self:UnregisterEvent('UNIT_RUNIC_POWER', Path)
+ end
+
+ self:UnregisterEvent('UNIT_MAXMANA', Path)
+ self:UnregisterEvent('UNIT_MAXRAGE', Path)
+ self:UnregisterEvent('UNIT_MAXFOCUS', Path)
+ self:UnregisterEvent('UNIT_MAXENERGY', Path)
+ self:UnregisterEvent('UNIT_MAXRUNIC_POWER', Path)
+ self:UnregisterEvent('UNIT_DISPLAYPOWER', Path)
+
+ self:UnregisterEvent('UNIT_CONNECTION', ColorPath)
+ self:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ self:UnregisterEvent('UNIT_FACTION', ColorPath)
+ self:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
+ end
+end
+
+oUF:AddElement('Power', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/powerenergy.lua b/ElvUI/Libraries/oUF/elements/powerenergy.lua
new file mode 100644
index 0000000..2fef6d2
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/powerenergy.lua
@@ -0,0 +1,321 @@
+local _, ns = ...
+local oUF = ns.oUF
+
+local unpack = unpack
+
+local GetPetHappiness = GetPetHappiness
+local UnitClass = UnitClass
+local UnitIsConnected = UnitIsConnected
+local UnitIsPlayer = UnitIsPlayer
+local UnitIsTapped = UnitIsTapped
+local UnitIsTappedByPlayer = UnitIsTappedByPlayer
+local UnitIsUnit = UnitIsUnit
+local UnitPlayerControlled = UnitPlayerControlled
+local UnitPower = UnitPower
+local UnitPowerMax = UnitPowerMax
+local UnitPowerType = UnitPowerType
+local UnitReaction = UnitReaction
+
+local function UpdateColor(self, event, unit)
+ if(self.unit ~= unit) then return end
+ local element = self.Energy
+
+ local ptype, ptoken, altR, altG, altB = UnitPowerType(unit)
+ local r, g, b
+ local t = self.colors.power["ENERGY"]
+ if(element.colorDisconnected and element.disconnected) then
+ t = self.colors.disconnected
+ elseif(element.colorTapping and not UnitPlayerControlled(unit) and (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) and not UnitIsTappedByAllThreatList(unit))) then
+ t = self.colors.tapped
+ elseif(element.colorThreat and not UnitPlayerControlled(unit) and UnitThreatSituation('player', unit)) then
+ t = self.colors.threat[UnitThreatSituation('player', unit)]
+ elseif(element.colorHappiness and UnitIsUnit(unit, 'pet') and GetPetHappiness()) then
+ t = self.colors.happiness[GetPetHappiness()]
+ elseif(element.colorPower) then
+ t = self.colors.power[ptoken or ptype]
+ if(not t) then
+ if(element.GetAlternativeColor) then
+ r, g, b = element:GetAlternativeColor(unit, ptype, ptoken, altR, altG, altB)
+ elseif(altR) then
+ r, g, b = altR, altG, altB
+ end
+ end
+ elseif(element.colorClass and UnitIsPlayer(unit)) or
+ (element.colorClassNPC and not UnitIsPlayer(unit)) or
+ (element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
+ local _, class = UnitClass(unit)
+ t = self.colors.class[class]
+ elseif(element.colorReaction and UnitReaction(unit, 'player')) then
+ t = self.colors.reaction[UnitReaction(unit, 'player')]
+ elseif(element.colorSmooth) then
+ r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth))
+ end
+
+ if(t) then
+ r, g, b = t[1], t[2], t[3]
+ end
+
+ element:SetStatusBarTexture(element.texture)
+
+ if(b) then
+ element:SetStatusBarColor(r, g, b)
+ end
+
+ local bg = element.bg
+ if(bg and b) then
+ local mu = bg.multiplier or 1
+ bg:SetVertexColor(r * mu, g * mu, b * mu)
+ end
+
+ if(element.PostUpdateColor) then
+ element:PostUpdateColor(unit, r, g, b)
+ end
+end
+
+local function ColorPath(self, ...)
+ --[[ Override: Energy.UpdateColor(self, event, unit)
+ Used to completely override the internal function for updating the widgets' colors.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ --]]
+ (self.Energy.UpdateColor or UpdateColor) (self, ...)
+end
+
+local function Update(self, event, unit)
+ if(self.unit ~= unit) then return end
+ local element = self.Energy
+
+ --[[ Callback: Energy:PreUpdate(unit)
+ Called before the element has been updated.
+
+ * self - the Energy element
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate(unit)
+ end
+
+ local cur, max = UnitPower(unit, 3), UnitPowerMax(unit, 3)
+ local disconnected = not UnitIsConnected(unit)
+ if max == 0 then
+ max = 1
+ end
+
+ element:SetMinMaxValues(0, max)
+
+ if(disconnected) then
+ element:SetValue(max)
+ else
+ element:SetValue(cur)
+ end
+
+ element.cur = cur
+ element.max = max
+ element.disconnected = disconnected
+
+ --[[ Callback: Energy:PostUpdate(unit, cur, max)
+ Called after the element has been updated.
+
+ * self - the Energy element
+ * unit - the unit for which the update has been triggered (string)
+ * cur - the unit's current energy value (number)
+ * max - the unit's maximum possible energy value (number)
+ --]]
+ if(element.PostUpdate) then
+ element:PostUpdate(unit, cur, max)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: Energy.Override(self, event, unit, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ * ... - the arguments accompanying the event
+ --]]
+ (self.Energy.Override or Update) (self, ...);
+
+ ColorPath(self, ...)
+end
+
+local function ForceUpdate(element)
+ Path(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+--[[ Energy:SetColorDisconnected(state)
+Used to toggle coloring if the unit is offline.
+
+* self - the Energy element
+* state - the desired state (boolean)
+--]]
+local function SetColorDisconnected(element, state)
+ if(element.colorDisconnected ~= state) then
+ element.colorDisconnected = state
+ if(element.colorDisconnected) then
+ element.__owner:RegisterEvent('UNIT_CONNECTION', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_CONNECTION', ColorPath)
+ end
+ end
+end
+
+--[[ Energy:SetColorTapping(state)
+Used to toggle coloring if the unit isn't tapped by the player.
+
+* self - the Energy element
+* state - the desired state (boolean)
+--]]
+local function SetColorTapping(element, state)
+ if(element.colorTapping ~= state) then
+ element.colorTapping = state
+ if(element.colorTapping) then
+ element.__owner:RegisterEvent('UNIT_FACTION', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_FACTION', ColorPath)
+ end
+ end
+end
+
+--[[ Energy:SetColorThreat(state)
+Used to toggle coloring by the unit's threat status.
+
+* self - the Energy element
+* state - the desired state (boolean)
+--]]
+local function SetColorThreat(element, state)
+ if(element.colorThreat ~= state) then
+ element.colorThreat = state
+ if(element.colorThreat) then
+ element.__owner:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ end
+ end
+end
+
+--[[ Energy:SetColorHappiness(state)
+Used to toggle coloring by the unit's happiness status.
+
+* self - the Energy element
+* state - the desired state (boolean)
+--]]
+local function SetColorHappiness(element, state)
+ if(element.colorHappiness ~= state) then
+ element.colorHappiness = state
+ if(element.colorHappiness) then
+ element.__owner:RegisterEvent('UNIT_HAPPINESS', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
+ end
+ end
+end
+
+
+local function onEnergyUpdate(self)
+ if(self.disconnected) then return end
+
+ local unit = self.__owner.unit
+ local energy = UnitPower(unit, 3)
+
+ if(energy ~= self.energy) then
+ self.energy = energy
+
+ return Path(self.__owner, 'OnEnergyUpdate', unit)
+ end
+end
+
+--[[ Energy:SetFrequentUpdates(state)
+Used to toggle frequent updates.
+
+* self - the Energy element
+* state - the desired state (boolean)
+--]]
+local function SetFrequentUpdates(element, state)
+ --if(not unit or (unit ~= 'player' and unit ~= 'pet')) then return end
+
+ if(element.frequentUpdates ~= state) then
+ element.frequentUpdates = state
+ if(element.frequentUpdates and not element:GetScript('OnUpdate')) then
+ element:SetScript('OnUpdate', onEnergyUpdate)
+
+ element.__owner:UnregisterEvent('UNIT_ENERGY', Path)
+ elseif(not element.frequentUpdates and element:GetScript('OnUpdate')) then
+ element:SetScript('OnUpdate', nil)
+
+ element.__owner:RegisterEvent('UNIT_ENERGY_FREQUENT', Path)
+ end
+ end
+end
+
+local function Enable(self, unit)
+ local element = self.Energy
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+ element.SetColorDisconnected = SetColorDisconnected
+ element.SetColorTapping = SetColorTapping
+ element.SetColorThreat = SetColorThreat
+ element.SetColorHappiness = SetColorHappiness
+ element.SetFrequentUpdates = SetFrequentUpdates
+
+ if(element.colorDisconnected) then
+ self:RegisterEvent('UNIT_CONNECTION', ColorPath)
+ end
+
+ if(element.colorTapping) then
+ self:RegisterEvent('UNIT_FACTION', ColorPath)
+ end
+
+ if(element.colorThreat) then
+ self:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ end
+
+ if(element.colorHappiness) then
+ self:RegisterEvent('UNIT_HAPPINESS', ColorPath)
+ end
+
+ -- if(element.frequentUpdates and (unit == 'player' or unit == 'pet')) then
+ if((unit == 'player' or unit == 'pet')) then
+ element:SetScript('OnUpdate', onEnergyUpdate)
+ else
+ self:RegisterEvent('UNIT_ENERGY', Path)
+ end
+
+ self:RegisterEvent('UNIT_MAXENERGY', Path)
+
+ if(element:IsObjectType('StatusBar')) then
+ element.texture = element:GetStatusBarTexture() and element:GetStatusBarTexture():GetTexture() or [[Interface\TargetingFrame\UI-StatusBar]]
+ element:SetStatusBarTexture(element.texture)
+ end
+
+ element:Show()
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.Energy
+ if(element) then
+ element:Hide()
+
+ if(element:GetScript('OnUpdate')) then
+ element:SetScript('OnUpdate', nil)
+ else
+ self:UnregisterEvent('UNIT_ENERGY', Path)
+ end
+
+ self:UnregisterEvent('UNIT_MAXENERGY', Path)
+
+ self:UnregisterEvent('UNIT_CONNECTION', ColorPath)
+ self:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ self:UnregisterEvent('UNIT_FACTION', ColorPath)
+ self:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
+ end
+end
+
+oUF:AddElement('Energy', Path, Enable, Disable)
diff --git a/ElvUI/Libraries/oUF/elements/powerrage.lua b/ElvUI/Libraries/oUF/elements/powerrage.lua
new file mode 100644
index 0000000..3a97067
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/powerrage.lua
@@ -0,0 +1,321 @@
+local _, ns = ...
+local oUF = ns.oUF
+
+local unpack = unpack
+
+local GetPetHappiness = GetPetHappiness
+local UnitClass = UnitClass
+local UnitIsConnected = UnitIsConnected
+local UnitIsPlayer = UnitIsPlayer
+local UnitIsTapped = UnitIsTapped
+local UnitIsTappedByPlayer = UnitIsTappedByPlayer
+local UnitIsUnit = UnitIsUnit
+local UnitPlayerControlled = UnitPlayerControlled
+local UnitPower = UnitPower
+local UnitPowerMax = UnitPowerMax
+local UnitPowerType = UnitPowerType
+local UnitReaction = UnitReaction
+
+local function UpdateColor(self, event, unit)
+ if(self.unit ~= unit) then return end
+ local element = self.Rage
+
+ local ptype, ptoken, altR, altG, altB = UnitPowerType(unit)
+ local r, g, b
+ local t = self.colors.power["RAGE"]
+ if(element.colorDisconnected and element.disconnected) then
+ t = self.colors.disconnected
+ elseif(element.colorTapping and not UnitPlayerControlled(unit) and (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) and not UnitIsTappedByAllThreatList(unit))) then
+ t = self.colors.tapped
+ elseif(element.colorThreat and not UnitPlayerControlled(unit) and UnitThreatSituation('player', unit)) then
+ t = self.colors.threat[UnitThreatSituation('player', unit)]
+ elseif(element.colorHappiness and UnitIsUnit(unit, 'pet') and GetPetHappiness()) then
+ t = self.colors.happiness[GetPetHappiness()]
+ elseif(element.colorPower) then
+ t = self.colors.power[ptoken or ptype]
+ if(not t) then
+ if(element.GetAlternativeColor) then
+ r, g, b = element:GetAlternativeColor(unit, ptype, ptoken, altR, altG, altB)
+ elseif(altR) then
+ r, g, b = altR, altG, altB
+ end
+ end
+ elseif(element.colorClass and UnitIsPlayer(unit)) or
+ (element.colorClassNPC and not UnitIsPlayer(unit)) or
+ (element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
+ local _, class = UnitClass(unit)
+ t = self.colors.class[class]
+ elseif(element.colorReaction and UnitReaction(unit, 'player')) then
+ t = self.colors.reaction[UnitReaction(unit, 'player')]
+ elseif(element.colorSmooth) then
+ r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth))
+ end
+
+ if(t) then
+ r, g, b = t[1], t[2], t[3]
+ end
+
+ element:SetStatusBarTexture(element.texture)
+
+ if(b) then
+ element:SetStatusBarColor(r, g, b)
+ end
+
+ local bg = element.bg
+ if(bg and b) then
+ local mu = bg.multiplier or 1
+ bg:SetVertexColor(r * mu, g * mu, b * mu)
+ end
+
+ if(element.PostUpdateColor) then
+ element:PostUpdateColor(unit, r, g, b)
+ end
+end
+
+local function ColorPath(self, ...)
+ --[[ Override: Rage.UpdateColor(self, event, unit)
+ Used to completely override the internal function for updating the widgets' colors.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ --]]
+ (self.Rage.UpdateColor or UpdateColor) (self, ...)
+end
+
+local function Update(self, event, unit)
+ if(self.unit ~= unit) then return end
+ local element = self.Rage
+
+ --[[ Callback: Rage:PreUpdate(unit)
+ Called before the element has been updated.
+
+ * self - the Rage element
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate(unit)
+ end
+
+ local cur, max = UnitPower(unit, 1), UnitPowerMax(unit, 1)
+ local disconnected = not UnitIsConnected(unit)
+ if max == 0 then
+ max = 1
+ end
+
+ element:SetMinMaxValues(0, max)
+
+ if(disconnected) then
+ element:SetValue(max)
+ else
+ element:SetValue(cur)
+ end
+
+ element.cur = cur
+ element.max = max
+ element.disconnected = disconnected
+
+ --[[ Callback: Rage:PostUpdate(unit, cur, max)
+ Called after the element has been updated.
+
+ * self - the Rage element
+ * unit - the unit for which the update has been triggered (string)
+ * cur - the unit's current rage value (number)
+ * max - the unit's maximum possible rage value (number)
+ --]]
+ if(element.PostUpdate) then
+ element:PostUpdate(unit, cur, max)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: Rage.Override(self, event, unit, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ * ... - the arguments accompanying the event
+ --]]
+ (self.Rage.Override or Update) (self, ...);
+
+ ColorPath(self, ...)
+end
+
+local function ForceUpdate(element)
+ Path(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+--[[ Rage:SetColorDisconnected(state)
+Used to toggle coloring if the unit is offline.
+
+* self - the Rage element
+* state - the desired state (boolean)
+--]]
+local function SetColorDisconnected(element, state)
+ if(element.colorDisconnected ~= state) then
+ element.colorDisconnected = state
+ if(element.colorDisconnected) then
+ element.__owner:RegisterEvent('UNIT_CONNECTION', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_CONNECTION', ColorPath)
+ end
+ end
+end
+
+--[[ Rage:SetColorTapping(state)
+Used to toggle coloring if the unit isn't tapped by the player.
+
+* self - the Rage element
+* state - the desired state (boolean)
+--]]
+local function SetColorTapping(element, state)
+ if(element.colorTapping ~= state) then
+ element.colorTapping = state
+ if(element.colorTapping) then
+ element.__owner:RegisterEvent('UNIT_FACTION', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_FACTION', ColorPath)
+ end
+ end
+end
+
+--[[ Rage:SetColorThreat(state)
+Used to toggle coloring by the unit's threat status.
+
+* self - the Rage element
+* state - the desired state (boolean)
+--]]
+local function SetColorThreat(element, state)
+ if(element.colorThreat ~= state) then
+ element.colorThreat = state
+ if(element.colorThreat) then
+ element.__owner:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ end
+ end
+end
+
+--[[ Rage:SetColorHappiness(state)
+Used to toggle coloring by the unit's happiness status.
+
+* self - the Rage element
+* state - the desired state (boolean)
+--]]
+local function SetColorHappiness(element, state)
+ if(element.colorHappiness ~= state) then
+ element.colorHappiness = state
+ if(element.colorHappiness) then
+ element.__owner:RegisterEvent('UNIT_HAPPINESS', ColorPath)
+ else
+ element.__owner:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
+ end
+ end
+end
+
+
+local function onRageUpdate(self)
+ if(self.disconnected) then return end
+
+ local unit = self.__owner.unit
+ local rage = UnitPower(unit, 1)
+
+ if(rage ~= self.rage) then
+ self.rage = rage
+
+ return Path(self.__owner, 'OnRageUpdate', unit)
+ end
+end
+
+--[[ Rage:SetFrequentUpdates(state)
+Used to toggle frequent updates.
+
+* self - the Rage element
+* state - the desired state (boolean)
+--]]
+local function SetFrequentUpdates(element, state)
+ --if(not unit or (unit ~= 'player' and unit ~= 'pet')) then return end
+
+ if(element.frequentUpdates ~= state) then
+ element.frequentUpdates = state
+ if(element.frequentUpdates and not element:GetScript('OnUpdate')) then
+ element:SetScript('OnUpdate', onRageUpdate)
+
+ element.__owner:UnregisterEvent('UNIT_RAGE', Path)
+ elseif(not element.frequentUpdates and element:GetScript('OnUpdate')) then
+ element:SetScript('OnUpdate', nil)
+
+ element.__owner:RegisterEvent('UNIT_RAGE', Path)
+ end
+ end
+end
+
+local function Enable(self, unit)
+ local element = self.Rage
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+ element.SetColorDisconnected = SetColorDisconnected
+ element.SetColorTapping = SetColorTapping
+ element.SetColorThreat = SetColorThreat
+ element.SetColorHappiness = SetColorHappiness
+ element.SetFrequentUpdates = SetFrequentUpdates
+
+ if(element.colorDisconnected) then
+ self:RegisterEvent('UNIT_CONNECTION', ColorPath)
+ end
+
+ if(element.colorTapping) then
+ self:RegisterEvent('UNIT_FACTION', ColorPath)
+ end
+
+ if(element.colorThreat) then
+ self:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ end
+
+ if(element.colorHappiness) then
+ self:RegisterEvent('UNIT_HAPPINESS', ColorPath)
+ end
+
+ -- if(element.frequentUpdates and (unit == 'player' or unit == 'pet')) then
+ if((unit == 'player' or unit == 'pet')) then
+ element:SetScript('OnUpdate', onRageUpdate)
+ else
+ self:RegisterEvent('UNIT_RAGE', Path)
+ end
+
+ self:RegisterEvent('UNIT_MAXRAGE', Path)
+
+ if(element:IsObjectType('StatusBar')) then
+ element.texture = element:GetStatusBarTexture() and element:GetStatusBarTexture():GetTexture() or [[Interface\TargetingFrame\UI-StatusBar]]
+ element:SetStatusBarTexture(element.texture)
+ end
+
+ element:Show()
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.Rage
+ if(element) then
+ element:Hide()
+
+ if(element:GetScript('OnUpdate')) then
+ element:SetScript('OnUpdate', nil)
+ else
+ self:UnregisterEvent('UNIT_RAGE', Path)
+ end
+
+ self:UnregisterEvent('UNIT_MAXRAGE', Path)
+
+ self:UnregisterEvent('UNIT_CONNECTION', ColorPath)
+ self:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+ self:UnregisterEvent('UNIT_FACTION', ColorPath)
+ self:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
+ end
+end
+
+oUF:AddElement('Rage', Path, Enable, Disable)
diff --git a/ElvUI/Libraries/oUF/elements/pvpindicator.lua b/ElvUI/Libraries/oUF/elements/pvpindicator.lua
new file mode 100644
index 0000000..fcf1798
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/pvpindicator.lua
@@ -0,0 +1,118 @@
+--[[
+# Element: PvP Icon
+
+Handles the visibility and updating of an indicator based on the unit's PvP status.
+
+## Widget
+
+PvPIndicator - A `Texture` used to display faction, FFA PvP status icon.
+
+## Notes
+
+This element updates by changing the texture.
+
+## Examples
+
+ -- Position and size
+ local PvPIndicator = self:CreateTexture(nil, 'ARTWORK', nil, 1)
+ PvPIndicator:SetSize(30, 30)
+ PvPIndicator:SetPoint('RIGHT', self, 'LEFT')
+
+ -- Register it with oUF
+ self.PvPIndicator = PvPIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local UnitFactionGroup = UnitFactionGroup
+local UnitIsPVP = UnitIsPVP
+local UnitIsPVPFreeForAll = UnitIsPVPFreeForAll
+
+local FFA_ICON = [[Interface\TargetingFrame\UI-PVP-FFA]]
+local FACTION_ICON = [[Interface\TargetingFrame\UI-PVP-]]
+
+local function Update(self, event, unit)
+ if(unit ~= self.unit) then return end
+
+ local element = self.PvPIndicator
+
+ --[[ Callback: PvPIndicator:PreUpdate(unit)
+ Called before the element has been updated.
+
+ * self - the PvPIndicator element
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate(unit)
+ end
+
+ local status
+ local factionGroup = UnitFactionGroup(unit)
+
+ if(UnitIsPVPFreeForAll(unit)) then
+ element:SetTexture(FFA_ICON)
+ element:SetTexCoord(0, 0.65625, 0, 0.65625)
+ status = 'ffa'
+ elseif(factionGroup and factionGroup ~= 'Neutral' and UnitIsPVP(unit)) then
+ element:SetTexture(FACTION_ICON .. factionGroup)
+ element:SetTexCoord(0, 0.65625, 0, 0.65625)
+ status = factionGroup
+ end
+
+ if(status) then
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ --[[ Callback: PvPIndicator:PostUpdate(unit, status)
+ Called after the element has been updated.
+
+ * self - the PvPIndicator element
+ * unit - the unit for which the update has been triggered (string)
+ * status - the unit's current PvP status or faction accounting for mercenary mode (string)['ffa', 'Alliance',
+ 'Horde']
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(unit, status)
+ end
+end
+
+local function Path(self, ...)
+ --[[Override: PvPIndicator.Override(self, event, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * ... - the arguments accompanying the event
+ --]]
+ return (self.PvPIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+local function Enable(self)
+ local element = self.PvPIndicator
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('UNIT_FACTION', Path)
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.PvPIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('UNIT_FACTION', Path)
+ end
+end
+
+oUF:AddElement('PvPIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/raidroleindicator.lua b/ElvUI/Libraries/oUF/elements/raidroleindicator.lua
new file mode 100644
index 0000000..37ae03d
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/raidroleindicator.lua
@@ -0,0 +1,115 @@
+--[[
+# Element: Raid Role Indicator
+
+Handles the visibility and updating of an indicator based on the unit's raid assignment (main tank or main assist).
+
+## Widget
+
+RaidRoleIndicator - A `Texture` representing the unit's raid assignment.
+
+## Notes
+
+This element updates by changing the texture.
+
+## Examples
+
+ -- Position and size
+ local RaidRoleIndicator = self:CreateTexture(nil, 'OVERLAY')
+ RaidRoleIndicator:SetSize(16, 16)
+ RaidRoleIndicator:SetPoint('TOPLEFT')
+
+ -- Register it with oUF
+ self.RaidRoleIndicator = RaidRoleIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local GetPartyAssignment = GetPartyAssignment
+local UnitHasVehicleUI = UnitHasVehicleUI
+local UnitInRaid = UnitInRaid
+
+local MAINTANK_ICON = [[Interface\GROUPFRAME\UI-GROUP-MAINTANKICON]]
+local MAINASSIST_ICON = [[Interface\GROUPFRAME\UI-GROUP-MAINASSISTICON]]
+
+local function Update(self, event)
+ local unit = self.unit
+
+ local element = self.RaidRoleIndicator
+
+ --[[ Callback: RaidRoleIndicator:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the RaidRoleIndicator element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local role, isShown
+ if(UnitInRaid(unit) and not UnitHasVehicleUI(unit)) then
+ if(GetPartyAssignment('MAINTANK', unit)) then
+ isShown = true
+ element:SetTexture(MAINTANK_ICON)
+ role = 'MAINTANK'
+ elseif(GetPartyAssignment('MAINASSIST', unit)) then
+ isShown = true
+ element:SetTexture(MAINASSIST_ICON)
+ role = 'MAINASSIST'
+ end
+ end
+
+ if isShown then
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ --[[ Callback: RaidRoleIndicator:PostUpdate(role)
+ Called after the element has been updated.
+
+ * self - the RaidRoleIndicator element
+ * role - the unit's raid assignment (string?)['MAINTANK', 'MAINASSIST']
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(role)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: RaidRoleIndicator.Override(self, event, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * ... - the arguments accompanying the event
+ --]]
+ return (self.RaidRoleIndicator.Override or Update)(self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate')
+end
+
+local function Enable(self)
+ local element = self.RaidRoleIndicator
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path, true)
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.RaidRoleIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
+ end
+end
+
+oUF:AddElement('RaidRoleIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/raidtargetindicator.lua b/ElvUI/Libraries/oUF/elements/raidtargetindicator.lua
new file mode 100644
index 0000000..3ec2d12
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/raidtargetindicator.lua
@@ -0,0 +1,102 @@
+--[[
+# Element: Raid Target Indicator
+
+Handles the visibility and updating of an indicator based on the unit's raid target assignment.
+
+## Widget
+
+RaidTargetIndicator - A `Texture` used to display the raid target icon.
+
+## Notes
+
+A default texture will be applied if the widget is a Texture and doesn't have a texture set.
+
+## Examples
+
+ -- Position and size
+ local RaidTargetIndicator = self:CreateTexture(nil, 'OVERLAY')
+ RaidTargetIndicator:SetSize(16, 16)
+ RaidTargetIndicator:SetPoint('TOPRIGHT', self)
+
+ -- Register it with oUF
+ self.RaidTargetIndicator = RaidTargetIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local GetRaidTargetIndex = GetRaidTargetIndex
+local SetRaidTargetIconTexture = SetRaidTargetIconTexture
+
+local function Update(self, event)
+ local element = self.RaidTargetIndicator
+
+ --[[ Callback: RaidTargetIndicator:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the RaidTargetIndicator element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local index = GetRaidTargetIndex(self.unit)
+ if(index) then
+ SetRaidTargetIconTexture(element, index)
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ --[[ Callback: RaidTargetIndicator:PostUpdate(index)
+ Called after the element has been updated.
+
+ * self - the RaidTargetIndicator element
+ * index - the index of the raid target marker (number?)[1-8]
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(index)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: RaidTargetIndicator.Override(self, event)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ --]]
+ return (self.RaidTargetIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ if(not element.__owner.unit) then return end
+ return Path(element.__owner, 'ForceUpdate')
+end
+
+local function Enable(self)
+ local element = self.RaidTargetIndicator
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('RAID_TARGET_UPDATE', Path, true)
+
+ if(element:IsObjectType('Texture') and not element:GetTexture()) then
+ element:SetTexture([[Interface\TargetingFrame\UI-RaidTargetingIcons]])
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.RaidTargetIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('RAID_TARGET_UPDATE', Path)
+ end
+end
+
+oUF:AddElement('RaidTargetIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/range.lua b/ElvUI/Libraries/oUF/elements/range.lua
new file mode 100644
index 0000000..3252112
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/range.lua
@@ -0,0 +1,137 @@
+--[[
+# Element: Range Fader
+
+Changes the opacity of a unit frame based on whether the frame's unit is in the player's range.
+
+## Widget
+
+Range - A table containing opacity values.
+
+## Notes
+
+Offline units are handled as if they are in range.
+
+## Options
+
+.outsideAlpha - Opacity when the unit is out of range. Defaults to 0.55 (number)[0-1].
+.insideAlpha - Opacity when the unit is within range. Defaults to 1 (number)[0-1].
+
+## Examples
+
+ -- Register with oUF
+ self.Range = {
+ insideAlpha = 1,
+ outsideAlpha = 1/2,
+ }
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local _FRAMES = {}
+local OnRangeFrame
+
+local UnitInRange, UnitIsConnected = UnitInRange, UnitIsConnected
+
+local function Update(self, event)
+ local element = self.Range
+ local unit = self.unit
+
+ --[[ Callback: Range:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the Range element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local inRange
+ local connected = UnitIsConnected(unit)
+ if(connected) then
+ inRange = UnitInRange(unit)
+ if(not inRange) then
+ self:SetAlpha(element.outsideAlpha)
+ else
+ self:SetAlpha(element.insideAlpha)
+ end
+ else
+ self:SetAlpha(element.insideAlpha)
+ end
+
+ --[[ Callback: Range:PostUpdate(object, inRange, isConnected)
+ Called after the element has been updated.
+
+ * self - the Range element
+ * object - the parent object
+ * inRange - indicates if the unit was within 40 yards of the player (boolean)
+ * isConnected - indicates if the unit is online (boolean)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(self, inRange, connected)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: Range.Override(self, event)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ --]]
+ return (self.Range.Override or Update) (self, ...)
+end
+
+-- Internal updating method
+local timer = 0
+local function OnRangeUpdate(_, elapsed)
+ timer = timer + elapsed
+
+ if(timer >= .20) then
+ for _, object in next, _FRAMES do
+ if(object:IsShown()) then
+ Path(object, 'OnUpdate')
+ end
+ end
+
+ timer = 0
+ end
+end
+
+local function Enable(self)
+ local element = self.Range
+ if(element) then
+ element.__owner = self
+ element.insideAlpha = element.insideAlpha or 1
+ element.outsideAlpha = element.outsideAlpha or 0.55
+
+ if(not OnRangeFrame) then
+ OnRangeFrame = CreateFrame('Frame')
+ OnRangeFrame:SetScript('OnUpdate', OnRangeUpdate)
+ end
+
+ table.insert(_FRAMES, self)
+ OnRangeFrame:Show()
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.Range
+ if(element) then
+ for index, frame in next, _FRAMES do
+ if(frame == self) then
+ table.remove(_FRAMES, index)
+ break
+ end
+ end
+ self:SetAlpha(element.insideAlpha)
+
+ if(#_FRAMES == 0) then
+ OnRangeFrame:Hide()
+ end
+ end
+end
+
+oUF:AddElement('Range', nil, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/readycheckindicator.lua b/ElvUI/Libraries/oUF/elements/readycheckindicator.lua
new file mode 100644
index 0000000..d8d1c44
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/readycheckindicator.lua
@@ -0,0 +1,161 @@
+--[[
+# Element: Ready Check Indicator
+
+Handles the visibility and updating of an indicator based on the unit's ready check status.
+
+## Widget
+
+ReadyCheckIndicator - A `Texture` representing ready check status.
+
+## Notes
+
+This element updates by changing the texture.
+Default textures will be applied if the layout does not provide custom ones. See Options.
+
+## Options
+
+.finishedTime - For how many seconds the icon should stick after a check has completed. Defaults to 10 (number).
+.fadeTime - For how many seconds the icon should fade away after the stick duration has completed. Defaults to
+ 1.5 (number).
+.readyTexture - Path to an alternate texture for the ready check 'ready' status.
+.notReadyTexture - Path to an alternate texture for the ready check 'notready' status.
+.waitingTexture - Path to an alternate texture for the ready check 'waiting' status.
+
+## Attributes
+
+.status - the unit's ready check status (string?)['ready', 'noready', 'waiting']
+
+## Examples
+
+ -- Position and size
+ local ReadyCheckIndicator = self:CreateTexture(nil, 'OVERLAY')
+ ReadyCheckIndicator:SetSize(16, 16)
+ ReadyCheckIndicator:SetPoint('TOP')
+
+ -- Register with oUF
+ self.ReadyCheckIndicator = ReadyCheckIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local GetReadyCheckStatus = GetReadyCheckStatus
+local UnitExists = UnitExists
+
+local function OnFinished(self)
+ local element = self:GetParent()
+ element:Hide()
+
+ --[[ Callback: ReadyCheckIndicator:PostUpdateFadeOut()
+ Called after the element has been faded out.
+
+ * self - the ReadyCheckIndicator element
+ --]]
+ if(element.PostUpdateFadeOut) then
+ element:PostUpdateFadeOut()
+ end
+end
+
+local function Update(self, event)
+ local element = self.ReadyCheckIndicator
+
+ --[[ Callback: ReadyCheckIndicator:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the ReadyCheckIndicator element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local unit = self.unit
+ local status = GetReadyCheckStatus(unit)
+ if(UnitExists(unit) and status) then
+ if(status == 'ready') then
+ element:SetTexture(element.readyTexture)
+ elseif(status == 'notready') then
+ element:SetTexture(element.notReadyTexture)
+ else
+ element:SetTexture(element.waitingTexture)
+ end
+
+ element.status = status
+ element:Show()
+ elseif(event ~= 'READY_CHECK_FINISHED') then
+ element.status = nil
+ element:Hide()
+ end
+
+ if(event == 'READY_CHECK_FINISHED') then
+ if(element.status == 'waiting') then
+ element:SetTexture(element.notReadyTexture)
+ end
+
+ element.Animation:Play()
+ end
+
+ --[[ Callback: ReadyCheckIndicator:PostUpdate(status)
+ Called after the element has been updated.
+
+ * self - the ReadyCheckIndicator element
+ * status - the unit's ready check status (string?)['ready', 'notready', 'waiting']
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(status)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: ReadyCheckIndicator.Override(self, event, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * ... - the arguments accompanying the event
+ --]]
+ return (self.ReadyCheckIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate')
+end
+
+local function Enable(self, unit)
+ local element = self.ReadyCheckIndicator
+ if(element and (unit and (unit:sub(1, 5) == 'party' or unit:sub(1, 4) == 'raid'))) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ element.readyTexture = element.readyTexture or READY_CHECK_READY_TEXTURE
+ element.notReadyTexture = element.notReadyTexture or READY_CHECK_NOT_READY_TEXTURE
+ element.waitingTexture = element.waitingTexture or READY_CHECK_WAITING_TEXTURE
+
+ local AnimationGroup = element:CreateAnimationGroup()
+ AnimationGroup:HookScript('OnFinished', OnFinished)
+ element.Animation = AnimationGroup
+
+ local Animation = AnimationGroup:CreateAnimation('Alpha')
+ Animation:SetChange(-1)
+ Animation:SetDuration(element.fadeTime or 1.5)
+ Animation:SetStartDelay(element.finishedTime or 10)
+
+ self:RegisterEvent('READY_CHECK', Path, true)
+ self:RegisterEvent('READY_CHECK_CONFIRM', Path, true)
+ self:RegisterEvent('READY_CHECK_FINISHED', Path, true)
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.ReadyCheckIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('READY_CHECK', Path)
+ self:UnregisterEvent('READY_CHECK_CONFIRM', Path)
+ self:UnregisterEvent('READY_CHECK_FINISHED', Path)
+ end
+end
+
+oUF:AddElement('ReadyCheckIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/restingindicator.lua b/ElvUI/Libraries/oUF/elements/restingindicator.lua
new file mode 100644
index 0000000..cad7f46
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/restingindicator.lua
@@ -0,0 +1,100 @@
+--[[
+# Element: Resting Indicator
+
+Toggles the visibility of an indicator based on the player's resting status.
+
+## Widget
+
+RestingIndicator - Any UI widget.
+
+## Notes
+
+A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
+
+## Examples
+
+ -- Position and size
+ local RestingIndicator = self:CreateTexture(nil, 'OVERLAY')
+ RestingIndicator:SetSize(16, 16)
+ RestingIndicator:SetPoint('TOPLEFT', self)
+
+ -- Register it with oUF
+ self.RestingIndicator = RestingIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local IsResting = IsResting
+
+local function Update(self, event)
+ local element = self.RestingIndicator
+
+ --[[ Callback: RestingIndicator:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the RestingIndicator element
+ --]]
+ if(element.PreUpdate) then
+ element:PreUpdate()
+ end
+
+ local isResting = IsResting()
+ if(isResting) then
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ --[[ Callback: RestingIndicator:PostUpdate(isResting)
+ Called after the element has been updated.
+
+ * self - the RestingIndicator element
+ * isResting - indicates if the player is resting (boolean)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(isResting)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: RestingIndicator.Override(self, event)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ --]]
+ return (self.RestingIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate')
+end
+
+local function Enable(self, unit)
+ local element = self.RestingIndicator
+ if(element and unit == 'player') then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('PLAYER_UPDATE_RESTING', Path, true)
+
+ if(element:IsObjectType('Texture') and not element:GetTexture()) then
+ element:SetTexture([[Interface\CharacterFrame\UI-StateIcon]])
+ element:SetTexCoord(0, 0.5, 0, 0.421875)
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.RestingIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('PLAYER_UPDATE_RESTING', Path)
+ end
+end
+
+oUF:AddElement('RestingIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/runes.lua b/ElvUI/Libraries/oUF/elements/runes.lua
new file mode 100644
index 0000000..bfa506b
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/runes.lua
@@ -0,0 +1,264 @@
+--[[
+# Element: Runes
+
+Handles the visibility and updating of Death Knight's runes.
+
+## Widget
+
+Runes - An `table` holding `StatusBar`s.
+
+## Sub-Widgets
+
+.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
+
+## Notes
+
+A default texture will be applied if the sub-widgets are StatusBars and don't have a texture set.
+
+## Options
+
+.colorSpec - Use `self.colors.runes[specID]` to color the bar based on player's spec. `specID` is defined by the return
+ value of [GetSpecialization](http://wowprogramming.com/docs/api/GetSpecialization) (boolean)
+
+## Sub-Widgets Options
+
+.multiplier - Used to tint the background based on the main widgets R, G and B values. Defaults to 1 (number)[0-1]
+
+## Examples
+
+ local Runes = {}
+ for index = 1, 6 do
+ -- Position and size of the rune bar indicators
+ local Rune = CreateFrame('StatusBar', nil, self)
+ Rune:SetSize(120 / 6, 20)
+ Rune:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', index * 120 / 6, 0)
+
+ Runes[index] = Rune
+ end
+
+ -- Register with oUF
+ self.Runes = Runes
+--]]
+
+if(select(2, UnitClass('player')) ~= 'DEATHKNIGHT') then return end
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local floor = math.floor
+
+local GetRuneCooldown = GetRuneCooldown
+local GetRuneType = GetRuneType
+local GetTime = GetTime
+local UnitHasVehicleUI = UnitHasVehicleUI
+
+local runemap = {1, 2, 5, 6, 3, 4}
+
+local VisibilityPath
+
+local function onUpdate(self, elapsed)
+ local duration = self.duration + elapsed
+ self.duration = duration
+ self:SetValue(duration)
+end
+
+local function UpdateType(self, event, runeID, alt)
+ local element = self.Runes
+ local rune = element[runemap[runeID]]
+ local runeType = GetRuneType(runeID) or alt
+
+ if not runeType then return end
+
+ local color = self.colors.runes[runeType]
+ local r, g, b = color[1], color[2], color[3]
+
+ rune:SetStatusBarColor(r, g, b)
+
+ if(rune.bg) then
+ local mu = rune.bg.multiplier or 1
+ rune.bg:SetVertexColor(r * mu, g * mu, b * mu)
+ end
+
+ if(element.PostUpdateType) then
+ return element:PostUpdateType(rune, runeID, alt)
+ end
+end
+
+local function Update(self, event, runeID)
+ local element = self.Runes
+ local rune = element[runemap[runeID]]
+ if(not rune) then return end
+
+ local start, duration, runeReady
+ if(UnitHasVehicleUI('player')) then
+ rune:Hide()
+ else
+ start, duration, runeReady = GetRuneCooldown(runeID)
+ if(not start) then return end
+
+ if(runeReady) then
+ rune:SetMinMaxValues(0, 1)
+ rune:SetValue(1)
+ rune:SetScript('OnUpdate', nil)
+ else
+ rune.duration = GetTime() - start
+ rune.max = duration
+ rune:SetMinMaxValues(0, duration)
+ rune:SetValue(0)
+ rune:SetScript('OnUpdate', onUpdate)
+ end
+
+ rune:Show()
+ end
+
+ --[[ Callback: Runes:PostUpdate(rune, runeID, start, duration, isReady)
+ Called after the element has been updated.
+
+ * self - the Runes element
+ * rune - the updated rune (StatusBar)
+ * runeID - the index of the updated rune (number)
+ * start - the value of `GetTime()` when the rune cooldown started (0 for ready) (number)
+ * duration - the duration of the rune's cooldown (number)
+ * isReady - indicates if the rune is ready for use (boolean)
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(rune, runeID, start, duration, runeReady)
+ end
+end
+
+local function Path(self, event, ...)
+ local element = self.Runes
+ --[[ Override: Runes.Override(self, event, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * ... - the arguments accompanying the event
+ --]]
+ local UpdateMethod = element.Override or Update
+ if(event == 'RUNE_POWER_UPDATE') then
+ return UpdateMethod(self, event, ...)
+ else
+ --[[ Override: Runes:UpdateType(powerType)
+ Used to completely override the internal function for updating the widgets' colors.
+
+ * self - the Runes element
+ * index - the index of the updated rune (number)
+ --]]
+ local UpdateTypeMethod = element.UpdateType or UpdateType
+ for index = 1, #element do
+ UpdateTypeMethod(self, element, index)
+ UpdateMethod(self, event, index)
+ end
+ end
+end
+
+local function RunesEnable(self)
+ self:RegisterEvent('UNIT_ENTERED_VEHICLE', VisibilityPath)
+ self:UnregisterEvent('UNIT_EXITED_VEHICLE', VisibilityPath)
+
+ self.Runes:Show()
+
+ if self.Runes.PostUpdateVisibility then
+ self.Runes:PostUpdateVisibility(true, not self.Runes.isEnabled)
+ end
+
+ self.Runes.isEnabled = true
+
+ Path(self, 'RunesEnable')
+end
+
+local function RunesDisable(self)
+ self:UnregisterEvent('UNIT_ENTERED_VEHICLE', VisibilityPath)
+ self:RegisterEvent('UNIT_EXITED_VEHICLE', VisibilityPath)
+
+ self.Runes:Hide()
+
+ if self.Runes.PostUpdateVisibility then
+ self.Runes:PostUpdateVisibility(false, self.Runes.isEnabled)
+ end
+
+ self.Runes.isEnabled = false
+
+ Path(self, 'RunesDisable')
+end
+
+local function Visibility(self, event, ...)
+ local element = self.Runes
+ local shouldEnable
+
+ if not (UnitHasVehicleUI('player')) then
+ shouldEnable = true
+ end
+
+ local isEnabled = element.isEnabled
+ if(shouldEnable and not isEnabled) then
+ RunesEnable(self)
+ elseif(not shouldEnable and (isEnabled or isEnabled == nil)) then
+ RunesDisable(self)
+ elseif(shouldEnable and isEnabled) then
+ Path(self, event, ...)
+ end
+end
+
+VisibilityPath = function(self, ...)
+ return (self.Runes.OverrideVisibility or Visibility) (self, ...)
+end
+
+local ForceUpdate = function(element)
+ return VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+local function Enable(self, unit)
+ local element = self.Runes
+ if(element and unit == 'player') then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ for i = 1, #element do
+ local rune = element[runemap[i]]
+ if(rune:IsObjectType('StatusBar') and not rune:GetStatusBarTexture()) then
+ rune:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
+ end
+
+ -- From my minor testing this is a okey solution. A full login always remove
+ -- the death runes, or at least the clients knowledge about them.
+ UpdateType(self, nil, i, floor((i + 1) / 2))
+ end
+
+ self:RegisterEvent('RUNE_POWER_UPDATE', Path, true)
+ self:RegisterEvent('RUNE_TYPE_UPDATE', UpdateType, true)
+ self:RegisterEvent('PLAYER_ENTERING_WORLD', Path)
+
+ -- oUF leaves the vehicle events registered on the player frame, so
+ -- buffs and such are correctly updated when entering/exiting vehicles.
+ --
+ -- This however makes the code also show/hide the RuneFrame.
+ RuneFrame.Show = RuneFrame.Hide
+ RuneFrame:Hide()
+
+ return true
+ end
+end
+
+local function Disable(self)
+ RuneFrame.Show = nil
+ RuneFrame:Show()
+
+ local element = self.Runes
+ if(element) then
+ for i = 1, #element do
+ element[i]:Hide()
+ end
+
+ self:SetScript('OnUpdate', nil)
+
+ self:UnregisterEvent('RUNE_POWER_UPDATE', Path)
+ self:UnregisterEvent('RUNE_TYPE_UPDATE', UpdateType)
+ self:UnregisterEvent('PLAYER_ENTERING_WORLD', Path)
+
+ RunesDisable(self)
+ end
+end
+
+oUF:AddElement('Runes', VisibilityPath, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/tags.lua b/ElvUI/Libraries/oUF/elements/tags.lua
new file mode 100644
index 0000000..60969fd
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/tags.lua
@@ -0,0 +1,872 @@
+-- Credits: Vika, Cladhaire, Tekkub
+--[[
+# Element: Tags
+
+Provides a system for text-based display of information by binding a tag string to a font string widget which in turn is
+tied to a unit frame.
+
+## Widget
+
+A FontString to hold a tag string. Unlike other elements, this widget must not have a preset name.
+
+## Notes
+
+A `Tag` is a Lua string consisting of a function name surrounded by square brackets. The tag will be replaced by the
+output of the function and displayed as text on the font string widget with that the tag has been registered. Literals
+can be pre- or appended by separating them with a `>` before or `<` after the function name. The literals will be only
+displayed when the function returns a non-nil value. I.e. `"[perhp<%]"` will display the current health as a percentage
+of the maximum health followed by the % sign.
+
+A `Tag String` is a Lua string consisting of one or multiple tags with optional literals between them. Each tag will be
+updated individually and the output will follow the tags order. Literals will be displayed in the output string
+regardless of whether the surrounding tag functions return a value. I.e. `"[curhp]/[maxhp]"` will resolve to something
+like `2453/5000`.
+
+A `Tag Function` is used to replace a single tag in a tag string by its output. A tag function receives only two
+arguments - the unit and the realUnit of the unit frame used to register the tag (see Options for further details). The
+tag function is called when the unit frame is shown or when a specified event has fired. It the tag is registered on an
+eventless frame (i.e. one holding the unit "targettarget"), then the tag function is called in a set time interval.
+
+A number of built-in tag functions exist. The layout can also define its own tag functions by adding them to the
+`oUF.Tags.Methods` table. The events upon which the function will be called are specified in a white-space separated
+list added to the `oUF.Tags.Events` table. Should an event fire without unit information, then it should also be listed
+in the `oUF.Tags.SharedEvents` table as follows: `oUF.Tags.SharedEvents.EVENT_NAME = true`.
+
+## Options
+
+.overrideUnit - if specified on the font string widget, the frame's realUnit will be passed as the second argument to
+ every tag function whose name is contained in the relevant tag string. Otherwise the second argument
+ is always nil (boolean)
+.frequentUpdates - defines how often the correspondig tag function(s) should be called. This will override the events for
+ the tag(s), if any. If the value is a number, it is taken as a time interval in seconds. If the value
+ is a boolean, the time interval is set to 0.5 seconds (number or boolean)
+
+## Attributes
+
+.parent - the unit frame on which the tag has been registered
+
+## Examples
+
+ -- define the tag function
+ oUF.Tags.Methods['mylayout:threatname'] = function(unit, realUnit)
+ local color = _TAGS['threatcolor'](unit)
+ local name = _TAGS['name'](unit, realUnit)
+ return string.format('%s%s|r', color, name)
+ end
+
+ -- add the events
+ oUF.Tags.Events['mylayout:threatname'] = 'UNIT_NAME_UPDATE UNIT_THREAT_SITUATION_UPDATE'
+
+ -- create the text widget
+ local info = self.Health:CreateFontString(nil, 'OVERLAY', 'GameFontNormal')
+ info:SetPoint('LEFT')
+
+ -- register the tag on the text widget with oUF
+ self:Tag(info, '[mylayout:threatname]')
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local _G = _G
+local unpack = unpack
+local floor = math.floor
+local format = string.format
+local tinsert, tremove = table.insert, table.remove
+
+local GetComboPoints = GetComboPoints
+local GetNumRaidMembers = GetNumRaidMembers
+local GetPetHappiness = GetPetHappiness
+local GetQuestDifficultyColor = GetQuestDifficultyColor
+local GetRaidRosterInfo = GetRaidRosterInfo
+local GetThreatStatusColor = GetThreatStatusColor
+local IsResting = IsResting
+local UnitCanAttack = UnitCanAttack
+local UnitClass = UnitClass
+local UnitClassification = UnitClassification
+local UnitCreatureFamily = UnitCreatureFamily
+local UnitCreatureType = UnitCreatureType
+local UnitFactionGroup = UnitFactionGroup
+local UnitHasVehicleUI = UnitHasVehicleUI
+local UnitHealth = UnitHealth
+local UnitHealthMax = UnitHealthMax
+local UnitIsConnected = UnitIsConnected
+local UnitIsDead = UnitIsDead
+local UnitIsGhost = UnitIsGhost
+local UnitIsPVP = UnitIsPVP
+local UnitIsPartyLeader = UnitIsPartyLeader
+local UnitIsPlayer = UnitIsPlayer
+local UnitLevel = UnitLevel
+local UnitName = UnitName
+local UnitPower = UnitPower
+local UnitPowerMax = UnitPowerMax
+local UnitPowerType = UnitPowerType
+local UnitRace = UnitRace
+local UnitSex = UnitSex
+local UnitThreatSituation = UnitThreatSituation
+
+local _PATTERN = '%[..-%]+'
+
+local _ENV = {
+ Hex = function(r, g, b)
+ if(type(r) == 'table') then
+ if(r.r) then
+ r, g, b = r.r, r.g, r.b
+ else
+ r, g, b = unpack(r)
+ end
+ end
+ if not r or type(r) == 'string' then
+ return '|cffFFFFFF'
+ end
+ return format('|cff%02x%02x%02x', r * 255, g * 255, b * 255)
+ end,
+ ColorGradient = oUF.ColorGradient,
+}
+local _PROXY = setmetatable(_ENV, {__index = _G})
+
+local tagStrings = {
+ ['creature'] = [[function(u)
+ return UnitCreatureFamily(u) or UnitCreatureType(u)
+ end]],
+
+ ['dead'] = [[function(u)
+ if(UnitIsDead(u)) then
+ return 'Dead'
+ elseif(UnitIsGhost(u)) then
+ return 'Ghost'
+ end
+ end]],
+
+ ['difficulty'] = [[function(u)
+ if UnitCanAttack('player', u) then
+ local l = UnitLevel(u)
+ return Hex(GetQuestDifficultyColor((l > 0) and l or 999))
+ end
+ end]],
+
+ ['leader'] = [[function(u)
+ if(UnitIsPartyLeader(u)) then
+ return 'L'
+ end
+ end]],
+
+ ['leaderlong'] = [[function(u)
+ if(UnitIsPartyLeader(u)) then
+ return 'Leader'
+ end
+ end]],
+
+ ['level'] = [[function(u)
+ local l = UnitLevel(u)
+ if(l > 0) then
+ return l
+ else
+ return '??'
+ end
+ end]],
+
+ ['missinghp'] = [[function(u)
+ local current = UnitHealthMax(u) - UnitHealth(u)
+ if(current > 0) then
+ return current
+ end
+ end]],
+
+ ['missingpp'] = [[function(u)
+ local current = UnitPowerMax(u) - UnitPower(u)
+ if(current > 0) then
+ return current
+ end
+ end]],
+
+ ['name'] = [[function(u, r)
+ return UnitName(r or u)
+ end]],
+
+ ['offline'] = [[function(u)
+ if(not UnitIsConnected(u)) then
+ return 'Offline'
+ end
+ end]],
+
+ ['perhp'] = [[function(u)
+ local m = UnitHealthMax(u)
+ if(m == 0) then
+ return 0
+ else
+ return floor(UnitHealth(u) / m * 100 + .5)
+ end
+ end]],
+
+ ['perpp'] = [[function(u)
+ local m = UnitPowerMax(u)
+ if(m == 0) then
+ return 0
+ else
+ return floor(UnitPower(u) / m * 100 + .5)
+ end
+ end]],
+
+ ['plus'] = [[function(u)
+ local c = UnitClassification(u)
+ if(c == 'elite' or c == 'rareelite') then
+ return '+'
+ end
+ end]],
+
+ ['pvp'] = [[function(u)
+ if(UnitIsPVP(u)) then
+ return 'PvP'
+ end
+ end]],
+
+ ['raidcolor'] = [[function(u)
+ local _, x = UnitClass(u)
+ if(x) then
+ return Hex(_COLORS.class[x])
+ end
+ end]],
+
+ ['rare'] = [[function(u)
+ local c = UnitClassification(u)
+ if(c == 'rare' or c == 'rareelite') then
+ return 'Rare'
+ end
+ end]],
+
+ ['resting'] = [[function(u)
+ if(u == 'player' and IsResting()) then
+ return 'zzz'
+ end
+ end]],
+
+ ['sex'] = [[function(u)
+ local s = UnitSex(u)
+ if(s == 2) then
+ return 'Male'
+ elseif(s == 3) then
+ return 'Female'
+ end
+ end]],
+
+ ['smartclass'] = [[function(u)
+ if(UnitIsPlayer(u)) then
+ return _TAGS['class'](u)
+ end
+
+ return _TAGS['creature'](u)
+ end]],
+
+ ['status'] = [[function(u)
+ if(UnitIsDead(u)) then
+ return 'Dead'
+ elseif(UnitIsGhost(u)) then
+ return 'Ghost'
+ elseif(not UnitIsConnected(u)) then
+ return 'Offline'
+ else
+ return _TAGS['resting'](u)
+ end
+ end]],
+
+ ['threat'] = [[function(u)
+ local s = UnitThreatSituation(u)
+ if(s == 1) then
+ return '++'
+ elseif(s == 2) then
+ return '--'
+ elseif(s == 3) then
+ return 'Aggro'
+ end
+ end]],
+
+ ['threatcolor'] = [[function(u)
+ return Hex(GetThreatStatusColor(UnitThreatSituation(u)))
+ end]],
+
+ ['cpoints'] = [[function(u)
+ local cp
+ if(UnitHasVehicleUI('player')) then
+ cp = GetComboPoints('vehicle', 'target')
+ else
+ cp = GetComboPoints('player', 'target')
+ end
+
+ if(cp > 0) then
+ return cp
+ end
+ end]],
+
+ ['smartlevel'] = [[function(u)
+ local c = UnitClassification(u)
+ if(c == 'worldboss') then
+ return 'Boss'
+ else
+ local plus = _TAGS['plus'](u)
+ local level = _TAGS['level'](u)
+ if(plus) then
+ return level .. plus
+ else
+ return level
+ end
+ end
+ end]],
+
+ ['classification'] = [[function(u)
+ local c = UnitClassification(u)
+ if(c == 'rare') then
+ return 'Rare'
+ elseif(c == 'rareelite') then
+ return 'Rare Elite'
+ elseif(c == 'elite') then
+ return 'Elite'
+ elseif(c == 'worldboss') then
+ return 'Boss'
+ end
+ end]],
+
+ ['shortclassification'] = [[function(u)
+ local c = UnitClassification(u)
+ if(c == 'rare') then
+ return 'R'
+ elseif(c == 'rareelite') then
+ return 'R+'
+ elseif(c == 'elite') then
+ return '+'
+ elseif(c == 'worldboss') then
+ return 'B'
+ end
+ end]],
+
+ ['group'] = [[function(unit)
+ local name, server = UnitName(unit)
+ if(server and server ~= '') then
+ name = format('%s-%s', name, server)
+ end
+
+ for i=1, GetNumRaidMembers() do
+ local raidName, _, group = GetRaidRosterInfo(i)
+ if(raidName == name) then
+ return group
+ end
+ end
+ end]],
+
+ ['deficit:name'] = [[function(u)
+ local missinghp = _TAGS['missinghp'](u)
+ if(missinghp) then
+ return '-' .. missinghp
+ else
+ return _TAGS['name'](u)
+ end
+ end]],
+
+ ['curmana'] = [[function(unit)
+ return UnitPower(unit, SPELL_POWER_MANA)
+ end]],
+
+ ['maxmana'] = [[function(unit)
+ return UnitPowerMax(unit, SPELL_POWER_MANA)
+ end]],
+
+ ['happiness'] = [[function(u)
+ if(UnitIsUnit(u, 'pet')) then
+ local happiness = GetPetHappiness()
+ if(happiness == 1) then
+ return ':<'
+ elseif(happiness == 2) then
+ return ':|'
+ elseif(happiness == 3) then
+ return ':D'
+ end
+ end
+ end]],
+
+ ['powercolor'] = [[function(u)
+ local pType, pToken, altR, altG, altB = UnitPowerType(u)
+ local t = _COLORS.power[pToken]
+
+ if not t then
+ return Hex(altR, altG, altB)
+ end
+
+ return Hex(t)
+ end]],
+
+ ['energycolor'] = [[function(u)
+ local pType, pToken, altR, altG, altB = UnitPowerType(u)
+ local t = _COLORS.power["ENERGY"]
+
+ if not t then
+ return Hex(altR, altG, altB)
+ end
+
+ return Hex(t)
+ end]],
+
+ ['ragecolor'] = [[function(u)
+ local pType, pToken, altR, altG, altB = UnitPowerType(u)
+ local t = _COLORS.power["RAGE"]
+
+ if not t then
+ return Hex(altR, altG, altB)
+ end
+
+ return Hex(t)
+ end]],
+}
+
+local tags = setmetatable(
+ {
+ curhp = UnitHealth,
+ curpp = UnitPower,
+ maxhp = UnitHealthMax,
+ maxpp = UnitPowerMax,
+ class = UnitClass,
+ faction = UnitFactionGroup,
+ race = UnitRace,
+ },
+ {
+ __index = function(self, key)
+ local tagFunc = tagStrings[key]
+ if(tagFunc) then
+ local func, err = loadstring('return ' .. tagFunc)
+ if(func) then
+ func = func()
+
+ -- Want to trigger __newindex, so no rawset.
+ self[key] = func
+ tagStrings[key] = nil
+
+ return func
+ else
+ error(err, 3)
+ end
+ end
+ end,
+ __newindex = function(self, key, val)
+ if(type(val) == 'string') then
+ tagStrings[key] = val
+ elseif(type(val) == 'function') then
+ -- So we don't clash with any custom envs.
+ if(getfenv(val) == _G) then
+ setfenv(val, _PROXY)
+ end
+
+ rawset(self, key, val)
+ end
+ end,
+ }
+)
+
+_ENV._TAGS = tags
+
+local tagEvents = {
+ ['curhp'] = 'UNIT_HEALTH',
+ ['maxhp'] = 'UNIT_MAXHEALTH',
+ ['curpp'] = 'UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_RUNIC_POWER',
+ ['maxpp'] = 'UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_MAXRUNIC_POWER',
+ ['dead'] = 'UNIT_HEALTH',
+ ['leader'] = 'PARTY_LEADER_CHANGED',
+ ['leaderlong'] = 'PARTY_LEADER_CHANGED',
+ ['level'] = 'UNIT_LEVEL PLAYER_LEVEL_UP',
+ ['missinghp'] = 'UNIT_HEALTH UNIT_MAXHEALTH',
+ ['missingpp'] = 'UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_MAXRUNIC_POWER UNIT_RUNIC_POWER',
+ ['name'] = 'UNIT_NAME_UPDATE',
+ ['offline'] = 'UNIT_HEALTH',
+ ['perhp'] = 'UNIT_HEALTH UNIT_MAXHEALTH',
+ ['perpp'] = 'UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_MAXRUNIC_POWER UNIT_RUNIC_POWER',
+ ['plus'] = 'UNIT_CLASSIFICATION_CHANGED',
+ ['pvp'] = 'UNIT_FACTION',
+ ['rare'] = 'UNIT_CLASSIFICATION_CHANGED',
+ ['resting'] = 'PLAYER_UPDATE_RESTING',
+ ['status'] = 'UNIT_HEALTH PLAYER_UPDATE_RESTING',
+ ['threat'] = 'UNIT_THREAT_SITUATION_UPDATE',
+ ['threatcolor'] = 'UNIT_THREAT_SITUATION_UPDATE',
+ ['cpoints'] = 'UNIT_COMBO_POINTS PLAYER_TARGET_CHANGED',
+ ['smartlevel'] = 'UNIT_LEVEL PLAYER_LEVEL_UP UNIT_CLASSIFICATION_CHANGED',
+ ['classification'] = 'UNIT_CLASSIFICATION_CHANGED',
+ ['shortclassification'] = 'UNIT_CLASSIFICATION_CHANGED',
+ ['group'] = 'PARTY_MEMBERS_CHANGED RAID_ROSTER_UPDATE',
+ ['curmana'] = 'UNIT_MANA UNIT_MAXMANA',
+ ['maxmana'] = 'UNIT_MANA UNIT_MAXMANA',
+ ['happiness'] = 'UNIT_HAPPINESS',
+ ['powercolor'] = 'UNIT_DISPLAYPOWER',
+ ['energycolor'] = 'UNIT_DISPLAYPOWER',
+ ['ragecolor'] = 'UNIT_DISPLAYPOWER',
+}
+
+local unitlessEvents = {
+ PLAYER_LEVEL_UP = true,
+ PLAYER_UPDATE_RESTING = true,
+ PLAYER_TARGET_CHANGED = true,
+
+ RAID_ROSTER_UPDATE = true,
+ PARTY_MEMBERS_CHANGED = true,
+ PARTY_LEADER_CHANGED = true,
+
+ UNIT_COMBO_POINTS = true,
+}
+
+local events = {}
+local frame = CreateFrame('Frame')
+frame:SetScript('OnEvent', function(self, event, unit)
+ local strings = events[event]
+ if(strings) then
+ for _, fontstring in next, strings do
+ if(fontstring:IsVisible() and (unitlessEvents[event] or fontstring.parent.unit == unit)) then
+ fontstring:UpdateTag()
+ end
+ end
+ end
+end)
+
+local onUpdates = {}
+local eventlessUnits = {}
+
+local function createOnUpdate(timer)
+ local OnUpdate = onUpdates[timer]
+
+ if(not OnUpdate) then
+ local total = timer
+ local frame = CreateFrame('Frame')
+ local strings = eventlessUnits[timer]
+
+ frame:SetScript('OnUpdate', function(self, elapsed)
+ if(total >= timer) then
+ for _, fs in next, strings do
+ if(fs.parent:IsShown() and UnitExists(fs.parent.unit)) then
+ fs:UpdateTag()
+ end
+ end
+
+ total = 0
+ end
+
+ total = total + elapsed
+ end)
+
+ onUpdates[timer] = frame
+ end
+end
+
+local function onShow(self)
+ for _, fs in next, self.__tags do
+ fs:UpdateTag()
+ end
+end
+
+local function getTagName(tag)
+ local tagStart = (tag:match('>+()') or 2)
+ local tagEnd = tag:match('.*()<+')
+ tagEnd = (tagEnd and tagEnd - 1) or -2
+
+ return tag:sub(tagStart, tagEnd), tagStart, tagEnd
+end
+
+local function registerEvent(fontstr, event)
+ if(not events[event]) then events[event] = {} end
+
+ frame:RegisterEvent(event)
+ tinsert(events[event], fontstr)
+end
+
+local function registerEvents(fontstr, tagstr)
+ for tag in tagstr:gmatch(_PATTERN) do
+ tag = getTagName(tag)
+ local tagevents = tagEvents[tag]
+ if(tagevents) then
+ for event in tagevents:gmatch('%S+') do
+ registerEvent(fontstr, event)
+ end
+ end
+ end
+end
+
+local function unregisterEvents(fontstr)
+ for event, data in next, events do
+ for i, tagfsstr in next, data do
+ if(tagfsstr == fontstr) then
+ if(#data == 1) then
+ frame:UnregisterEvent(event)
+ end
+
+ tremove(data, i)
+ end
+ end
+ end
+end
+
+local OnEnter = function(self)
+ for _, fs in pairs(self.__mousetags) do
+ fs:SetAlpha(1)
+ end
+end
+
+local OnLeave = function(self)
+ for _, fs in pairs(self.__mousetags) do
+ fs:SetAlpha(0)
+ end
+end
+
+local onUpdateDelay = {}
+local tagPool = {}
+local funcPool = {}
+local tmp = {}
+local escapeSequences = {
+ ["||c"] = "|c",
+ ["||r"] = "|r",
+ ["||T"] = "|T",
+ ["||t"] = "|t",
+}
+
+--[[ Tags: frame:Tag(fs, tagstr)
+Used to register a tag on a unit frame.
+
+* self - the unit frame on which to register the tag
+* fs - the font string to display the tag (FontString)
+* tagstr - the tag string (string)
+--]]
+local function Tag(self, fs, tagstr)
+ if(not fs or not tagstr) then return end
+
+ if(not self.__tags) then
+ self.__tags = {}
+ self.__mousetags = {}
+ tinsert(self.__elements, onShow)
+ else
+ -- Since people ignore everything that's good practice - unregister the tag
+ -- if it already exists.
+ for _, tag in pairs(self.__tags) do
+ if(fs == tag) then
+ -- We don't need to remove it from the __tags table as Untag handles
+ -- that for us.
+ self:Untag(fs)
+ end
+ end
+ end
+
+ fs.parent = self
+
+ for escapeSequence, replacement in pairs(escapeSequences) do
+ while tagstr:find(escapeSequence) do
+ tagstr = tagstr:gsub(escapeSequence, replacement)
+ end
+ end
+
+ if tagstr:find('%[mouseover%]') then
+ tinsert(self.__mousetags, fs)
+ fs:SetAlpha(0)
+ if not self.__HookFunc then
+ self:HookScript('OnEnter', OnEnter)
+ self:HookScript('OnLeave', OnLeave)
+ self.__HookFunc = true;
+ end
+ tagstr = tagstr:gsub('%[mouseover%]', '')
+ else
+ for index, fontString in pairs(self.__mousetags) do
+ if fontString == fs then
+ self.__mousetags[index] = nil;
+ fs:SetAlpha(1)
+ end
+ end
+ end
+
+ local containsOnUpdate
+ for tag in tagstr:gmatch(_PATTERN) do
+ tag = getTagName(tag)
+ if not tagEvents[tag] then
+ containsOnUpdate = onUpdateDelay[tag] or 0.15;
+ end
+ end
+
+ local func = tagPool[tagstr]
+ if(not func) then
+ local format, numTags = tagstr:gsub('%%', '%%%%'):gsub(_PATTERN, '%%s')
+ local args = {}
+
+ for bracket in tagstr:gmatch(_PATTERN) do
+ local tagFunc = funcPool[bracket] or tags[bracket:sub(2, -2)]
+ if(not tagFunc) then
+ local tagName, tagStart, tagEnd = getTagName(bracket)
+
+ local tag = tags[tagName]
+ if(tag) then
+ tagStart = tagStart - 2
+ tagEnd = tagEnd + 2
+
+ if(tagStart ~= 0 and tagEnd ~= 0) then
+ local prefix = bracket:sub(2, tagStart)
+ local suffix = bracket:sub(tagEnd, -2)
+
+ tagFunc = function(unit, realUnit)
+ local str = tag(unit, realUnit)
+ if(str) then
+ return prefix .. str .. suffix
+ end
+ end
+ elseif(tagStart ~= 0) then
+ local prefix = bracket:sub(2, tagStart)
+
+ tagFunc = function(unit, realUnit)
+ local str = tag(unit, realUnit)
+ if(str) then
+ return prefix .. str
+ end
+ end
+ elseif(tagEnd ~= 0) then
+ local suffix = bracket:sub(tagEnd, -2)
+
+ tagFunc = function(unit, realUnit)
+ local str = tag(unit, realUnit)
+ if(str) then
+ return str .. suffix
+ end
+ end
+ end
+
+ funcPool[bracket] = tagFunc
+ end
+ end
+
+ if(tagFunc) then
+ tinsert(args, tagFunc)
+ else
+ numTags = -1
+ func = function(self)
+ return self:SetText(bracket)
+ end
+ end
+ end
+
+ if(numTags == 1) then
+ func = function(self)
+ local parent = self.parent
+ local realUnit
+ if(self.overrideUnit) then
+ realUnit = parent.realUnit
+ end
+
+ _ENV._COLORS = parent.colors
+ return self:SetFormattedText(
+ format,
+ args[1](parent.unit, realUnit) or ''
+ )
+ end
+ elseif(numTags == 2) then
+ func = function(self)
+ local parent = self.parent
+ local unit = parent.unit
+ local realUnit
+ if(self.overrideUnit) then
+ realUnit = parent.realUnit
+ end
+
+ _ENV._COLORS = parent.colors
+ return self:SetFormattedText(
+ format,
+ args[1](unit, realUnit) or '',
+ args[2](unit, realUnit) or ''
+ )
+ end
+ elseif(numTags == 3) then
+ func = function(self)
+ local parent = self.parent
+ local unit = parent.unit
+ local realUnit
+ if(self.overrideUnit) then
+ realUnit = parent.realUnit
+ end
+
+ _ENV._COLORS = parent.colors
+ return self:SetFormattedText(
+ format,
+ args[1](unit, realUnit) or '',
+ args[2](unit, realUnit) or '',
+ args[3](unit, realUnit) or ''
+ )
+ end
+ elseif numTags ~= -1 then
+ func = function(self)
+ local parent = self.parent
+ local unit = parent.unit
+ local realUnit
+ if(self.overrideUnit) then
+ realUnit = parent.realUnit
+ end
+
+ _ENV._COLORS = parent.colors
+ for i, func in next, args do
+ tmp[i] = func(unit, realUnit) or ''
+ end
+
+ -- We do 1, numTags because tmp can hold several unneeded variables.
+ return self:SetFormattedText(format, unpack(tmp, 1, numTags))
+ end
+ end
+
+ if numTags ~= -1 then
+ tagPool[tagstr] = func
+ end
+ end
+ fs.UpdateTag = func
+
+ local unit = self.unit
+ if(self.__eventless or fs.frequentUpdates) or containsOnUpdate then
+ local timer
+ if(type(fs.frequentUpdates) == 'number') then
+ timer = fs.frequentUpdates
+ elseif containsOnUpdate then
+ timer = containsOnUpdate
+ else
+ timer = .1
+ end
+
+ if(not eventlessUnits[timer]) then eventlessUnits[timer] = {} end
+ tinsert(eventlessUnits[timer], fs)
+
+ createOnUpdate(timer)
+ else
+ registerEvents(fs, tagstr)
+ end
+
+ tinsert(self.__tags, fs)
+end
+
+--[[ Tags: frame:Untag(fs)
+Used to unregister a tag from a unit frame.
+
+* self - the unit frame from which to unregister the tag
+* fs - the font string holding the tag (FontString)
+--]]
+local function Untag(self, fs)
+ if(not fs) then return end
+
+ unregisterEvents(fs)
+ for _, timers in next, eventlessUnits do
+ for i, fontstr in next, timers do
+ if(fs == fontstr) then
+ tremove(timers, i)
+ end
+ end
+ end
+
+ for i, fontstr in next, self.__tags do
+ if(fontstr == fs) then
+ tremove(self.__tags, i)
+ end
+ end
+
+ fs.UpdateTag = nil
+end
+
+oUF.Tags = {
+ Methods = tags,
+ Events = tagEvents,
+ SharedEvents = unitlessEvents,
+ OnUpdateThrottle = onUpdateDelay,
+}
+
+oUF:RegisterMetaFunction('Tag', Tag)
+oUF:RegisterMetaFunction('Untag', Untag)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/elements/threatindicator.lua b/ElvUI/Libraries/oUF/elements/threatindicator.lua
new file mode 100644
index 0000000..79234f6
--- /dev/null
+++ b/ElvUI/Libraries/oUF/elements/threatindicator.lua
@@ -0,0 +1,134 @@
+--[[
+# Element: Threat Indicator
+
+Handles the visibility and updating of an indicator based on the unit's current threat level.
+
+## Widget
+
+ThreatIndicator - A `Texture` used to display the current threat level.
+The element works by changing the texture's vertex color.
+
+## Notes
+
+A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
+
+## Options
+
+.feedbackUnit - The unit whose threat situation is being requested. If defined, it'll be passed as the first argument to
+ [GetThreatStatusColor](http://wowprogramming.com/docs/api/UnitThreatSituation).
+
+## Examples
+
+ -- Position and size
+ local ThreatIndicator = self:CreateTexture(nil, 'OVERLAY')
+ ThreatIndicator:SetSize(16, 16)
+ ThreatIndicator:SetPoint('TOPRIGHT', self)
+
+ -- Register it with oUF
+ self.ThreatIndicator = ThreatIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local GetThreatStatusColor = GetThreatStatusColor
+local UnitExists = UnitExists
+local UnitThreatSituation = UnitThreatSituation
+
+local function Update(self, event, unit)
+ if(not unit or self.unit ~= unit) then return end
+
+ local element = self.ThreatIndicator
+ --[[ Callback: ThreatIndicator:PreUpdate(unit)
+ Called before the element has been updated.
+
+ * self - the ThreatIndicator element
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if(element.PreUpdate) then element:PreUpdate(unit) end
+
+ local feedbackUnit = element.feedbackUnit
+ unit = unit or self.unit
+
+ local status
+ -- BUG: Non-existent '*target' or '*pet' units cause UnitThreatSituation() errors
+ if(UnitExists(unit)) then
+ if(feedbackUnit and feedbackUnit ~= unit and UnitExists(feedbackUnit)) then
+ status = UnitThreatSituation(feedbackUnit, unit)
+ else
+ status = UnitThreatSituation(unit)
+ end
+ end
+
+ local r, g, b
+ if(status and status > 0) then
+ r, g, b = GetThreatStatusColor(status)
+
+ if(element.SetVertexColor) then
+ element:SetVertexColor(r, g, b)
+ end
+
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ --[[ Callback: ThreatIndicator:PostUpdate(unit, status, r, g, b)
+ Called after the element has been updated.
+
+ * self - the ThreatIndicator element
+ * unit - the unit for which the update has been triggered (string)
+ * status - the unit's threat status (see [UnitThreatSituation](http://wowprogramming.com/docs/api/UnitThreatSituation))
+ * r - the red color component based on the unit's threat status (number?)[0-1]
+ * g - the green color component based on the unit's threat status (number?)[0-1]
+ * b - the blue color component based on the unit's threat status (number?)[0-1]
+ --]]
+ if(element.PostUpdate) then
+ return element:PostUpdate(unit, status, r, g, b)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: ThreatIndicator.Override(self, event, ...)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * ... - the arguments accompanying the event
+ --]]
+ return (self.ThreatIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+local function Enable(self)
+ local element = self.ThreatIndicator
+ if(element) then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent('UNIT_THREAT_SITUATION_UPDATE', Path)
+ self:RegisterEvent('UNIT_THREAT_LIST_UPDATE', Path)
+
+ if(element:IsObjectType('Texture') and not element:GetTexture()) then
+ element:SetTexture([[Interface\Minimap\ObjectIcons]])
+ element:SetTexCoord(6/8, 7/8, 1/8, 2/8)
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.ThreatIndicator
+ if(element) then
+ element:Hide()
+
+ self:UnregisterEvent('UNIT_THREAT_SITUATION_UPDATE', Path)
+ self:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', Path)
+ end
+end
+
+oUF:AddElement('ThreatIndicator', Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/events.lua b/ElvUI/Libraries/oUF/events.lua
new file mode 100644
index 0000000..3ecd036
--- /dev/null
+++ b/ElvUI/Libraries/oUF/events.lua
@@ -0,0 +1,120 @@
+local parent, ns = ...
+local oUF = ns.oUF
+local Private = oUF.Private
+
+local argcheck = Private.argcheck
+local error = Private.error
+local frame_metatable = Private.frame_metatable
+
+-- Original event methods
+local registerEvent = frame_metatable.__index.RegisterEvent
+local unregisterEvent = frame_metatable.__index.UnregisterEvent
+
+function Private.UpdateUnits(frame, unit, realUnit)
+ if(unit == realUnit) then
+ realUnit = nil
+ end
+
+ if(frame.unit ~= unit or frame.realUnit ~= realUnit) then
+ frame.unit = unit
+ frame.realUnit = realUnit
+ frame.id = unit:match('^.-(%d+)')
+ return true
+ end
+end
+
+local function onEvent(self, event, ...)
+ if(self:IsVisible() or event == 'UNIT_COMBO_POINTS') then
+ return self[event](self, event, ...)
+ end
+end
+
+local event_metatable = {
+ __call = function(funcs, self, ...)
+ for _, func in next, funcs do
+ func(self, ...)
+ end
+ end,
+}
+
+--[[ Events: frame:RegisterEvent(event, func, unitless)
+Used to register a frame for a game event and add an event handler. OnUpdate polled frames are prevented from
+registering events.
+
+* self - frame that will be registered for the given event.
+* event - name of the event to register (string)
+* func - function that will be executed when the event fires. If a string is passed, then a function by that name
+ must be defined on the frame. Multiple functions can be added for the same frame and event
+ (string or function)
+* unitless - indicates that the event does not fire for a specific unit, so the event arguments won't be
+ matched to the frame unit(s). Events that do not start with UNIT_ or are not known to be unit events are
+ automatically considered unitless (boolean)
+--]]
+function frame_metatable.__index:RegisterEvent(event, func)
+ -- Block OnUpdate polled frames from registering events.
+ -- UNIT_PORTRAIT_UPDATE and UNIT_MODEL_CHANGED which are used for
+ -- portrait updates.
+ if(self.__eventless and event ~= 'UNIT_PORTRAIT_UPDATE' and event ~= 'UNIT_MODEL_CHANGED') then return end
+
+ argcheck(event, 2, 'string')
+ argcheck(func, 3, 'function')
+
+ local curev = self[event]
+ local kind = type(curev)
+ if(curev) then
+ if(kind == 'function' and curev ~= func) then
+ self[event] = setmetatable({curev, func}, event_metatable)
+ elseif(kind == 'table') then
+ for _, infunc in next, curev do
+ if(infunc == func) then return end
+ end
+
+ table.insert(curev, func)
+ end
+ else
+ self[event] = func
+
+ if(not self:GetScript('OnEvent')) then
+ self:SetScript('OnEvent', onEvent)
+ end
+
+ registerEvent(self, event)
+ end
+end
+
+--[[ Events: frame:UnregisterEvent(event, func)
+Used to remove a function from the event handler list for a game event.
+
+* self - the frame registered for the event
+* event - name of the registered event (string)
+* func - function to be removed from the list of event handlers. If this is the only handler for the given event, then
+ the frame will be unregistered for the event (function)
+--]]
+function frame_metatable.__index:UnregisterEvent(event, func)
+ argcheck(event, 2, 'string')
+
+ local cleanUp = false
+ local curev = self[event]
+ if(type(curev) == 'table' and func) then
+ for k, infunc in next, curev do
+ if(infunc == func) then
+ curev[k] = nil
+
+ break
+ end
+ end
+
+ if(not next(curev)) then
+ cleanUp = true
+ end
+ end
+
+ if(cleanUp or curev == func) then
+ self[event] = nil
+ if(self.unitEvents) then
+ self.unitEvents[event] = nil
+ end
+
+ unregisterEvent(self, event)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/factory.lua b/ElvUI/Libraries/oUF/factory.lua
new file mode 100644
index 0000000..59b73e9
--- /dev/null
+++ b/ElvUI/Libraries/oUF/factory.lua
@@ -0,0 +1,71 @@
+local parent, ns = ...
+local oUF = ns.oUF
+local Private = oUF.Private
+
+local argcheck = Private.argcheck
+
+local queue = {}
+local factory = CreateFrame('Frame')
+factory:SetScript('OnEvent', function(self, event, ...)
+ return self[event](self, event, ...)
+end)
+
+factory:RegisterEvent('PLAYER_LOGIN')
+factory.active = true
+
+function factory:PLAYER_LOGIN()
+ if(not self.active) then return end
+
+ for _, func in next, queue do
+ func(oUF)
+ end
+
+ -- Avoid creating dupes.
+ wipe(queue)
+end
+
+--[[ Factory: oUF:Factory(func)
+Used to call a function directly if the current character is logged in and the factory is active. Else the function is
+queued up to be executed at a later time (upon PLAYER_LOGIN by default).
+
+* self - the global oUF object
+* func - function to be executed or delayed (function)
+--]]
+function oUF:Factory(func)
+ argcheck(func, 2, 'function')
+
+ -- Call the function directly if we're active and logged in.
+ if(IsLoggedIn() and factory.active) then
+ return func(self)
+ else
+ table.insert(queue, func)
+ end
+end
+
+--[[ Factory: oUF:EnableFactory()
+Used to enable the factory.
+
+* self - the global oUF object
+--]]
+function oUF:EnableFactory()
+ factory.active = true
+end
+
+--[[ Factory: oUF:DisableFactory()
+Used to disable the factory.
+
+* self - the global oUF object
+--]]
+function oUF:DisableFactory()
+ factory.active = nil
+end
+
+--[[ Factory: oUF:RunFactoryQueue()
+Used to try to execute queued up functions. The current player must be logged in and the factory must be active for
+this to succeed.
+
+* self - the global oUF object
+--]]
+function oUF:RunFactoryQueue()
+ factory:PLAYER_LOGIN()
+end
diff --git a/ElvUI/Libraries/oUF/finalize.lua b/ElvUI/Libraries/oUF/finalize.lua
new file mode 100644
index 0000000..dec0bc1
--- /dev/null
+++ b/ElvUI/Libraries/oUF/finalize.lua
@@ -0,0 +1,4 @@
+local parent, ns = ...
+
+-- It's named Private for a reason!
+ns.oUF.Private = nil
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/init.lua b/ElvUI/Libraries/oUF/init.lua
new file mode 100644
index 0000000..dabbd5d
--- /dev/null
+++ b/ElvUI/Libraries/oUF/init.lua
@@ -0,0 +1,3 @@
+local parent, ns = ...
+ns.oUF = {}
+ns.oUF.Private = {}
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/oUF.xml b/ElvUI/Libraries/oUF/oUF.xml
new file mode 100644
index 0000000..a2a94a3
--- /dev/null
+++ b/ElvUI/Libraries/oUF/oUF.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/ouf.lua b/ElvUI/Libraries/oUF/ouf.lua
new file mode 100644
index 0000000..13a9967
--- /dev/null
+++ b/ElvUI/Libraries/oUF/ouf.lua
@@ -0,0 +1,808 @@
+local parent, ns = ...
+local global = GetAddOnMetadata(parent, 'X-oUF')
+local _VERSION = '@project-version@'
+if(_VERSION:find('project%-version')) then
+ _VERSION = 'devel'
+end
+
+local oUF = ns.oUF
+local Private = oUF.Private
+
+local argcheck = Private.argcheck
+local error = Private.error
+local print = Private.print
+local unitExists = Private.unitExists
+
+local styles, style = {}
+local callback, objects, headers = {}, {}, {}
+
+local elements = {}
+local activeElements = {}
+
+-- updating of "invalid" units.
+local function enableTargetUpdate(object)
+ object.onUpdateFrequency = object.onUpdateFrequency or .5
+ object.__eventless = true
+
+ local total = 0
+ object:SetScript('OnUpdate', function(self, elapsed)
+ if(not self.unit) then
+ return
+ elseif(total > self.onUpdateFrequency) then
+ self:UpdateAllElements('OnUpdate')
+ total = 0
+ end
+
+ total = total + elapsed
+ end)
+end
+Private.enableTargetUpdate = enableTargetUpdate
+
+local function updateActiveUnit(self, event, unit)
+ -- Calculate units to work with
+ local realUnit, modUnit = SecureButton_GetUnit(self), SecureButton_GetModifiedUnit(self)
+
+ -- _GetUnit() doesn't rewrite playerpet -> pet like _GetModifiedUnit does.
+ if(realUnit == 'playerpet') then
+ realUnit = 'pet'
+ elseif(realUnit == 'playertarget') then
+ realUnit = 'target'
+ end
+
+ if(modUnit == 'pet' and realUnit ~= 'pet') then
+ modUnit = 'vehicle'
+ end
+
+ if(not UnitExists(modUnit)) then
+ if(modUnit ~= realUnit) then
+ modUnit = realUnit
+ else
+ return
+ end
+ end
+
+ -- Change the active unit and run a full update.
+ if(Private.UpdateUnits(self, modUnit, realUnit)) then
+ self:UpdateAllElements('RefreshUnit')
+
+ return true
+ end
+end
+
+local function iterateChildren(...)
+ for i = 1, select('#', ...) do
+ local obj = select(i, ...)
+
+ if(type(obj) == 'table' and obj.isChild) then
+ updateActiveUnit(obj, 'iterateChildren')
+ end
+ end
+end
+
+local function onAttributeChanged(self, name, value)
+ if(name == 'unit' and value) then
+ if(self.hasChildren) then
+ iterateChildren(self:GetChildren())
+ end
+
+ if(not self.onlyProcessChildren) then
+ updateActiveUnit(self, 'OnAttributeChanged')
+ end
+--[[
+ if(self.unit and self.unit == value) then
+ return
+ else
+ if(self.hasChildren) then
+ iterateChildren(self:GetChildren())
+ end
+ end
+]]
+ end
+end
+
+local frame_metatable = {
+ __index = CreateFrame('Button')
+}
+Private.frame_metatable = frame_metatable
+
+for k, v in next, {
+ UpdateElement = function(self, name)
+ local unit = self.unit
+ if(not unit or not UnitExists(unit)) then return end
+
+ local element = elements[name]
+ if(not element or not self:IsElementEnabled(name) or not activeElements[self]) then return end
+ if(element.update) then
+ element.update(self, 'OnShow', unit)
+ end
+ end,
+
+ --[[ frame:EnableElement(name, unit)
+ Used to activate an element for the given unit frame.
+
+ * self - unit frame for which the element should be enabled
+ * name - name of the element to be enabled (string)
+ * unit - unit to be passed to the element's Enable function. Defaults to the frame's unit (string?)
+ --]]
+ EnableElement = function(self, name, unit)
+ argcheck(name, 2, 'string')
+ argcheck(unit, 3, 'string', 'nil')
+
+ local element = elements[name]
+ if(not element or self:IsElementEnabled(name)) then return end
+
+ if(element.enable(self, unit or self.unit)) then
+ activeElements[self][name] = true
+
+ if(element.update) then
+ table.insert(self.__elements, element.update)
+ end
+ end
+ end,
+
+ --[[ frame:DisableElement(name)
+ Used to deactivate an element for the given unit frame.
+
+ * self - unit frame for which the element should be disabled
+ * name - name of the element to be disabled (string)
+ --]]
+ DisableElement = function(self, name)
+ argcheck(name, 2, 'string')
+
+ local enabled = self:IsElementEnabled(name)
+ if(not enabled) then return end
+
+ local update = elements[name].update
+ for k, func in next, self.__elements do
+ if(func == update) then
+ table.remove(self.__elements, k)
+ break
+ end
+ end
+
+ activeElements[self][name] = nil
+
+ -- We need to run a new update cycle in-case we knocked ourself out of sync.
+ -- The main reason we do this is to make sure the full update is completed
+ -- if an element for some reason removes itself _during_ the update
+ -- progress.
+ self:UpdateAllElements('DisableElement')
+
+ return elements[name].disable(self)
+ end,
+
+ --[[ frame:IsElementEnabled(name)
+ Used to check if an element is enabled on the given frame.
+
+ * self - unit frame
+ * name - name of the element (string)
+ --]]
+ IsElementEnabled = function(self, name)
+ argcheck(name, 2, 'string')
+
+ local element = elements[name]
+ if(not element) then return end
+
+ local active = activeElements[self]
+ return active and active[name]
+ end,
+
+ --[[ frame:Enable(asState)
+ Used to toggle the visibility of a unit frame based on the existence of its unit. This is a reference to
+ `RegisterUnitWatch`.
+
+ * self - unit frame
+ * asState - if true, the frame's "state-unitexists" attribute will be set to a boolean value denoting whether the
+ unit exists; if false, the frame will be shown if its unit exists, and hidden if it does not (boolean)
+ --]]
+ Enable = RegisterUnitWatch,
+ --[[ frame:Disable()
+ Used to UnregisterUnitWatch for the given frame and hide it.
+
+ * self - unit frame
+ --]]
+ Disable = function(self)
+ UnregisterUnitWatch(self)
+ self:Hide()
+ end,
+ --[[ frame:IsEnabled()
+ Used to check if a unit frame is registered with the unit existence monitor. This is a reference to
+ `UnitWatchRegistered`.
+
+ * self - unit frame
+ --]]
+ IsEnabled = UnitWatchRegistered,
+ --[[ frame:UpdateAllElements(event)
+ Used to update all enabled elements on the given frame.
+
+ * self - unit frame
+ * event - event name to pass to the elements' update functions (string)
+ --]]
+ UpdateAllElements = function(self, event)
+ local unit = self.unit
+ if(not unitExists(unit)) then return end
+
+ assert(type(event) == 'string', "Invalid argument 'event' in UpdateAllElements.")
+
+ if(self.PreUpdate) then
+ --[[ Callback: frame:PreUpdate(event)
+ Fired before the frame is updated.
+
+ * self - the unit frame
+ * event - the event triggering the update (string)
+ --]]
+ self:PreUpdate(event)
+ end
+
+ for _, func in next, self.__elements do
+ func(self, event, unit)
+ end
+
+ if(self.PostUpdate) then
+ --[[ Callback: frame:PostUpdate(event)
+ Fired after the frame is updated.
+
+ * self - the unit frame
+ * event - the event triggering the update (string)
+ --]]
+ self:PostUpdate(event)
+ end
+ end,
+} do
+ frame_metatable.__index[k] = v
+end
+
+local secureDropdown
+local function InitializeSecureMenu(self)
+ local unit = self.unit
+ if(not unit) then return end
+
+ local unitType = string.match(unit, '^([a-z]+)[0-9]+$') or unit
+
+ local menu
+ if(unitType == 'party') then
+ menu = 'PARTY'
+ elseif(unitType == 'boss') then
+ menu = 'BOSS'
+ elseif(unitType == 'focus') then
+ menu = 'FOCUS'
+ elseif(unitType == 'arenapet' or unitType == 'arena') then
+ menu = 'ARENAENEMY'
+ elseif(UnitIsUnit(unit, 'player')) then
+ menu = 'SELF'
+ elseif(UnitIsUnit(unit, 'vehicle')) then
+ menu = 'VEHICLE'
+ elseif(UnitIsUnit(unit, 'pet')) then
+ menu = 'PET'
+ elseif(UnitIsPlayer(unit)) then
+ if(UnitInRaid(unit)) then
+ menu = 'RAID_PLAYER'
+ elseif(UnitInParty(unit)) then
+ menu = 'PARTY'
+ else
+ menu = 'PLAYER'
+ end
+ elseif(UnitIsUnit(unit, 'target')) then
+ menu = 'TARGET'
+ end
+
+ if(menu) then
+ UnitPopup_ShowMenu(self, menu, unit)
+ end
+end
+
+local function togglemenu(self, unit)
+ if(not secureDropdown) then
+ secureDropdown = CreateFrame('Frame', 'SecureTemplatesDropdown', nil, 'UIDropDownMenuTemplate')
+ secureDropdown:SetID(1)
+
+ table.insert(UnitPopupFrames, secureDropdown:GetName())
+ UIDropDownMenu_Initialize(secureDropdown, InitializeSecureMenu, 'MENU')
+ end
+
+ if(secureDropdown.openedFor and secureDropdown.openedFor ~= self) then
+ CloseDropDownMenus()
+ end
+
+ secureDropdown.unit = string.lower(unit)
+ secureDropdown.openedFor = self
+
+ ToggleDropDownMenu(1, nil, secureDropdown, 'cursor')
+end
+
+local function onShow(self)
+ if(not updateActiveUnit(self, 'OnShow')) then
+ return self:UpdateAllElements('OnShow')
+ end
+end
+
+local function updatePet(self, event, unit)
+ local petUnit
+ if(unit == 'target') then
+ return
+ elseif(unit == 'player') then
+ petUnit = 'pet'
+ else
+ -- Convert raid26 -> raidpet26
+ petUnit = unit:gsub('^(%a+)(%d+)', '%1pet%2')
+ end
+
+ if(self.unit ~= petUnit) then return end
+ if(not updateActiveUnit(self, event)) then
+ return self:UpdateAllElements(event)
+ end
+end
+
+local function updateRaid(self, event)
+ local unitGUID = UnitGUID(self.unit)
+ if(unitGUID and unitGUID ~= self.unitGUID) then
+ self.unitGUID = unitGUID
+
+ self:UpdateAllElements(event)
+ end
+end
+
+local function initObject(unit, style, styleFunc, header, ...)
+ local num = select('#', ...)
+ for i = 1, num do
+ local object = select(i, ...)
+ local objectUnit = object.guessUnit or unit
+ local suffix = object:GetAttribute('unitsuffix')
+
+ object.__elements = {}
+ object.style = style
+ object = setmetatable(object, frame_metatable)
+
+ -- Expose the frame through oUF.objects.
+ table.insert(objects, object)
+
+ -- We have to force update the frames when PEW fires.
+ object:RegisterEvent('PLAYER_ENTERING_WORLD', object.UpdateAllElements)
+
+ -- Handle the case where someone has modified the unitsuffix attribute in
+ -- oUF-initialConfigFunction.
+ if(suffix and objectUnit and not objectUnit:match(suffix)) then
+ objectUnit = objectUnit .. suffix
+ end
+
+ if(not (suffix == 'target' or objectUnit and objectUnit:match('target'))) then
+ object:RegisterEvent('UNIT_ENTERING_VEHICLE', updateActiveUnit)
+ object:RegisterEvent('UNIT_ENTERED_VEHICLE', updateActiveUnit)
+ object:RegisterEvent('UNIT_EXITING_VEHICLE', updateActiveUnit)
+ object:RegisterEvent('PLAYER_ENTERING_WORLD', updateActiveUnit)
+
+ -- We don't need to register UNIT_PET for the player unit. We register it
+ -- mainly because UNIT_EXITED_VEHICLE and UNIT_ENTERED_VEHICLE doesn't always
+ -- have pet information when they fire for party and raid units.
+ if(objectUnit ~= 'player') then
+ object:RegisterEvent('UNIT_PET', updatePet, true)
+ end
+ end
+
+ if(not header) then
+ -- No header means it's a frame created through :Spawn().
+ object.menu = togglemenu
+ object:SetAttribute('*type1', 'target')
+ object:SetAttribute('*type2', 'menu')
+
+ -- No need to enable this for *target frames.
+ if(not (unit:match('target') or suffix == 'target')) then
+ object:SetAttribute('toggleForVehicle', true)
+ end
+
+ -- Other boss and target units are handled by :HandleUnit().
+ if(suffix == 'target') then
+ enableTargetUpdate(object)
+ else
+ oUF:HandleUnit(object)
+ end
+ else
+ -- update the frame when its prev unit is replaced with a new one
+ -- updateRaid relies on UnitGUID to detect the unit change
+ object:RegisterEvent('RAID_ROSTER_UPDATE', updateRaid)
+
+ if(num > 1) then
+ if(object:GetParent() == header) then
+ object.hasChildren = true
+ else
+ object.isChild = true
+ end
+ end
+
+ if(suffix == 'target') then
+ enableTargetUpdate(object)
+ end
+ end
+
+ activeElements[object] = {} -- ElvUI: styleFunc on headers break before this is set when they try to enable elements before it's set.
+
+ Private.UpdateUnits(object, objectUnit)
+
+ styleFunc(object, objectUnit, not header)
+
+ object:HookScript('OnAttributeChanged', onAttributeChanged)
+ object:SetScript('OnShow', onShow)
+
+ for element in next, elements do
+ object:EnableElement(element, objectUnit)
+ end
+
+ for _, func in next, callback do
+ func(object)
+ end
+
+ -- ElvUI block
+ if object.PostCreate then
+ object:PostCreate(object)
+ end
+ -- end block
+
+ -- Make Clique kinda happy
+ _G.ClickCastFrames = ClickCastFrames or {}
+ ClickCastFrames[object] = true
+ end
+end
+
+local function walkObject(object, unit)
+ local parent = object:GetParent()
+ local style = parent.style or style
+ local styleFunc = styles[style]
+
+ local header = parent.headerType and parent
+
+ -- Check if we should leave the main frame blank.
+ if(object.onlyProcessChildren) then
+ object.hasChildren = true
+ object:HookScript('OnAttributeChanged', onAttributeChanged)
+ return initObject(unit, style, styleFunc, header, object:GetChildren())
+ end
+
+ return initObject(unit, style, styleFunc, header, object, object:GetChildren())
+end
+
+--[[ oUF:RegisterInitCallback(func)
+Used to add a function to a table to be executed upon unit frame/header initialization.
+
+* self - the global oUF object
+* func - function to be added
+--]]
+function oUF:RegisterInitCallback(func)
+ table.insert(callback, func)
+end
+
+--[[ oUF:RegisterMetaFunction(name, func)
+Used to make a (table of) function(s) available to all unit frames.
+
+* self - the global oUF object
+* name - unique name of the function (string)
+* func - function or a table of functions (function or table)
+--]]
+function oUF:RegisterMetaFunction(name, func)
+ argcheck(name, 2, 'string')
+ argcheck(func, 3, 'function', 'table')
+
+ if(frame_metatable.__index[name]) then
+ return
+ end
+
+ frame_metatable.__index[name] = func
+end
+
+--[[ oUF:RegisterStyle(name, func)
+Used to register a style with oUF. This will also set the active style if it hasn't been set yet.
+
+* self - the global oUF object
+* name - name of the style
+* func - function(s) defining the style (function or table)
+--]]
+function oUF:RegisterStyle(name, func)
+ argcheck(name, 2, 'string')
+ argcheck(func, 3, 'function', 'table')
+
+ if(styles[name]) then return error('Style [%s] already registered.', name) end
+ if(not style) then style = name end
+
+ styles[name] = func
+end
+
+--[[ oUF:SetActiveStyle(name)
+Used to set the active style.
+
+* self - the global oUF object
+* name - name of the style (string)
+--]]
+function oUF:SetActiveStyle(name)
+ argcheck(name, 2, 'string')
+ if(not styles[name]) then return error('Style [%s] does not exist.', name) end
+
+ style = name
+end
+
+do
+ local function iter(_, n)
+ -- don't expose the style functions.
+ return (next(styles, n))
+ end
+
+ --[[ oUF:IterateStyles()
+ Returns an iterator over all registered styles.
+
+ * self - the global oUF object
+ --]]
+ function oUF.IterateStyles()
+ return iter, nil, nil
+ end
+end
+
+local getCondition
+do
+ local conditions = {
+ raid40 = '[@raid26,exists] show;',
+ raid25 = '[@raid11,exists] show;',
+ raid10 = '[@raid6,exists] show;',
+ raid = '[group:raid] show;',
+ party = '[group:party,nogroup:raid] show;',
+ solo = '[@player,exists,nogroup:party] show;',
+ }
+
+ function getCondition(...)
+ local cond = ''
+
+ for i = 1, select('#', ...) do
+ local short = select(i, ...)
+
+ local condition = conditions[short]
+ if(condition) then
+ cond = cond .. condition
+ end
+ end
+
+ return cond .. 'hide'
+ end
+end
+
+local function generateName(unit, ...)
+ local name = 'oUF_' .. style:gsub('^oUF_?', ''):gsub('[^%a%d_]+', '')
+
+ local raid, party, groupFilter, unitsuffix
+ for i = 1, select('#', ...), 2 do
+ local att, val = select(i, ...)
+ if(att == 'showRaid') then
+ raid = val ~= false and val ~= nil
+ elseif(att == 'showParty') then
+ party = val ~= false and val ~= nil
+ elseif(att == 'groupFilter') then
+ groupFilter = val
+ end
+ end
+
+ local append
+ if(raid) then
+ if(groupFilter) then
+ if(type(groupFilter) == 'number' and groupFilter > 0) then
+ append = 'Raid' .. groupFilter
+ elseif(groupFilter:match('MAINTANK')) then
+ append = 'MainTank'
+ elseif(groupFilter:match('MAINASSIST')) then
+ append = 'MainAssist'
+ else
+ local _, count = groupFilter:gsub(',', '')
+ if(count == 0) then
+ append = 'Raid' .. groupFilter
+ else
+ append = 'Raid'
+ end
+ end
+ else
+ append = 'Raid'
+ end
+ elseif(party) then
+ append = 'Party'
+ elseif(unit) then
+ append = unit:gsub('^%l', string.upper)
+ end
+
+ if(append) then
+ name = name .. append
+ end
+
+ local base = name
+ local i = 2
+ while(_G[name]) do
+ name = base .. i
+ i = i + 1
+ end
+
+ return name
+end
+
+do
+ local function styleProxy(self, frame, ...)
+ return walkObject(_G[frame])
+ end
+
+ -- There has to be an easier way to do this.
+ local initialConfigFunction = function(self)
+ local header = self:GetParent()
+ for i = 1, select('#', self), 1 do
+ local frame = select(i, self)
+ local unit
+ -- There's no need to do anything on frames with onlyProcessChildren
+ if(not frame.onlyProcessChildren) then
+ -- Attempt to guess what the header is set to spawn.
+ local groupFilter = header:GetAttribute('groupFilter')
+
+ if(type(groupFilter) == 'string' and groupFilter:match('MAIN[AT]')) then
+ local role = groupFilter:match('MAIN([AT])')
+ if(role == 'T') then
+ unit = 'maintank'
+ else
+ unit = 'mainassist'
+ end
+ elseif(header:GetAttribute('showRaid')) then
+ unit = 'raid'
+ elseif(header:GetAttribute('showParty')) then
+ unit = 'party'
+ end
+
+ local headerType = header.headerType
+ local suffix = frame:GetAttribute('unitsuffix')
+ if(unit and suffix) then
+ if(headerType == 'pet' and suffix == 'target') then
+ unit = unit .. headerType .. suffix
+ else
+ unit = unit .. suffix
+ end
+ elseif(unit and headerType == 'pet') then
+ unit = unit .. headerType
+ end
+
+ frame.menu = togglemenu
+ frame:SetAttribute('*type1', 'target')
+ frame:SetAttribute('*type2', 'menu')
+ frame:SetAttribute('toggleForVehicle', true)
+ frame.guessUnit = unit
+ end
+ end
+
+ header:styleFunction(self:GetName())
+ end
+
+ --[[ oUF:SpawnHeader(overrideName, template, visibility, ...)
+ Used to create a group header and apply the currently active style to it.
+
+ * self - the global oUF object
+ * overrideName - unique global name to be used for the header. Defaults to an auto-generated name based on the name
+ of the active style and other arguments passed to `:SpawnHeader` (string?)
+ * template - name of a template to be used for creating the header. Defaults to `'SecureGroupHeaderTemplate'`
+ (string?)
+ * visibility - macro conditional(s) which define when to display the header (string).
+ * ... - further argument pairs. Consult [Group Headers](http://wowprogramming.com/docs/secure_template/Group_Headers)
+ for possible values.
+
+ In addition to the standard group headers, oUF implements some of its own attributes. These can be supplied by the
+ layout, but are optional.
+
+ * oUF-initialConfigFunction - can contain code that will be securely run at the end of the initial secure
+ configuration (string?)
+ * oUF-onlyProcessChildren - can be used to force headers to only process children (boolean?)
+ --]]
+ function oUF:SpawnHeader(overrideName, template, visibility, ...)
+ if(not style) then return error('Unable to create frame. No styles have been registered.') end
+
+ template = (template or 'SecureGroupHeaderTemplate')
+
+ local isPetHeader = template:match('PetHeader')
+ local name = overrideName or generateName(nil, ...)
+ local header = CreateFrame('Frame', name, UIParent, template)
+ header:Hide()
+
+ header:SetAttribute('template', 'oUF_ClickCastUnitTemplate')
+ for i = 1, select('#', ...), 2 do
+ local att, val = select(i, ...)
+ if(not att) then break end
+ header:SetAttribute(att, val)
+ end
+
+ header.style = style
+ header.styleFunction = styleProxy
+ header.visibility = visibility
+
+ -- Expose the header through oUF.headers.
+ table.insert(headers, header)
+
+ header.initialConfigFunction = initialConfigFunction
+ header.headerType = isPetHeader and 'pet' or 'group'
+
+ if(header:GetAttribute('showParty')) then
+ self:DisableBlizzard('party')
+ end
+
+ if(visibility) then
+ local type, list = string.split(' ', visibility, 2)
+ if(list and type == 'custom') then
+ RegisterStateDriver(header, 'visibility', list)
+ header.visibility = list
+ else
+ local condition = getCondition(string.split(',', visibility))
+ RegisterStateDriver(header, 'visibility', condition)
+ header.visibility = condition
+ end
+ end
+
+ return header
+ end
+end
+
+--[[ oUF:Spawn(unit, overrideName)
+Used to create a single unit frame and apply the currently active style to it.
+
+* self - the global oUF object
+* unit - the frame's unit (string)
+* overrideName - unique global name to use for the unit frame. Defaults to an auto-generated name based on the unit
+ (string?)
+--]]
+function oUF:Spawn(unit, overrideName)
+ argcheck(unit, 2, 'string')
+ if(not style) then return error('Unable to create frame. No styles have been registered.') end
+
+ unit = unit:lower()
+
+ local name = overrideName or generateName(unit)
+ local object = CreateFrame('Button', name, UIParent, 'SecureUnitButtonTemplate')
+ Private.UpdateUnits(object, unit)
+
+ self:DisableBlizzard(unit)
+ walkObject(object, unit)
+
+ object:SetAttribute('unit', unit)
+ RegisterUnitWatch(object)
+
+ return object
+end
+
+--[[ oUF:AddElement(name, update, enable, disable)
+Used to register an element with oUF.
+
+* self - the global oUF object
+* name - unique name of the element (string)
+* update - used to update the element (function?)
+* enable - used to enable the element for a given unit frame and unit (function?)
+* disable - used to disable the element for a given unit frame (function?)
+--]]
+function oUF:AddElement(name, update, enable, disable)
+ argcheck(name, 2, 'string')
+ argcheck(update, 3, 'function', 'nil')
+ argcheck(enable, 4, 'function', 'nil')
+ argcheck(disable, 5, 'function', 'nil')
+
+ if(elements[name]) then return error('Element [%s] is already registered.', name) end
+
+ elements[name] = {
+ update = update;
+ enable = enable;
+ disable = disable;
+ }
+end
+
+oUF.version = _VERSION
+--[[ oUF.objects
+Array containing all unit frames created by `oUF:Spawn`.
+--]]
+oUF.objects = objects
+--[[ oUF.headers
+Array containing all group headers created by `oUF:SpawnHeader`.
+--]]
+oUF.headers = headers
+
+if(global) then
+ if(parent ~= 'oUF' and global == 'oUF') then
+ error('%s is doing it wrong and setting its global to "oUF".', parent)
+ elseif(_G[global]) then
+ error('%s is setting its global to an existing name "%s".', parent, global)
+ else
+ _G[global] = oUF
+ end
+end
+
+oUF.herocolor = {0.0, 1.0, 0.0}
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/private.lua b/ElvUI/Libraries/oUF/private.lua
new file mode 100644
index 0000000..ee4e82c
--- /dev/null
+++ b/ElvUI/Libraries/oUF/private.lua
@@ -0,0 +1,26 @@
+local parent, ns = ...
+local Private = ns.oUF.Private
+
+function Private.argcheck(value, num, ...)
+ assert(type(num) == 'number', "Bad argument #2 to 'argcheck' (number expected, got " .. type(num) .. ')')
+
+ for i = 1, select('#', ...) do
+ if(type(value) == select(i, ...)) then return end
+ end
+
+ local types = strjoin(', ', ...)
+ local name = debugstack(2,2,0):match(": in function [`<](.-)['>]")
+ error(string.format("Bad argument #%d to '%s' (%s expected, got %s)", num, name, types, type(value)), 3)
+end
+
+function Private.print(...)
+ print('|cff33ff99oUF:|r', ...)
+end
+
+function Private.error(...)
+ Private.print('|cffff0000Error:|r ' .. string.format(...))
+end
+
+function Private.unitExists(unit)
+ return unit and UnitExists(unit)
+end
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF/units.lua b/ElvUI/Libraries/oUF/units.lua
new file mode 100644
index 0000000..8dad10e
--- /dev/null
+++ b/ElvUI/Libraries/oUF/units.lua
@@ -0,0 +1,19 @@
+local parent, ns = ...
+local oUF = ns.oUF
+local Private = oUF.Private
+
+local enableTargetUpdate = Private.enableTargetUpdate
+
+-- Handles unit specific actions.
+function oUF:HandleUnit(object, unit)
+ local unit = object.unit or unit
+ if(unit == 'target') then
+ object:RegisterEvent('PLAYER_TARGET_CHANGED', object.UpdateAllElements)
+ elseif(unit == 'mouseover') then
+ object:RegisterEvent('UPDATE_MOUSEOVER_UNIT', object.UpdateAllElements)
+ elseif(unit == 'focus') then
+ object:RegisterEvent('PLAYER_FOCUS_CHANGED', object.UpdateAllElements)
+ elseif(unit:match('%w+target') or unit:match('boss%d?$')) then
+ enableTargetUpdate(object)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_AuraBars/oUF_AuraBars.lua b/ElvUI/Libraries/oUF_Plugins/oUF_AuraBars/oUF_AuraBars.lua
new file mode 100644
index 0000000..12e6b86
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_AuraBars/oUF_AuraBars.lua
@@ -0,0 +1,381 @@
+local _, ns = ...
+local oUF = oUF or ns.oUF
+assert(oUF, "oUF_AuraBars was unable to locate oUF install.")
+
+local type = type
+local unpack = unpack
+local floor, huge, min = math.floor, math.huge, math.min
+local format = string.format
+local tsort, tremove = table.sort, table.remove
+
+local CreateFrame = CreateFrame
+local GetTime = GetTime
+local UnitAura = UnitAura
+local UnitIsFriend = UnitIsFriend
+
+local DAY, HOUR, MINUTE = 86400, 3600, 60
+local function formatTime(s)
+ if s < MINUTE then
+ return format("%.1fs", s)
+ elseif s < HOUR then
+ return format("%dm %ds", s / 60 % 60, s % 60)
+ elseif s < DAY then
+ return format("%dh %dm", s / HOUR, s / 60 % 60)
+ else
+ return format("%dd %dh", s/DAY, (s / HOUR) - (floor(s / DAY) * 24))
+ end
+end
+
+local function UpdateTooltip(self)
+ GameTooltip:SetUnitAura(self.__unit, self:GetParent().aura.name, self:GetParent().aura.rank, self:GetParent().aura.filter)
+end
+
+local function OnEnter(self)
+ if not self:IsVisible() then return end
+
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT")
+ self:UpdateTooltip()
+end
+
+local function OnLeave(self)
+ GameTooltip:Hide()
+end
+
+local function SetAnchors(self)
+ local bars = self.bars
+
+ for i = 1, #bars do
+ local frame = bars[i]
+ local anchor = frame.anchor
+
+ frame:Height(self.auraBarHeight or 20)
+ frame:Width((self.auraBarWidth or self:GetWidth()) - (frame:GetHeight() + (self.gap or 0)))
+ frame.statusBar.iconHolder:Size(frame:GetHeight())
+
+ frame:ClearAllPoints()
+ if self.down then
+ if self == anchor then -- Root frame so indent for icon
+ frame:SetPoint("TOPLEFT", anchor, "TOPLEFT", (frame:GetHeight() + (self.gap or 0)), -1)
+ else
+ frame:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, (-self.spacing or 0))
+ end
+ else
+ if self == anchor then -- Root frame so indent for icon
+ frame:SetPoint("BOTTOMLEFT", anchor, "BOTTOMLEFT", (frame:GetHeight() + (self.gap or 0)), 1)
+ else
+ frame:SetPoint("BOTTOMLEFT", anchor, "TOPLEFT", 0, (self.spacing or 0))
+ end
+ end
+ end
+end
+
+local function CreateAuraBar(self, anchor)
+ local element = self.AuraBars
+
+ local frame = CreateFrame("Frame", nil, element)
+ frame:Height(element.auraBarHeight or 20)
+ frame:Width((element.auraBarWidth or element:GetWidth()) - (frame:GetHeight() + (element.gap or 0)))
+ frame.anchor = anchor
+
+ -- the main bar
+ local statusBar = CreateFrame("StatusBar", nil, frame)
+ statusBar:SetStatusBarTexture(element.auraBarTexture or [[Interface\TargetingFrame\UI-StatusBar]])
+ statusBar:SetAlpha(element.fgalpha or 1)
+ statusBar:SetAllPoints(frame)
+
+ frame.statusBar = statusBar
+
+ if element.down then
+ if element == anchor then -- Root frame so indent for icon
+ frame:SetPoint("TOPLEFT", anchor, "TOPLEFT", (frame:GetHeight() + (element.gap or 0)), -1)
+ else
+ frame:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, (-element.spacing or 0))
+ end
+ else
+ if element == anchor then -- Root frame so indent for icon
+ frame:SetPoint("BOTTOMLEFT", anchor, "BOTTOMLEFT", (frame:GetHeight() + (element.gap or 0)), 1)
+ else
+ frame:SetPoint("BOTTOMLEFT", anchor, "TOPLEFT", 0, (element.spacing or 0))
+ end
+ end
+
+ local spark = statusBar:CreateTexture(nil, "OVERLAY", nil)
+ spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
+ spark:Width(12)
+ spark:SetBlendMode("ADD")
+ spark:SetPoint("CENTER", statusBar:GetStatusBarTexture(), "RIGHT")
+ statusBar.spark = spark
+
+ statusBar.iconHolder = CreateFrame("Button", nil, statusBar)
+ statusBar.iconHolder:Size(frame:GetHeight())
+ statusBar.iconHolder:SetPoint("BOTTOMRIGHT", frame, "BOTTOMLEFT", -element.gap, 0)
+ statusBar.iconHolder.__unit = self.unit
+ statusBar.iconHolder:SetScript("OnEnter", OnEnter)
+ statusBar.iconHolder:SetScript("OnLeave", OnLeave)
+ statusBar.iconHolder.UpdateTooltip = UpdateTooltip
+
+ statusBar.icon = statusBar.iconHolder:CreateTexture(nil, "BACKGROUND")
+ statusBar.icon:SetTexCoord(unpack(ElvUI[1].TexCoords))
+ statusBar.icon:SetAllPoints()
+
+ statusBar.spelltime = statusBar:CreateFontString(nil, "ARTWORK")
+ if element.spellTimeObject then
+ statusBar.spelltime:SetFontObject(element.spellTimeObject)
+ else
+ statusBar.spelltime:SetFont(element.spellTimeFont or [[Fonts\FRIZQT__.TTF]], element.spellTimeSize or 10)
+ end
+ statusBar.spelltime:SetTextColor(1, 1, 1)
+ statusBar.spelltime:SetJustifyH("RIGHT")
+ statusBar.spelltime:SetJustifyV("CENTER")
+ statusBar.spelltime:SetPoint("RIGHT")
+
+ statusBar.spellname = statusBar:CreateFontString(nil, "ARTWORK")
+ if element.spellNameObject then
+ statusBar.spellname:SetFontObject(element.spellNameObject)
+ else
+ statusBar.spellname:SetFont(element.spellNameFont or [[Fonts\FRIZQT__.TTF]], element.spellNameSize or 10)
+ end
+ statusBar.spellname:SetTextColor(1, 1, 1)
+ statusBar.spellname:SetJustifyH("LEFT")
+ statusBar.spellname:SetJustifyV("CENTER")
+ statusBar.spellname:SetPoint("LEFT")
+ statusBar.spellname:SetPoint("RIGHT", statusBar.spelltime, "LEFT")
+
+ if element.PostCreateBar then
+ element.PostCreateBar(frame)
+ end
+
+ return frame
+end
+
+local function UpdateBars(element)
+ local bars = element.bars
+ local currentTime = GetTime()
+
+ for i = 1, #bars do
+ local frame = bars[i]
+ if not frame:IsVisible() then break end
+
+ local bar = frame.statusBar
+
+ if bar.aura.noTime then
+ bar.spelltime:SetText()
+ bar.spark:Hide()
+ else
+ local timeleft = bar.aura.expirationTime - currentTime
+ bar:SetValue(timeleft)
+ bar.spelltime:SetText(formatTime(timeleft))
+
+ if element.spark == true then
+ if element.scaleTime and ((element.scaleTime <= 0) or (element.scaleTime > 0 and timeleft < element.scaleTime)) then
+ bar.spark:Show()
+ else
+ bar.spark:Hide()
+ end
+ end
+ end
+ end
+end
+
+local function DefaultFilter(self, unit, name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate)
+ if unitCaster == "player" and not shouldConsolidate then
+ return true
+ end
+end
+
+local function sortByTime(a, b)
+ local compa = a.noTime and huge or a.expirationTime
+ local compb = b.noTime and huge or b.expirationTime
+ return compa > compb
+end
+
+local function Update(self, event, unit)
+ if self.unit ~= unit then return end
+
+ local element = self.AuraBars
+ local helpOrHarm
+ local isFriend = UnitIsFriend("player", unit) == 1 and true or false
+
+ if element.friendlyAuraType and element.enemyAuraType then
+ if isFriend then
+ helpOrHarm = element.friendlyAuraType
+ else
+ helpOrHarm = element.enemyAuraType
+ end
+ else
+ helpOrHarm = isFriend and "HELPFUL" or "HARMFUL"
+ end
+
+ -- Create a table of auras to display
+ local auras = {}
+ local lastAuraIndex = 0
+
+ if element.forceShow then
+ local spellID = 47540
+ local name, rank, icon = GetSpellInfo(spellID)
+ local count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate = 5, "Magic", 0, 0, "player", nil, nil
+
+ for i = 1, element.maxBars do
+ lastAuraIndex = lastAuraIndex + 1
+ auras[lastAuraIndex] = {}
+ auras[lastAuraIndex].spellID = spellID
+ auras[lastAuraIndex].name = name
+ auras[lastAuraIndex].rank = rank
+ auras[lastAuraIndex].icon = icon
+ auras[lastAuraIndex].count = count
+ auras[lastAuraIndex].debuffType = debuffType
+ auras[lastAuraIndex].duration = duration
+ auras[lastAuraIndex].expirationTime = expirationTime
+ auras[lastAuraIndex].unitCaster = unitCaster
+ auras[lastAuraIndex].isStealable = isStealable
+ auras[lastAuraIndex].noTime = (duration == 0 and expirationTime == 0)
+ auras[lastAuraIndex].filter = helpOrHarm
+ auras[lastAuraIndex].shouldConsolidate = shouldConsolidate
+ end
+ else
+ local i = 0
+ while lastAuraIndex <= element.maxBars do
+ i = i + 1
+
+ local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellID = UnitAura(unit, i, helpOrHarm)
+ if not name then break end
+
+ if (element.filter or DefaultFilter)(self, unit, name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellID) then
+ lastAuraIndex = lastAuraIndex + 1
+ auras[lastAuraIndex] = {}
+ auras[lastAuraIndex].spellID = spellID
+ auras[lastAuraIndex].name = name
+ auras[lastAuraIndex].rank = rank
+ auras[lastAuraIndex].icon = icon
+ auras[lastAuraIndex].count = count
+ auras[lastAuraIndex].debuffType = debuffType
+ auras[lastAuraIndex].duration = duration
+ auras[lastAuraIndex].expirationTime = expirationTime
+ auras[lastAuraIndex].unitCaster = unitCaster
+ auras[lastAuraIndex].isStealable = isStealable
+ auras[lastAuraIndex].noTime = (duration == 0 and expirationTime == 0)
+ auras[lastAuraIndex].filter = helpOrHarm
+ auras[lastAuraIndex].shouldConsolidate = shouldConsolidate
+ end
+ end
+ end
+
+ if element.sort and not element.forceShow then
+ tsort(auras, type(element.sort) == "function" and element.sort or sortByTime)
+ end
+
+ -- Show and configure bars for buffs/debuffs.
+ local bars = element.bars
+ if lastAuraIndex == 0 then
+ element:Height(1)
+ end
+
+ local currentTime = GetTime()
+
+ for i = 1, lastAuraIndex do
+ if element:GetWidth() == 0 then break end
+
+ local aura = auras[i]
+ local frame = bars[i]
+
+ if not frame then
+ frame = CreateAuraBar(self, i == 1 and element or bars[i - 1])
+ bars[i] = frame
+ end
+
+ if i == lastAuraIndex then
+ if element.down then
+ element:Height(element:GetTop() - frame:GetBottom())
+ elseif frame:GetTop() and element:GetBottom() then
+ element:Height(frame:GetTop() - element:GetBottom())
+ else
+ element:Height(20)
+ end
+ end
+
+ local bar = frame.statusBar
+ frame.index = i
+
+ -- Backup the details of the aura onto the bar, so the OnUpdate function can use it
+ bar.aura = aura
+
+ -- Configure
+ if bar.aura.noTime then
+ bar:SetMinMaxValues(0, 1)
+ bar:SetValue(1)
+ else
+ if element.scaleTime and element.scaleTime > 0 then
+ local maxValue = min(element.scaleTime, bar.aura.duration)
+ bar:SetMinMaxValues(0, element.scaleTime)
+ bar:Width((maxValue / element.scaleTime) * ((element.auraBarWidth or element:GetWidth()) - (bar:GetHeight() + (element.gap or 0)))) -- icon size + gap
+ else
+ bar:SetMinMaxValues(0, bar.aura.duration)
+ end
+
+ bar:SetValue(bar.aura.expirationTime - currentTime)
+ end
+
+ bar.icon:SetTexture(bar.aura.icon)
+
+ bar.spellname:SetText(bar.aura.count > 1 and format("%s [%d]", bar.aura.name, bar.aura.count) or bar.aura.name)
+ bar.spelltime:SetText(not bar.noTime and formatTime(bar.aura.expirationTime - currentTime))
+
+ -- Colour bars
+ local r, g, b
+
+ if helpOrHarm == "HARMFUL" then
+ local debuffType = bar.aura.debuffType and bar.aura.debuffType or "none"
+
+ if element.debuffColor then
+ r, g, b = unpack(element.debuffColor)
+ elseif debuffType == "none" and element.defaultDebuffColor then
+ r, g, b = unpack(element.defaultDebuffColor)
+ else
+ r, g, b = DebuffTypeColor[debuffType].r, DebuffTypeColor[debuffType].g, DebuffTypeColor[debuffType].b
+ end
+ elseif element.buffColor then
+ r, g, b = unpack(element.buffColor)
+ else
+ -- buffs default
+ r, g, b = .2, .6, 1
+ end
+
+ bar:SetStatusBarColor(r, g, b)
+ frame:Show()
+ end
+
+ -- Hide unused bars
+ for i = lastAuraIndex + 1, #bars do
+ bars[i]:Hide()
+ end
+
+ if element.PostUpdate then
+ element:PostUpdate(event, unit)
+ end
+end
+
+local function Enable(self)
+ local element = self.AuraBars
+
+ if element then
+ self:RegisterEvent("UNIT_AURA", Update)
+ element.SetAnchors = SetAnchors
+ element.maxBars = element.maxBars or 40
+ element.bars = element.bars or {}
+ element:Height(1)
+ element:SetScript("OnUpdate", UpdateBars)
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.AuraBars
+
+ if element then
+ element:SetScript("OnUpdate", nil)
+ self:UnregisterEvent("UNIT_AURA", Update)
+ end
+end
+
+oUF:AddElement("AuraBars", Update, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_AuraWatch/oUF_AuraWatch.lua b/ElvUI/Libraries/oUF_Plugins/oUF_AuraWatch/oUF_AuraWatch.lua
new file mode 100644
index 0000000..488c720
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_AuraWatch/oUF_AuraWatch.lua
@@ -0,0 +1,424 @@
+--[[------------------------------------------------------------------------------------------------------
+oUF_AuraWatch by Astromech
+Please leave comments, suggestions, and bug reports on this addon's WoWInterface page
+
+To setup, create a table named AuraWatch in your unit frame. There are several options
+you can specify, as explained below.
+
+ icons
+ Mandatory!
+ A table of frames to be used as icons. oUF_Aurawatch does not position
+ these frames, so you must do so yourself. Each icon needs a spellID entry,
+ which is the spell ID of the aura to watch. Table should be set up
+ such that values are icon frames, but the keys can be anything.
+
+ Note each icon can have several options set as well. See below.
+ strictMatching
+ Default: false
+ If true, AuraWatch will only show an icon if the specific aura
+ with the specified spell id is on the unit. If false, AuraWatch
+ will show the icon if any aura with the same name and icon texture
+ is on the unit. Strict matching can be undesireable because most
+ ranks of an aura have different spell ids.
+ missingAlpha
+ Default 0.75
+ The alpha value for icons of auras which have faded from the unit.
+ presentAlpha
+ Default 1
+ The alpha value for icons or auras present on the unit.
+ onlyShowMissing
+ Default false
+ If this is true, oUF_AW will hide icons if they are present on the unit.
+ onlyShowPresent
+ Default false
+ If this is true, oUF_AW will hide icons if they have expired from the unit.
+ hideCooldown
+ Default false
+ If this is true, oUF_AW will not create a cooldown frame
+ hideCount
+ Default false
+ If this is true, oUF_AW will not create a count fontstring
+ fromUnits
+ Default {["player"] = true, ["pet"] = true, ["vehicle"] = true}
+ A table of units from which auras can originate. Have the units be the keys
+ and "true" be the values.
+ anyUnit
+ Default false
+ Set to true for oUF_AW to to show an aura no matter what unit it
+ originates from. This will override any fromUnits setting.
+ decimalThreshold
+ Default 5
+ The threshold before timers go into decimal form. Set to -1 to disable decimals.
+ PostCreateIcon
+ Default nil
+ A function to call when an icon is created to modify it, such as adding
+ a border or repositioning the count fontstring. Leave as nil to ignore.
+ The arguements are: AuraWatch table, icon, auraSpellID, auraName, unitFrame
+
+Below are options set on a per icon basis. Set these as fields in the icon frames.
+
+The following settings can be overridden from the AuraWatch table on a per-aura basis:
+ onlyShowMissing
+ onlyShowPresent
+ hideCooldown
+ hideCount
+ fromUnits
+ anyUnit
+ decimalThreshold
+
+The following settings are unique to icons:
+
+ spellID
+ Mandatory!
+ The spell id of the aura, as explained above.
+ icon
+ Default aura texture
+ A texture value for this icon.
+ overlay
+ Default Blizzard aura overlay
+ An overlay for the icon. This is not created if a custom icon texture is created.
+ count
+ Default A fontstring
+ An fontstring to show the stack count of an aura.
+
+Here is an example of how to set oUF_AW up:
+
+ local createAuraWatch = function(self, unit)
+ local auras = {}
+
+ -- A table of spellIDs to create icons for
+ -- To find spellIDs, look up a spell on www.wowhead.com and look at the URL
+ -- http://www.wowhead.com/?spell=SPELL_ID
+ local spellIDs = { ... }
+
+ auras.presentAlpha = 1
+ auras.missingAlpha = .7
+ auras.PostCreateIcon = myCustomIconSkinnerFunction
+ -- Set any other AuraWatch settings
+ auras.icons = {}
+ for i, sid in pairs(spellIDs) do
+ local icon = CreateFrame("Frame", nil, auras)
+ icon.spellID = sid
+ -- set the dimensions and positions
+ icon:SetWidth(24)
+ icon:SetHeight(24)
+ icon:SetPoint("BOTTOM", self, "BOTTOM", 0, 28 * i)
+ auras.icons[sid] = icon
+ -- Set any other AuraWatch icon settings
+ end
+ self.AuraWatch = auras
+ end
+-----------------------------------------------------------------------------------------------------------]]
+
+local _, ns = ...
+local oUF = oUF or ns.oUF
+assert(oUF, "oUF_AuraWatch was unable to locate oUF install")
+
+local next = next
+local pairs = pairs
+
+local CreateFrame = CreateFrame
+local GetSpellInfo = GetSpellInfo
+local GetTime = GetTime
+local UnitAura = UnitAura
+local UnitGUID = UnitGUID
+
+local GUIDs = {}
+
+local PLAYER_UNITS = {
+ player = true,
+ vehicle = true,
+ pet = true,
+}
+
+local setupGUID
+do
+ local cache = setmetatable({}, {__type = "k"})
+
+ local frame = CreateFrame("Frame")
+ frame:SetScript("OnEvent", function(self, event)
+ for k, t in pairs(GUIDs) do
+ GUIDs[k] = nil
+ for a in pairs(t) do
+ t[a] = nil
+ end
+ cache[t] = true
+ end
+ end)
+ frame:RegisterEvent("PLAYER_REGEN_ENABLED")
+ frame:RegisterEvent("PLAYER_ENTERING_WORLD")
+
+ function setupGUID(guid)
+ local t = next(cache)
+ if t then
+ cache[t] = nil
+ else
+ t = {}
+ end
+ GUIDs[guid] = t
+ end
+end
+
+local DAY, HOUR, MINUTE = 86400, 3600, 60
+local function formatTime(s, threshold)
+ if s >= DAY then
+ return format("%dd", ceil(s / HOUR))
+ elseif s >= HOUR then
+ return format("%dh", ceil(s / HOUR))
+ elseif s >= MINUTE then
+ return format("%dm", ceil(s / MINUTE))
+ elseif s >= threshold then
+ return floor(s)
+ end
+
+ return format("%.1f", s)
+end
+
+local function updateText(self, elapsed)
+ if self.timeLeft then
+ self.elapsed = self.elapsed + elapsed
+
+ if self.elapsed >= 0.1 then
+ if not self.first then
+ self.timeLeft = self.timeLeft - self.elapsed
+ else
+ self.timeLeft = self.timeLeft - GetTime()
+ self.first = false
+ end
+
+ if self.timeLeft > 0 then
+ if self.timeLeft <= self.textThreshold or self.textThreshold == -1 then
+ self.text:SetText(formatTime(self.timeLeft, self.decimalThreshold or 5))
+ else
+ self.text:SetText("")
+ end
+ else
+ self.text:SetText("")
+ self:SetScript("OnUpdate", nil)
+ end
+
+ self.elapsed = 0
+ end
+ end
+end
+
+local function resetIcon(icon, frame, count, duration, remaining)
+ if icon.onlyShowMissing then
+ icon:Hide()
+ else
+ if icon.cd then
+ if duration and duration > 0 and icon.style ~= "NONE" then
+ icon.cd:SetCooldown(remaining - duration, duration)
+ icon.cd:Show()
+ else
+ icon.cd:Hide()
+ end
+ end
+
+ if icon.displayText then
+ icon.timeLeft = remaining
+ icon.first = true
+ icon.elapsed = 0
+ icon:SetScript("OnUpdate", updateText)
+ end
+
+ if icon.count then
+ icon.count:SetText(count > 1 and count)
+ end
+
+ if icon.overlay then
+ icon.overlay:Hide()
+ end
+
+ icon:SetAlpha(icon.presentAlpha)
+ icon:Show()
+ end
+end
+
+local function expireIcon(icon, frame)
+ if icon.onlyShowPresent then
+ icon:Hide()
+ else
+ if icon.cd then
+ icon.cd:Hide()
+ end
+
+ if icon.count then
+ icon.count:SetText()
+ end
+
+ if icon.overlay then
+ icon.overlay:Show()
+ end
+
+ icon:SetAlpha(icon.missingAlpha)
+ icon:Show()
+ end
+end
+
+local found = {}
+local function Update(self, event, unit)
+ if not unit or self.unit ~= unit then return end
+
+ local guid = UnitGUID(unit)
+ if not guid then return end
+
+ if not GUIDs[guid] then
+ setupGUID(guid)
+ end
+
+ local element = self.AuraWatch
+ local icons = element.watched
+
+ for _, icon in pairs(icons) do
+ if not icon.onlyShowMissing then
+ icon:Hide()
+ else
+ icon:Show()
+ end
+ end
+
+ local filter, index = "HELPFUL", 1
+ local _, name, texture, count, duration, remaining, caster, spellID
+ local key, icon
+
+ while true do
+ name, _, texture, count, _, duration, remaining, caster, _, _, spellID = UnitAura(unit, index, filter)
+
+ if not name then
+ if filter == "HELPFUL" then
+ filter = "HARMFUL"
+ index = 1
+ else
+ break
+ end
+ else
+ if element.strictMatching then
+ key = spellID
+ else
+ key = name..texture
+ end
+
+ icon = icons[key]
+
+ if icon and (icon.anyUnit or (caster and icon.fromUnits and icon.fromUnits[caster])) then
+ resetIcon(icon, element, count, duration, remaining)
+ GUIDs[guid][key] = true
+ found[key] = true
+ end
+
+ index = index + 1
+ end
+ end
+
+ for icon in pairs(GUIDs[guid]) do
+ if icons[icon] and not found[icon] then
+ expireIcon(icons[icon], element)
+ end
+ end
+
+ for k in pairs(found) do
+ found[k] = nil
+ end
+end
+
+local function setupIcons(self)
+ local element = self.AuraWatch
+ local icons = element.icons
+
+ element.watched = {}
+
+ for _, icon in pairs(icons) do
+ local name, _, image = GetSpellInfo(icon.spellID)
+
+ if name then
+ icon.name = name
+
+ if not icon.cd and not (element.hideCooldown or icon.hideCooldown) then
+ local cd = CreateFrame("Cooldown", nil, icon, "CooldownFrameTemplate")
+ cd:SetAllPoints(icon)
+ icon.cd = cd
+ end
+
+ if not icon.icon then
+ local tex = icon:CreateTexture(nil, "BACKGROUND")
+ tex:SetAllPoints(icon)
+ tex:SetTexture(image)
+ icon.icon = tex
+
+ if not icon.overlay then
+ local overlay = icon:CreateTexture(nil, "OVERLAY")
+ overlay:SetTexture("Interface\\Buttons\\UI-Debuff-Overlays")
+ overlay:SetAllPoints(icon)
+ overlay:SetTexCoord(.296875, .5703125, 0, .515625)
+ overlay:SetVertexColor(1, 0, 0)
+ icon.overlay = overlay
+ end
+ end
+
+ if not icon.count and not (element.hideCount or icon.hideCount) then
+ local count = icon:CreateFontString(nil, "OVERLAY")
+ count:SetFontObject(NumberFontNormal)
+ count:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", -1, 0)
+ icon.count = count
+ end
+
+ if icon.onlyShowMissing == nil then
+ icon.onlyShowMissing = element.onlyShowMissing
+ end
+ if icon.onlyShowPresent == nil then
+ icon.onlyShowPresent = element.onlyShowPresent
+ end
+ if icon.presentAlpha == nil then
+ icon.presentAlpha = element.presentAlpha
+ end
+ if icon.missingAlpha == nil then
+ icon.missingAlpha = element.missingAlpha
+ end
+ if icon.fromUnits == nil then
+ icon.fromUnits = element.fromUnits or PLAYER_UNITS
+ end
+ if icon.anyUnit == nil then
+ icon.anyUnit = element.anyUnit
+ end
+
+ if element.strictMatching then
+ element.watched[icon.spellID] = icon
+ else
+ element.watched[name..image] = icon
+ end
+
+ if element.PostCreateIcon then
+ element:PostCreateIcon(icon, icon.spellID, name, self)
+ end
+ else
+ print("oUF_AuraWatch error: no spell with "..tostring(icon.spellID).." spell ID exists")
+ end
+ end
+end
+
+local function Enable(self)
+ local element = self.AuraWatch
+
+ if element then
+ element.Update = setupIcons
+ self:RegisterEvent("UNIT_AURA", Update)
+ setupIcons(self)
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.AuraWatch
+
+ if element then
+ self:UnregisterEvent("UNIT_AURA", Update)
+
+ for _, icon in pairs(element.icons) do
+ icon:Hide()
+ end
+ end
+end
+
+oUF:AddElement("AuraWatch", Update, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_Cutaway/oUF_Cutaway.lua b/ElvUI/Libraries/oUF_Plugins/oUF_Cutaway/oUF_Cutaway.lua
new file mode 100644
index 0000000..14b45fa
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_Cutaway/oUF_Cutaway.lua
@@ -0,0 +1,298 @@
+local _, ns = ...
+local oUF = _G.oUF or ns.oUF
+assert(oUF, "oUF_Cutaway was unable to locate oUF install.")
+
+--[[
+ Configuration values for both health and power:
+ .enabled: enable cutaway for this element, defaults to disabled
+ .fadeOutTime: How long it takes the cutaway health to fade, defaults to 0.6 seconds
+ .lengthBeforeFade: How long it takes before the cutaway begins to fade, defaults to 0.3 seconds
+]]
+-- GLOBALS: ElvUI
+
+local max = math.max
+
+local UnitGUID = UnitGUID
+local UnitHealthMax = UnitHealthMax
+local UnitIsTapped = UnitIsTapped
+local UnitIsTappedByAllThreatList = UnitIsTappedByAllThreatList
+local UnitIsTappedByPlayer = UnitIsTappedByPlayer
+local UnitPowerMax = UnitPowerMax
+local hooksecurefunc = hooksecurefunc
+
+local E -- placeholder
+
+local function checkElvUI()
+ if not E then
+ E = _G.ElvUI[1]
+ assert(E, "oUF_Cutaway was not able to locate ElvUI and it is required.")
+ end
+end
+
+local function closureFunc(self)
+ self.ready = nil
+ self.playing = nil
+ self.cur = nil
+end
+
+local function fadeClosure(element)
+ if not element.FadeObject then
+ element.FadeObject = {
+ finishedFuncKeep = true,
+ finishedArg1 = element,
+ finishedFunc = closureFunc
+ }
+ end
+
+ E:UIFrameFadeOut(element, element.fadeOutTime, element.__parentElement:GetAlpha(), 0)
+end
+
+local function Shared_PreUpdate(self, element, unit)
+ element.unit = unit
+ local oldGUID, newGUID = element.guid, UnitGUID(unit)
+ element.guid = newGUID
+ if (not oldGUID or oldGUID ~= newGUID) then
+ return
+ end
+ element.cur = self.cur
+ element.ready = true
+end
+
+local function UpdateSize(self, element, curV, maxV)
+ local isVertical = self:GetOrientation() == "VERTICAL"
+ local pm = (isVertical and self:GetHeight()) or self:GetWidth()
+ local oum = (1 / maxV) * pm
+ local c = max(element.cur - curV, 0)
+ local mm = c * oum
+ if isVertical then
+ element:SetHeight(mm)
+ else
+ element:SetWidth(mm)
+ end
+end
+
+local PRE = 0
+local POST = 1
+
+local function Shared_UpdateCheckReturn(self, element, updateType, ...)
+ if not element:IsVisible() then
+ return true
+ end
+ if (updateType == PRE) then
+ local maxV = ...
+ return (not element.enabled or not self.cur) or element.ready or not maxV
+ elseif (updateType == POST) then
+ local curV, maxV, unit = ...
+ return (not element.enabled or not element.cur) or (not element.ready or not curV or not maxV) or element.unit ~= unit
+ else
+ return false
+ end
+end
+
+local function Health_PreUpdate(self, unit)
+ local element = self.__owner.Cutaway.Health
+ local maxV = UnitHealthMax(unit)
+ if Shared_UpdateCheckReturn(self, element, PRE, maxV) or (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) and not UnitIsTappedByAllThreatList(unit)) then return end
+
+ Shared_PreUpdate(self, element, unit)
+end
+
+local function Health_PostUpdate(self, unit, curHealth, maxHealth)
+ local element = self.__owner.Cutaway.Health
+ if Shared_UpdateCheckReturn(self, element, POST, curHealth, maxHealth, unit) then return end
+
+ UpdateSize(self, element, curHealth, maxHealth)
+ if element.playing then return end
+
+ if (element.cur - curHealth) > (maxHealth * 0.01) then
+ element:SetAlpha(self:GetAlpha())
+
+ E:Delay(element.lengthBeforeFade, fadeClosure, element)
+
+ element.playing = true
+ else
+ element:SetAlpha(0)
+ closureFunc(element)
+ end
+end
+
+local function Health_PostUpdateColor(self, _, _, _, _)
+ local r, g, b = self:GetStatusBarColor()
+ self.__owner.Cutaway.Health:SetVertexColor(r * 1.5, g * 1.5, b * 1.5)
+end
+
+local function Power_PreUpdate(self, unit)
+ local element = self.__owner.Cutaway.Power
+ local maxV = UnitPowerMax(unit)
+ if Shared_UpdateCheckReturn(self, element, PRE, maxV) then return end
+
+ Shared_PreUpdate(self, element, unit)
+end
+
+local function Power_PostUpdate(self, unit, curPower, maxPower)
+ local element = self.__owner.Cutaway.Power
+ if Shared_UpdateCheckReturn(self, element, POST, curPower, maxPower, unit) then return end
+
+ UpdateSize(self, element, curPower, maxPower)
+ if element.playing then return end
+
+ if (element.cur - curPower) > (maxPower * 0.01) then
+ element:SetAlpha(self:GetAlpha())
+
+ E:Delay(element.lengthBeforeFade, fadeClosure, element)
+
+ element.playing = true
+ else
+ element:SetAlpha(0)
+ closureFunc(element)
+ end
+end
+
+local function Power_PostUpdateColor(self, _, _, _, _)
+ local r, g, b = self:GetStatusBarColor()
+ self.__owner.Cutaway.Power:SetVertexColor(r * 1.5, g * 1.5, b * 1.5)
+end
+
+local defaults = {
+ health = {
+ enabled = false,
+ lengthBeforeFade = 0.3,
+ fadeOutTime = 0.6
+ },
+ power = {
+ enabled = false,
+ lengthBeforeFade = 0.3,
+ fadeOutTime = 0.6
+ }
+}
+
+local function UpdateConfigurationValues(self, db)
+ local hs, ps = false, false
+ if (self.Health) then
+ local health = self.Health
+ local hdb = db.health
+ hs = hdb.enabled
+ health.enabled = hs
+ if (hs) then
+ health.lengthBeforeFade = hdb.lengthBeforeFade
+ health.fadeOutTime = hdb.fadeOutTime
+ health:Show()
+ else
+ health:Hide()
+ end
+ end
+ if (self.Power) then
+ local power = self.Power
+ local pdb = db.power
+ ps = pdb.enabled
+ power.enabled = ps
+ if (ps) then
+ power.lengthBeforeFade = pdb.lengthBeforeFade
+ power.fadeOutTime = pdb.fadeOutTime
+ power:Show()
+ else
+ power:Hide()
+ end
+ end
+ return hs, ps
+end
+
+local function Enable(self)
+ local element = self and self.Cutaway
+ if (element) then
+ checkElvUI()
+
+ if (element.Health and element.Health:IsObjectType("Texture") and not element.Health:GetTexture()) then
+ element.Health:SetTexture([[Interface\TargetingFrame\UI-StatusBar]])
+ end
+
+ if (element.Power and element.Power:IsObjectType("Texture") and not element.Power:GetTexture()) then
+ element.Power:SetTexture([[Interface\TargetingFrame\UI-StatusBar]])
+ end
+
+ if (not element.defaultsSet) then
+ UpdateConfigurationValues(element, defaults)
+ element.defaultsSet = true
+ end
+
+ if element.Health and self.Health then
+ self.Health.__owner = self
+
+ element.Health.__parentElement = self.Health
+ element.Health:SetAlpha(0)
+
+ if not element.Health.hasCutawayHook then
+ if self.Health.PreUpdate then
+ hooksecurefunc(self.Health, "PreUpdate", Health_PreUpdate)
+ else
+ self.Health.PreUpdate = Health_PreUpdate
+ end
+
+ if self.Health.PostUpdate then
+ hooksecurefunc(self.Health, "PostUpdate", Health_PostUpdate)
+ else
+ self.Health.PostUpdate = Health_PostUpdate
+ end
+
+ if self.Health.PostUpdateColor then
+ hooksecurefunc(self.Health, "PostUpdateColor", Health_PostUpdateColor)
+ else
+ self.Health.PostUpdateColor = Health_PostUpdateColor
+ end
+
+ element.Health.hasCutawayHook = true
+ end
+ end
+
+ if element.Power and self.Power then
+ self.Power.__owner = self
+
+ element.Power.__parentElement = self.Power
+ element.Power:SetAlpha(0)
+
+ if not element.Power.hasCutawayHook then
+ if self.Power.PreUpdate then
+ hooksecurefunc(self.Power, "PreUpdate", Power_PreUpdate)
+ else
+ self.Power.PreUpdate = Power_PreUpdate
+ end
+
+ if self.Power.PostUpdate then
+ hooksecurefunc(self.Power, "PostUpdate", Power_PostUpdate)
+ else
+ self.Power.PostUpdate = Power_PostUpdate
+ end
+
+ if self.Power.PostUpdateColor then
+ hooksecurefunc(self.Power, "PostUpdateColor", Power_PostUpdateColor)
+ else
+ self.Power.PostUpdateColor = Power_PostUpdateColor
+ end
+
+ element.Power.hasCutawayHook = true
+ end
+ end
+
+ if not (element.UpdateConfigurationValues) then
+ element.UpdateConfigurationValues = UpdateConfigurationValues
+ end
+
+ return true
+ end
+end
+
+local function disableElement(element)
+ if element then
+ element.enabled = false
+ element:Hide()
+ end
+end
+
+local function Disable(self)
+ if self and self.Cutaway then
+ disableElement(self.Cutaway.Health)
+ disableElement(self.Cutaway.Power)
+ end
+end
+
+oUF:AddElement("Cutaway", nil, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_DebuffHighlight/oUF_DebuffHighlight.lua b/ElvUI/Libraries/oUF_Plugins/oUF_DebuffHighlight/oUF_DebuffHighlight.lua
new file mode 100644
index 0000000..d3de78f
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_DebuffHighlight/oUF_DebuffHighlight.lua
@@ -0,0 +1,89 @@
+local _, ns = ...
+local oUF = oUF or ns.oUF
+if not oUF then return end
+
+local UnitAura = UnitAura
+local UnitCanAssist = UnitCanAssist
+
+local function GetDebuffType(unit, filterTable)
+ if not unit or not UnitCanAssist("player", unit) then return nil end
+
+ local i = 1
+ while true do
+ local name, _, texture, _, debufftype, _, _, _, _, _, spellID = UnitAura(unit, i, "HARMFUL")
+ if not texture then break end
+
+ local filterSpell = filterTable[spellID] or filterTable[name]
+
+ if filterTable and filterSpell and filterSpell.enable then
+ return debufftype, texture, true, filterSpell.style, filterSpell.color
+ elseif debufftype then
+ return debufftype, texture
+ end
+
+ i = i + 1
+ end
+end
+
+local function Update(object, event, unit)
+ if unit ~= object.unit then return end
+
+ local debuffType, texture, wasFiltered, style, color = GetDebuffType(unit, object.DebuffHighlightFilterTable)
+
+ if wasFiltered then
+ if style == "GLOW" and object.DBHGlow then
+ object.DBHGlow:Show()
+ object.DBHGlow:SetBackdropBorderColor(color.r, color.g, color.b)
+ elseif object.DBHGlow then
+ object.DBHGlow:Hide()
+ object.DebuffHighlight:SetVertexColor(color.r, color.g, color.b, color.a or object.DebuffHighlightAlpha or .5)
+ end
+ elseif debuffType then
+ color = DebuffTypeColor[debuffType]
+
+ if object.DebuffHighlightBackdrop and object.DBHGlow then
+ object.DBHGlow:Show()
+ object.DBHGlow:SetBackdropBorderColor(color.r, color.g, color.b)
+ elseif object.DebuffHighlightUseTexture then
+ object.DebuffHighlight:SetTexture(texture)
+ else
+ object.DebuffHighlight:SetVertexColor(color.r, color.g, color.b, object.DebuffHighlightAlpha or .5)
+ end
+ else
+ if object.DBHGlow then
+ object.DBHGlow:Hide()
+ end
+
+ if object.DebuffHighlightUseTexture then
+ object.DebuffHighlight:SetTexture(nil)
+ else
+ object.DebuffHighlight:SetVertexColor(0, 0, 0, 0)
+ end
+ end
+
+ if object.DebuffHighlight.PostUpdate then
+ object.DebuffHighlight:PostUpdate(object, debuffType, texture, wasFiltered, style, color)
+ end
+end
+
+local function Enable(object)
+ -- if we're not highlighting this unit return
+ if not object.DebuffHighlightBackdrop and not object.DebuffHighlight and not object.DBHGlow then
+ return
+ end
+
+ -- make sure aura scanning is active for this object
+ object:RegisterEvent("UNIT_AURA", Update)
+
+ return true
+end
+
+local function Disable(object)
+ object:UnregisterEvent("UNIT_AURA", Update)
+
+ if object.DBHGlow then
+ object.DBHGlow:Hide()
+ end
+end
+
+oUF:AddElement("DebuffHighlight", Update, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_Fader/oUF_Fader.lua b/ElvUI/Libraries/oUF_Plugins/oUF_Fader/oUF_Fader.lua
new file mode 100644
index 0000000..91c8553
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_Fader/oUF_Fader.lua
@@ -0,0 +1,342 @@
+local _, ns = ...
+local oUF = _G.oUF or ns.oUF
+assert(oUF, "oUF_Fader cannot find an instance of oUF. If your oUF is embedded into a layout, it may not be embedded properly.")
+
+-------------
+-- Credits -- p3lim, Azilroka, Simpy
+-------------
+
+local _G = _G
+local pairs, ipairs = pairs, ipairs
+local next, tinsert, tremove = next, tinsert, tremove
+local CreateFrame = CreateFrame
+local GetMouseFocus = GetMouseFocus
+local UnitAffectingCombat = UnitAffectingCombat
+local UnitCastingInfo = UnitCastingInfo
+local UnitChannelInfo = UnitChannelInfo
+local UnitExists = UnitExists
+local UnitHasVehicleUI = UnitHasVehicleUI
+local UnitHealth = UnitHealth
+local UnitHealthMax = UnitHealthMax
+local UnitPower = UnitPower
+local UnitPowerMax = UnitPowerMax
+local UnitPowerType = UnitPowerType
+
+-- These variables will be left-over when disabled if they were used (for reuse later if they become re-enabled):
+---- Fader.HoverHooked, Fader.TargetHooked
+
+local E -- ElvUI engine defined in ClearTimers
+local MIN_ALPHA, MAX_ALPHA = .35, 1
+local onRangeObjects, onRangeFrame = {}
+local PowerTypesFull = {MANA = true, FOCUS = true, ENERGY = true}
+
+local function ClearTimers(element)
+ if not E then E = _G.ElvUI[1] end
+
+ if element.configTimer then
+ E:CancelTimer(element.configTimer)
+ element.configTimer = nil
+ end
+
+ if element.delayTimer then
+ E:CancelTimer(element.delayTimer)
+ element.delayTimer = nil
+ end
+end
+
+local function ToggleAlpha(self, element, endAlpha)
+ element:ClearTimers()
+
+ if element.Smooth then
+ E:UIFrameFadeOut(self, element.Smooth, self:GetAlpha(), endAlpha)
+ else
+ self:SetAlpha(endAlpha)
+ end
+end
+
+local function Update(self, _, unit)
+ local element = self.Fader
+ if self.isForced or (not element or not element.count or element.count <= 0) then
+ self:SetAlpha(1)
+ return
+ end
+
+ unit = unit or self.unit
+ if self.unit ~= unit then return end
+
+ -- range fader
+ if element.Range then
+ if element.UpdateRange then
+ element.UpdateRange(self, unit)
+ end
+ if element.RangeAlpha then
+ ToggleAlpha(self, element, element.RangeAlpha)
+ end
+ return
+ end
+
+ -- normal fader
+ local _, powerType
+ if element.Power then
+ _, powerType = UnitPowerType(unit)
+ end
+
+ if
+ (element.Casting and (UnitCastingInfo(unit) or UnitChannelInfo(unit))) or
+ (element.Combat and UnitAffectingCombat(unit)) or
+ (element.PlayerTarget and UnitExists('target')) or
+ (element.UnitTarget and UnitExists(unit..'target')) or
+ (element.Focus and UnitExists('focus')) or
+ (element.Health and UnitHealth(unit) < UnitHealthMax(unit)) or
+ (element.Power and (PowerTypesFull[powerType] and UnitPower(unit) < UnitPowerMax(unit))) or
+ (element.Vehicle and UnitHasVehicleUI(unit)) or
+ (element.Hover and GetMouseFocus() == (self.__faderobject or self))
+ then
+ ToggleAlpha(self, element, element.MaxAlpha)
+ else
+ if element.Delay then
+ element:ClearTimers()
+ element.delayTimer = E:ScheduleTimer(ToggleAlpha, element.Delay, self, element, element.MinAlpha)
+ else
+ ToggleAlpha(self, element, element.MinAlpha)
+ end
+ end
+end
+
+local function ForceUpdate(element)
+ return Update(element.__owner, "ForceUpdate", element.__owner.unit)
+end
+
+local function onRangeUpdate(frame, elapsed)
+ frame.timer = (frame.timer or 0) + elapsed
+
+ if frame.timer >= .20 then
+ for _, object in next, onRangeObjects do
+ if object:IsVisible() then
+ object.Fader:ForceUpdate()
+ end
+ end
+
+ frame.timer = 0
+ end
+end
+
+local function HoverScript(self)
+ local Fader = self.__faderelement or self.Fader
+ if Fader and Fader.HoverHooked == 1 then
+ Fader:ForceUpdate()
+ end
+end
+
+local function TargetScript(self)
+ if self.Fader and self.Fader.TargetHooked == 1 then
+ if self:IsShown() then
+ self.Fader:ForceUpdate()
+ else
+ self:SetAlpha(0)
+ end
+ end
+end
+
+local options = {
+ Range = {
+ enable = function(self)
+ if not onRangeFrame then
+ onRangeFrame = CreateFrame('Frame')
+ onRangeFrame:SetScript('OnUpdate', onRangeUpdate)
+ end
+
+ onRangeFrame:Show()
+ tinsert(onRangeObjects, self)
+ end,
+ disable = function(self)
+ if onRangeFrame then
+ for idx, obj in next, onRangeObjects do
+ if obj == self then
+ self.Fader.RangeAlpha = nil
+ tremove(onRangeObjects, idx)
+ break
+ end
+ end
+
+ if #onRangeObjects == 0 then
+ onRangeFrame:Hide()
+ end
+ end
+ end
+ },
+ Hover = {
+ enable = function(self)
+ if not self.Fader.HoverHooked then
+ local Frame = self.__faderobject or self
+ Frame:HookScript('OnEnter', HoverScript)
+ Frame:HookScript('OnLeave', HoverScript)
+ end
+
+ self.Fader.HoverHooked = 1 -- on state
+ end,
+ disable = function(self)
+ if self.Fader.HoverHooked == 1 then
+ self.Fader.HoverHooked = 0 -- off state
+ end
+ end
+ },
+ Combat = {
+ enable = function(self)
+ self:RegisterEvent('PLAYER_REGEN_ENABLED', Update, true)
+ self:RegisterEvent('PLAYER_REGEN_DISABLED', Update, true)
+ self:RegisterEvent('UNIT_FLAGS', Update)
+ end,
+ events = {'PLAYER_REGEN_ENABLED','PLAYER_REGEN_DISABLED','UNIT_FLAGS'}
+ },
+ Target = { --[[ UnitTarget, PlayerTarget ]]
+ enable = function(self)
+ if not self.Fader.TargetHooked then
+ self:HookScript('OnShow', TargetScript)
+ self:HookScript('OnHide', TargetScript)
+ end
+
+ self.Fader.TargetHooked = 1 -- on state
+
+ if not self:IsShown() then
+ self:SetAlpha(0)
+ end
+
+ self:RegisterEvent('UNIT_TARGET', Update)
+ self:RegisterEvent('PLAYER_TARGET_CHANGED', Update, true)
+ self:RegisterEvent('PLAYER_FOCUS_CHANGED', Update, true)
+ end,
+ events = {'UNIT_TARGET','PLAYER_TARGET_CHANGED','PLAYER_FOCUS_CHANGED'},
+ disable = function(self)
+ if self.Fader.TargetHooked == 1 then
+ self.Fader.TargetHooked = 0 -- off state
+ end
+ end
+ },
+ Focus = {
+ enable = function(self)
+ self:RegisterEvent('PLAYER_FOCUS_CHANGED', Update, true)
+ end,
+ events = {'PLAYER_FOCUS_CHANGED'}
+ },
+ Health = {
+ enable = function(self)
+ self:RegisterEvent('UNIT_HEALTH', Update)
+ self:RegisterEvent('UNIT_MAXHEALTH', Update)
+ end,
+ events = {'UNIT_HEALTH','UNIT_MAXHEALTH'}
+ },
+ Power = {
+ enable = function(self)
+ self:RegisterEvent('UNIT_POWER_UPDATE', Update)
+ self:RegisterEvent('UNIT_MAXPOWER', Update)
+ end,
+ events = {'UNIT_POWER_UPDATE','UNIT_MAXPOWER'}
+ },
+ Vehicle = {
+ enable = function(self)
+ self:RegisterEvent('UNIT_ENTERED_VEHICLE', Update, true)
+ self:RegisterEvent('UNIT_EXITED_VEHICLE', Update, true)
+ end,
+ events = {'UNIT_ENTERED_VEHICLE','UNIT_EXITED_VEHICLE'}
+ },
+ Casting = {
+ enable = function(self)
+ self:RegisterEvent('UNIT_SPELLCAST_START', Update)
+ self:RegisterEvent('UNIT_SPELLCAST_FAILED', Update)
+ self:RegisterEvent('UNIT_SPELLCAST_STOP', Update)
+ self:RegisterEvent('UNIT_SPELLCAST_INTERRUPTED', Update)
+ self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_START', Update)
+ self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_STOP', Update)
+ end,
+ events = {'UNIT_SPELLCAST_START','UNIT_SPELLCAST_FAILED','UNIT_SPELLCAST_STOP','UNIT_SPELLCAST_INTERRUPTED','UNIT_SPELLCAST_CHANNEL_START','UNIT_SPELLCAST_CHANNEL_STOP'}
+ },
+ MinAlpha = {
+ countIgnored = true,
+ enable = function(self, state)
+ self.Fader.MinAlpha = state or MIN_ALPHA
+ end
+ },
+ MaxAlpha = {
+ countIgnored = true,
+ enable = function(self, state)
+ self.Fader.MaxAlpha = state or MAX_ALPHA
+ end
+ },
+ Smooth = {countIgnored = true},
+ Delay = {countIgnored = true},
+}
+
+local function CountOption(element, state, oldState)
+ if state and not oldState then
+ element.count = (element.count or 0) + 1
+ elseif oldState and element.count and not state then
+ element.count = element.count - 1
+ end
+end
+
+local function SetOption(element, opt, state)
+ local option = ((opt == 'UnitTarget' or opt == 'PlayerTarget') and 'Target') or opt
+ local oldState = element[opt]
+
+ if option and options[option] and (oldState ~= state) then
+ element[opt] = state
+
+ if state then
+ if type(state) == 'table' then
+ state.__faderelement = element
+ element.__owner.__faderobject = state
+ end
+
+ if options[option].enable then
+ options[option].enable(element.__owner, state)
+ end
+ else
+ if options[option].events and next(options[option].events) then
+ for _, event in ipairs(options[option].events) do
+ element.__owner:UnregisterEvent(event, Update)
+ end
+ end
+
+ if options[option].disable then
+ options[option].disable(element.__owner)
+ end
+ end
+
+ if not options[option].countIgnored then
+ CountOption(element, state, oldState)
+ end
+ end
+end
+
+local function Enable(self)
+ if self.Fader then
+ self.Fader.__owner = self
+ self.Fader.ForceUpdate = ForceUpdate
+ self.Fader.SetOption = SetOption
+ self.Fader.ClearTimers = ClearTimers
+
+ self.Fader.MinAlpha = MIN_ALPHA
+ self.Fader.MaxAlpha = MAX_ALPHA
+
+ return true
+ end
+end
+
+local function Disable(self)
+ if self.Fader then
+ for opt in pairs(options) do
+ if opt == 'Target' then
+ self.Fader:SetOption('UnitTarget')
+ self.Fader:SetOption('PlayerTarget')
+ else
+ self.Fader:SetOption(opt)
+ end
+ end
+
+ self.Fader.count = nil
+ self.Fader:ClearTimers()
+ end
+end
+
+oUF:AddElement('Fader', nil, Enable, Disable)
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_GPS/oUF_GPS.lua b/ElvUI/Libraries/oUF_Plugins/oUF_GPS/oUF_GPS.lua
new file mode 100644
index 0000000..e92c6f8
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_GPS/oUF_GPS.lua
@@ -0,0 +1,178 @@
+local _, ns = ...
+local oUF = ns.oUF or oUF
+assert(oUF, "oUF_GPS was unable to locate oUF install")
+
+local atan2, cos, sin = math.atan2, math.cos, math.sin
+local tremove = table.remove
+
+local sqrt2 = math.sqrt(2)
+local pi2 = math.pi / 2
+
+local GetPlayerFacing = GetPlayerFacing
+local GetPlayerMapPosition = GetPlayerMapPosition
+local UnitInParty = UnitInParty
+local UnitInRaid = UnitInRaid
+local UnitInRange = UnitInRange
+local UnitIsConnected = UnitIsConnected
+local UnitIsUnit = UnitIsUnit
+
+local function CalculateCorner(r)
+ return 0.5 + cos(r) / sqrt2, 0.5 + sin(r) / sqrt2
+end
+
+local function RotateTexture(texture, angle)
+ local LRx, LRy = CalculateCorner(angle + 0.785398163)
+ local LLx, LLy = CalculateCorner(angle + 2.35619449)
+ local ULx, ULy = CalculateCorner(angle + 3.92699082)
+ local URx, URy = CalculateCorner(angle - 0.785398163)
+
+ texture:SetTexCoord(ULx, ULy, LLx, LLy, URx, URy, LRx, LRy)
+end
+
+local function GetAngle(unit1, unit2)
+ local x1, y1 = GetPlayerMapPosition(unit1)
+ if x1 <= 0 and y1 <= 0 then return end
+
+ local x2, y2 = GetPlayerMapPosition(unit2)
+ if x2 <= 0 and y2 <= 0 then return end
+
+ return -pi2 - GetPlayerFacing() - atan2(y2 - y1, x2 - x1)
+end
+
+local function UpdateElement(element, unit)
+ if not unit or UnitIsUnit(unit, "player") or not UnitIsConnected(unit) or not (UnitInParty(unit) or UnitInRaid(unit)) or (element.outOfRange and UnitInRange(unit)) then
+ element:Hide()
+ else
+ local angle = GetAngle("player", unit)
+
+ if angle then
+ RotateTexture(element.Texture, angle)
+ element:Show()
+ else
+ element:Hide()
+ end
+ end
+end
+
+local _FRAMES = {}
+local ListUpdateFrame
+
+local function OnUpdateList(self, elapsed)
+ self.elapsed = self.elapsed + elapsed
+
+ if self.elapsed < 0.0333 then return end
+
+ self.elapsed = 0
+
+ for i = 1, #_FRAMES do
+ local object = _FRAMES[i]
+
+ if object:IsShown() then
+ UpdateElement(object.GPS, object.unit)
+ end
+ end
+end
+local function OnUpdateFrame(self, elapsed)
+ self.__elapsed = self.__elapsed + elapsed
+
+ if self.__elapsed < 0.0333 then return end
+
+ self.__elapsed = 0
+ UpdateElement(self.GPS, self.unit)
+end
+
+local function OnEnter(self)
+ if not self.__enabled then return end
+
+ self.__elapsed = 0
+ self:SetScript("OnUpdate", OnUpdateFrame)
+end
+local function OnLeave(self)
+ if not self.__enabled then return end
+
+ self:SetScript("OnUpdate", nil)
+ self.GPS:Hide()
+end
+
+local function disableHook(self, element)
+ if not element.__hooked then return end
+
+ self.__enabled = false
+ self:SetScript("OnUpdate", nil)
+end
+local function disableGlobal(self, element)
+ if not element.__global then return end
+
+ for i = 1, #_FRAMES do
+ if _FRAMES[i] == self then
+ tremove(_FRAMES, i)
+ element:Hide()
+ break
+ end
+ end
+
+ element.__global = nil
+
+ if #_FRAMES == 0 and ListUpdateFrame then
+ ListUpdateFrame:Hide()
+ end
+end
+
+local function UpdateState(self, disable)
+ local element = self.GPS
+
+ if not disable then
+ if element.onMouseOver then
+ disableGlobal(self, element)
+
+ if not element.__hooked then
+ self:HookScript("OnEnter", OnEnter)
+ self:HookScript("OnLeave", OnLeave)
+
+ element.__hooked = true
+ end
+
+ self.__enabled = true
+ else
+ disableHook(self, element)
+
+ if not element.__global then
+ _FRAMES[#_FRAMES + 1] = self
+ element.__global = true
+
+ if not ListUpdateFrame then
+ ListUpdateFrame = CreateFrame("Frame")
+ ListUpdateFrame:SetScript("OnUpdate", OnUpdateList)
+ ListUpdateFrame.elapsed = 0
+ end
+
+ ListUpdateFrame:Show()
+ end
+ end
+ else
+ disableGlobal(self, element)
+ disableHook(self, element)
+ end
+end
+
+local function Enable(self)
+ local element = self.GPS
+
+ if element then
+ element.UpdateState = UpdateState
+
+ UpdateState(self)
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.GPS
+
+ if element then
+ UpdateState(self, true)
+ end
+end
+
+oUF:AddElement("GPS", nil, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/LibHealComm-4.0/LibHealComm-4.0.lua b/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/LibHealComm-4.0/LibHealComm-4.0.lua
new file mode 100644
index 0000000..5ecb03b
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/LibHealComm-4.0/LibHealComm-4.0.lua
@@ -0,0 +1,2963 @@
+local major = "LibHealComm-4.0"
+local minor = 67
+assert(LibStub, string.format("%s requires LibStub.", major))
+
+local HealComm = LibStub:NewLibrary(major, minor)
+if( not HealComm ) then return end
+
+local pairs = pairs
+local rawget, rawset = rawget, rawset
+local select = select
+local setmetatable = setmetatable
+local tonumber = tonumber
+local type = type
+local unpack = unpack
+local band, bor = bit.band, bit.bor
+local ceil, floor, max, min = math.ceil, math.floor, math.max, math.min
+local byte, char, format, gsub, len, match, split = string.byte, string.char, string.format, string.gsub, string.len, string.match, string.split
+local tconcat, tinsert, tremove, twipe = table.concat, table.insert, table.remove, table.wipe
+
+local GetGlyphSocketInfo = GetGlyphSocketInfo
+local GetInventoryItemLink = GetInventoryItemLink
+local GetNumGlyphSockets = GetNumGlyphSockets
+local GetNumPartyMembers = GetNumPartyMembers
+local GetNumRaidMembers = GetNumRaidMembers
+local GetNumSpellTabs = GetNumSpellTabs
+local GetNumTalentTabs = GetNumTalentTabs
+local GetNumTalents = GetNumTalents
+local GetRaidRosterInfo = GetRaidRosterInfo
+local GetSpellBonusHealing = GetSpellBonusHealing
+local GetSpellCritChance = GetSpellCritChance
+local GetSpellInfo = GetSpellInfo
+local GetSpellName = GetSpellName
+local GetSpellTabInfo = GetSpellTabInfo
+local GetTalentInfo = GetTalentInfo
+local GetTime = GetTime
+local GetZonePVPInfo = GetZonePVPInfo
+local InCombatLockdown = InCombatLockdown
+local IsEquippedItem = IsEquippedItem
+local IsInInstance = IsInInstance
+local IsSpellInRange = IsSpellInRange
+local SpellIsTargeting = SpellIsTargeting
+local UnitAura = UnitAura
+local UnitBuff = UnitBuff
+local UnitCanAssist = UnitCanAssist
+local UnitCastingInfo = UnitCastingInfo
+local UnitChannelInfo = UnitChannelInfo
+local UnitExists = UnitExists
+local UnitGUID = UnitGUID
+local UnitHasVehicleUI = UnitHasVehicleUI
+local UnitIsCharmed = UnitIsCharmed
+local UnitIsVisible = UnitIsVisible
+local UnitLevel = UnitLevel
+local UnitName = UnitName
+local UnitPlayerControlled = UnitPlayerControlled
+
+local BOOKTYPE_SPELL = BOOKTYPE_SPELL
+local MAX_PARTY_MEMBERS = MAX_PARTY_MEMBERS
+local MAX_PLAYER_LEVEL = MAX_PLAYER_LEVEL
+local MAX_RAID_MEMBERS = MAX_RAID_MEMBERS
+
+-- API CONSTANTS
+local ALL_DATA = 0x0f
+local DIRECT_HEALS = 0x01
+local CHANNEL_HEALS = 0x02
+local HOT_HEALS = 0x04
+local ABSORB_SHIELDS = 0x08
+local BOMB_HEALS = 0x10
+local ALL_HEALS = bor(DIRECT_HEALS, CHANNEL_HEALS, HOT_HEALS, BOMB_HEALS)
+local CASTED_HEALS = bor(DIRECT_HEALS, CHANNEL_HEALS)
+local OVERTIME_HEALS = bor(HOT_HEALS, CHANNEL_HEALS)
+
+HealComm.ALL_HEALS, HealComm.CHANNEL_HEALS, HealComm.DIRECT_HEALS, HealComm.HOT_HEALS, HealComm.CASTED_HEALS, HealComm.ABSORB_SHIELDS, HealComm.ALL_DATA, HealComm.BOMB_HEALS = ALL_HEALS, CHANNEL_HEALS, DIRECT_HEALS, HOT_HEALS, CASTED_HEALS, ABSORB_SHIELDS, ALL_DATA, BOMB_HEALS
+
+local COMM_PREFIX = "LHC40"
+local playerGUID, playerName, playerLevel
+local playerHealModifier = 1
+local IS_BUILD30300 = tonumber((select(4, GetBuildInfo()))) >= 30300
+
+HealComm.callbacks = HealComm.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(HealComm)
+HealComm.spellData = HealComm.spellData or {}
+HealComm.hotData = HealComm.hotData or {}
+HealComm.talentData = HealComm.talentData or {}
+HealComm.itemSetsData = HealComm.itemSetsData or {}
+HealComm.glyphCache = HealComm.glyphCache or {}
+HealComm.equippedSetCache = HealComm.equippedSetCache or {}
+HealComm.guidToGroup = HealComm.guidToGroup or {}
+HealComm.guidToUnit = HealComm.guidToUnit or {}
+HealComm.pendingHeals = HealComm.pendingHeals or {}
+HealComm.tempPlayerList = HealComm.tempPlayerList or {}
+HealComm.activePets = HealComm.activePets or {}
+HealComm.activeHots = HealComm.activeHots or {}
+
+if( not HealComm.unitToPet ) then
+ HealComm.unitToPet = {["player"] = "pet"}
+ for i=1, MAX_PARTY_MEMBERS do HealComm.unitToPet["party" .. i] = "partypet" .. i end
+ for i=1, MAX_RAID_MEMBERS do HealComm.unitToPet["raid" .. i] = "raidpet" .. i end
+end
+
+local spellData, hotData, tempPlayerList, pendingHeals = HealComm.spellData, HealComm.hotData, HealComm.tempPlayerList, HealComm.pendingHeals
+local equippedSetCache, itemSetsData, talentData = HealComm.equippedSetCache, HealComm.itemSetsData, HealComm.talentData
+local activeHots, activePets = HealComm.activeHots, HealComm.activePets
+
+-- Figure out what they are now since a few things change based off of this
+local playerClass = select(2, UnitClass("player"))
+local isHealerClass = playerClass == "DRUID" or playerClass == "PRIEST" or playerClass == "SHAMAN" or playerClass == "PALADIN"
+
+-- Stolen from Threat-2.0, compresses GUIDs from 18 characters to around 8 - 9, 50%/55% savings
+-- 44 = , / 58 = : / 255 = \255 / 0 = line break / 64 = @ / 254 = FE, used for escape code so has to be escaped
+if( not HealComm.compressGUID or not HealComm.fixedCompress ) then
+ local map = {[58] = "\254\250", [64] = "\254\251", [44] = "\254\252", [255] = "\254\253", [0] = "\255", [254] = "\254\249"}
+ local function guidCompressHelper(x)
+ local a = tonumber(x, 16)
+ return map[a] or char(a)
+ end
+
+ local dfmt = "0x%02X%02X%02X%02X%02X%02X%02X%02X"
+ local function unescape(str)
+ str = gsub(str, "\255", "\000")
+ str = gsub(str, "\254\250", "\058")
+ str = gsub(str, "\254\251", "\064")
+ str = gsub(str, "\254\252", "\044")
+ str = gsub(str, "\254\253", "\255")
+ return gsub(str, "\254\249", "\254")
+ end
+
+ HealComm.fixedCompress = true
+ HealComm.compressGUID = setmetatable({}, {
+ __index = function(tbl, guid)
+ local cguid = match(guid, "0x(.*)")
+ local str = gsub(cguid, "(%x%x)", guidCompressHelper)
+
+ rawset(tbl, guid, str)
+ return str
+ end})
+
+ HealComm.decompressGUID = setmetatable({}, {
+ __index = function(tbl, str)
+ if( not str ) then return nil end
+ local usc = unescape(str)
+ local a, b, c, d, e, f, g, h = byte(usc, 1, 8)
+
+ -- Failed to decompress, silently exit
+ if( not a or not b or not c or not d or not e or not f or not g or not h ) then
+ return ""
+ end
+
+ local guid = format(dfmt, a, b, c, d, e, f, g, h)
+
+ rawset(tbl, str, guid)
+ return guid
+ end})
+end
+
+local compressGUID, decompressGUID = HealComm.compressGUID, HealComm.decompressGUID
+
+-- Handles caching of tables for variable tick spells, like Wild Growth
+if( not HealComm.tableCache ) then
+ HealComm.tableCache = setmetatable({}, {__mode = "k"})
+ function HealComm:RetrieveTable()
+ return tremove(HealComm.tableCache, 1) or {}
+ end
+
+ function HealComm:DeleteTable(tbl)
+ twipe(tbl)
+ tinsert(HealComm.tableCache, tbl)
+ end
+end
+
+-- Validation for passed arguments
+if( not HealComm.tooltip ) then
+ local tooltip = CreateFrame("GameTooltip")
+ tooltip:SetOwner(UIParent, "ANCHOR_NONE")
+ tooltip.TextLeft1 = tooltip:CreateFontString()
+ tooltip.TextRight1 = tooltip:CreateFontString()
+ tooltip:AddFontStrings(tooltip.TextLeft1, tooltip.TextRight1)
+
+ HealComm.tooltip = tooltip
+end
+
+-- So I don't have to keep matching the same numbers every time or create a local copy of every rank -> # map for locals
+if( not HealComm.rankNumbers ) then
+ HealComm.rankNumbers = setmetatable({}, {
+ __index = function(tbl, index)
+ local number = tonumber(match(index, "(%d+)")) or 1
+
+ rawset(tbl, index, number)
+ return number
+ end,
+ })
+end
+
+-- Find the spellID by the name/rank combination
+-- Need to swap this to a double table metatable something like [spellName][spellRank] so I can reduce the garbage created
+if( not HealComm.spellToID ) then
+ HealComm.spellToID = setmetatable({}, {
+ __index = function(tbl, index)
+ -- Find the spell from the spell book and cache the results!
+ local offset, numSpells = select(3, GetSpellTabInfo(GetNumSpellTabs()))
+ for id=1, (offset + numSpells) do
+ -- Match, yay!
+ local spellName, spellRank = GetSpellName(id, BOOKTYPE_SPELL)
+ local name = spellName .. spellRank
+ if( index == name ) then
+ HealComm.tooltip:SetSpell(id, BOOKTYPE_SPELL)
+ local spellID = select(3, HealComm.tooltip:GetSpell())
+ if( spellID ) then
+ rawset(tbl, index, spellID)
+ return spellID
+ end
+ end
+ end
+
+ rawset(tbl, index, false)
+ return false
+ end,
+ })
+end
+
+-- This gets filled out after data has been loaded, this is only for casted heals. Hots just directly pull from the averages as they do not increase in power with level, Cataclysm will change this though.
+if( HealComm.averageHealMT and not HealComm.fixedAverage ) then
+ HealComm.averageHealMT = nil
+end
+
+HealComm.fixedAverage = true
+HealComm.averageHeal = HealComm.averageHeal or {}
+HealComm.averageHealMT = HealComm.averageHealMT or {
+ __index = function(tbl, index)
+ local rank = HealComm.rankNumbers[index]
+ local spellData = HealComm.spellData[rawget(tbl, "spell")]
+ local spellLevel = spellData.levels[rank]
+
+ -- No increase, it doesn't scale with levely
+ if( not spellData.increase or UnitLevel("player") <= spellLevel ) then
+ rawset(tbl, index, spellData.averages[rank])
+ return spellData.averages[rank]
+ end
+
+ local average = spellData.averages[rank]
+ if( UnitLevel("level") >= MAX_PLAYER_LEVEL ) then
+ average = average + spellData.increase[rank]
+ -- Here's how this works: If a spell increases 1,000 between 70 and 80, the player is level 75 the spell is 70
+ -- it's 1000 / (80 - 70) so 100, the player learned the spell 5 levels ago which means that the spell average increases by 500
+ -- This figures out how much it increases per level and how ahead of the spells level they are to figure out how much to add
+ else
+ average = average + (UnitLevel("player") - spellLevel) * (spellData.increase[rank] / (MAX_PLAYER_LEVEL - spellLevel))
+ end
+
+ rawset(tbl, index, average)
+ return average
+ end}
+
+-- Record management, because this is getting more complicted to deal with
+local function updateRecord(pending, guid, amount, stack, endTime, ticksLeft)
+ if( pending[guid] ) then
+ local id = pending[guid]
+
+ pending[id] = guid
+ pending[id + 1] = amount
+ pending[id + 2] = stack
+ pending[id + 3] = endTime or 0
+ pending[id + 4] = ticksLeft or 0
+ else
+ pending[guid] = #(pending) + 1
+ tinsert(pending, guid)
+ tinsert(pending, amount)
+ tinsert(pending, stack)
+ tinsert(pending, endTime or 0)
+ tinsert(pending, ticksLeft or 0)
+
+ if( pending.bitType == HOT_HEALS ) then
+ activeHots[guid] = (activeHots[guid] or 0) + 1
+ HealComm.hotMonitor:Show()
+ end
+ end
+end
+
+local function getRecord(pending, guid)
+ local id = pending[guid]
+ if( not id ) then return nil end
+
+ -- amount, stack, endTime, ticksLeft
+ return pending[id + 1], pending[id + 2], pending[id + 3], pending[id + 4]
+end
+
+local function removeRecord(pending, guid)
+ local id = pending[guid]
+ if( not id ) then return nil end
+
+ -- ticksLeft, endTime, stack, amount, guid
+ tremove(pending, id + 4)
+ tremove(pending, id + 3)
+ tremove(pending, id + 2)
+ local amount = tremove(pending, id + 1)
+ tremove(pending, id)
+ pending[guid] = nil
+
+ -- Release the table
+ if( type(amount) == "table" ) then HealComm:DeleteTable(amount) end
+
+ if( pending.bitType == HOT_HEALS and activeHots[guid] ) then
+ activeHots[guid] = activeHots[guid] - 1
+ activeHots[guid] = activeHots[guid] > 0 and activeHots[guid] or nil
+ end
+
+ -- Shift any records after this ones index down 5 to account for the removal
+ for i=1, #(pending), 5 do
+ local guid = pending[i]
+ if( pending[guid] > id ) then
+ pending[guid] = pending[guid] - 5
+ end
+ end
+end
+
+local function removeRecordList(pending, inc, comp, ...)
+ for i=1, select("#", ...), inc do
+ local guid = select(i, ...)
+ guid = comp and decompressGUID[guid] or guid
+
+ local id = pending[guid]
+ -- ticksLeft, endTime, stack, amount, guid
+ tremove(pending, id + 4)
+ tremove(pending, id + 3)
+ tremove(pending, id + 2)
+ local amount = tremove(pending, id + 1)
+ tremove(pending, id)
+ pending[guid] = nil
+
+ -- Release the table
+ if( type(amount) == "table" ) then HealComm:DeleteTable(amount) end
+ end
+
+ -- Redo all the id maps
+ for i=1, #(pending), 5 do
+ pending[pending[i]] = i
+ end
+end
+
+-- Removes every mention to the given GUID
+local function removeAllRecords(guid)
+ local changed
+ for _, spells in pairs(pendingHeals) do
+ for _, pending in pairs(spells) do
+ if( pending.bitType and pending[guid] ) then
+ local id = pending[guid]
+
+ -- ticksLeft, endTime, stack, amount, guid
+ tremove(pending, id + 4)
+ tremove(pending, id + 3)
+ tremove(pending, id + 2)
+ local amount = tremove(pending, id + 1)
+ tremove(pending, id)
+ pending[guid] = nil
+
+ -- Release the table
+ if( type(amount) == "table" ) then HealComm:DeleteTable(amount) end
+
+ -- Shift everything back
+ if( #(pending) > 0 ) then
+ for i=1, #(pending), 5 do
+ local guid = pending[i]
+ if( pending[guid] > id ) then
+ pending[guid] = pending[guid] - 5
+ end
+ end
+ else
+ twipe(pending)
+ end
+
+ changed = true
+ end
+ end
+ end
+
+ activeHots[guid] = nil
+
+ if( changed ) then
+ HealComm.callbacks:Fire("HealComm_GUIDDisappeared", guid)
+ end
+end
+
+-- These are not public APIs and are purely for the wrapper to use
+HealComm.removeRecordList = removeRecordList
+HealComm.removeRecord = removeRecord
+HealComm.getRecord = getRecord
+HealComm.updateRecord = updateRecord
+
+-- Removes all pending heals, if it's a group that is causing the clear then we won't remove the players heals on themselves
+local function clearPendingHeals()
+ for casterGUID, spells in pairs(pendingHeals) do
+ for _, pending in pairs(spells) do
+ if( pending.bitType ) then
+ twipe(tempPlayerList)
+ for i=#(pending), 1, -5 do tinsert(tempPlayerList, pending[i - 4]) end
+
+ if( #(tempPlayerList) > 0 ) then
+ local spellID, bitType = pending.spellID, pending.bitType
+ twipe(pending)
+
+ HealComm.callbacks:Fire("HealComm_HealStopped", casterGUID, spellID, bitType, true, unpack(tempPlayerList))
+ end
+ end
+ end
+ end
+end
+
+-- APIs
+-- Returns the players current heaing modifier
+function HealComm:GetPlayerHealingMod()
+ return playerHealModifier or 1
+end
+
+-- Returns the current healing modifier for the GUID
+function HealComm:GetHealModifier(guid)
+ return HealComm.currentModifiers[guid] or 1
+end
+
+-- Returns whether or not the GUID has casted a heal
+function HealComm:GUIDHasHealed(guid)
+ return pendingHeals[guid] and true or nil
+end
+
+-- Returns the guid to unit table
+function HealComm:GetGUIDUnitMapTable()
+ if( not HealComm.protectedMap ) then
+ HealComm.protectedMap = setmetatable({}, {
+ __index = function(tbl, key) return HealComm.guidToUnit[key] end,
+ __newindex = function() error("This is a read only table and cannot be modified.", 2) end,
+ __metatable = false
+ })
+ end
+
+ return HealComm.protectedMap
+end
+
+-- Gets the next heal landing on someone using the passed filters
+function HealComm:GetNextHealAmount(guid, bitFlag, time, ignoreGUID)
+ local healTime, healAmount, healFrom
+ local currentTime = GetTime()
+
+ for casterGUID, spells in pairs(pendingHeals) do
+ if( not ignoreGUID or ignoreGUID ~= casterGUID ) then
+ for _, pending in pairs(spells) do
+ if( pending.bitType and band(pending.bitType, bitFlag) > 0 ) then
+ for i=1, #(pending), 5 do
+ local guid = pending[i]
+ local amount = pending[i + 1]
+ local stack = pending[i + 2]
+ local endTime = pending[i + 3]
+ endTime = endTime > 0 and endTime or pending.endTime
+
+ -- Direct heals are easy, if they match the filter then return them
+ if( ( pending.bitType == DIRECT_HEALS or pending.bitType == BOMB_HEALS ) and ( not time or endTime <= time ) ) then
+ if( not healTime or endTime < healTime ) then
+ healTime = endTime
+ healAmount = amount * stack
+ healFrom = casterGUID
+ end
+
+ -- Channeled heals and hots, have to figure out how many times it'll tick within the given time band
+ elseif( ( pending.bitType == CHANNEL_HEALS or pending.bitType == HOT_HEALS ) and ( not pending.hasVariableTicks or pending.hasVariableTicks and amount[1] ) ) then
+ local secondsLeft = time and time - currentTime or endTime - currentTime
+ local nextTick = currentTime + (secondsLeft % pending.tickInterval)
+ if( not healTime or nextTick < healTime ) then
+ healTime = nextTick
+ healAmount = not pending.hasVariableTicks and amount * stack or amount[1] * stack
+ healFrom = casterGUID
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ return healTime, healFrom, healAmount
+end
+
+-- Get the healing amount that matches the passed filters
+local function filterData(spells, filterGUID, bitFlag, time, ignoreGUID)
+ local healAmount = 0
+ local currentTime = GetTime()
+
+ for _, pending in pairs(spells) do
+ if( pending.bitType and band(pending.bitType, bitFlag) > 0 ) then
+ for i=1, #(pending), 5 do
+ local guid = pending[i]
+ if( guid == filterGUID or ignoreGUID ) then
+ local amount = pending[i + 1]
+ local stack = pending[i + 2]
+ local endTime = pending[i + 3]
+ endTime = endTime > 0 and endTime or pending.endTime
+
+ -- Direct heals are easy, if they match the filter then return them
+ if( ( pending.bitType == DIRECT_HEALS or pending.bitType == BOMB_HEALS ) and ( not time or endTime <= time ) ) then
+ healAmount = healAmount + amount * stack
+ -- Channeled heals and hots, have to figure out how many times it'll tick within the given time band
+ elseif( ( pending.bitType == CHANNEL_HEALS or pending.bitType == HOT_HEALS ) and endTime > currentTime ) then
+ local ticksLeft = pending[i + 4]
+ if( not time or time >= endTime ) then
+ if( not pending.hasVariableTicks ) then
+ healAmount = healAmount + (amount * stack) * ticksLeft
+ else
+ for _, heal in pairs(amount) do
+ healAmount = healAmount + (heal * stack)
+ end
+ end
+ else
+ local secondsLeft = endTime - currentTime
+ local bandSeconds = time - currentTime
+ local ticks = floor(min(bandSeconds, secondsLeft) / pending.tickInterval)
+ local nextTickIn = secondsLeft % pending.tickInterval
+ local fractionalBand = bandSeconds % pending.tickInterval
+ if( nextTickIn > 0 and nextTickIn < fractionalBand ) then
+ ticks = ticks + 1
+ end
+
+ if( not pending.hasVariableTicks ) then
+ healAmount = healAmount + (amount * stack) * min(ticks, ticksLeft)
+ else
+ for j=1, min(ticks, #(amount)) do
+ healAmount = healAmount + (amount[j] * stack)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ return healAmount
+end
+
+-- Gets healing amount using the passed filters
+function HealComm:GetHealAmount(guid, bitFlag, time, casterGUID)
+ local amount = 0
+ if( casterGUID and pendingHeals[casterGUID] ) then
+ amount = filterData(pendingHeals[casterGUID], guid, bitFlag, time)
+ elseif( not casterGUID ) then
+ for _, spells in pairs(pendingHeals) do
+ amount = amount + filterData(spells, guid, bitFlag, time)
+ end
+ end
+
+ return amount > 0 and amount or nil
+end
+
+-- Gets healing amounts for everyone except the player using the passed filters
+function HealComm:GetOthersHealAmount(guid, bitFlag, time)
+ local amount = 0
+ for casterGUID, spells in pairs(pendingHeals) do
+ if( casterGUID ~= playerGUID ) then
+ amount = amount + filterData(spells, guid, bitFlag, time)
+ end
+ end
+
+ return amount > 0 and amount or nil
+end
+
+function HealComm:GetCasterHealAmount(guid, bitFlag, time)
+ local amount = pendingHeals[guid] and filterData(pendingHeals[guid], nil, bitFlag, time, true) or 0
+ return amount > 0 and amount or nil
+end
+
+-- Healing class data
+-- Thanks to Gagorian (DrDamage) for letting me steal his formulas and such
+local playerCurrentRelic
+local averageHeal, rankNumbers = HealComm.averageHeal, HealComm.rankNumbers
+local guidToUnit, guidToGroup, glyphCache = HealComm.guidToUnit, HealComm.guidToGroup, HealComm.glyphCache
+
+-- UnitBuff priortizes our buffs over everyone elses when there is a name conflict, so yay for that
+local function unitHasAura(unit, name)
+ return select(8, UnitBuff(unit, name)) == "player"
+end
+
+-- Note because I always forget on the order:
+-- Talents that effective the coeffiency of spell power to healing are first and are tacked directly onto the coeffiency (Empowered Rejuvenation)
+-- Penalty modifiers (downranking/spell level too low) are applied directly to the spell power
+-- Spell power modifiers are then applied to the spell power
+-- Heal modifiers are applied after all of that
+-- Crit modifiers are applied after
+-- Any other modifiers such as Mortal Strike or Avenging Wrath are applied after everything else
+local function calculateGeneralAmount(level, amount, spellPower, spModifier, healModifier)
+ -- Apply downranking penalities for spells below 20
+ local penalty = level > 20 and 1 or (1 - ((20 - level) * 0.0375))
+
+ -- Apply further downranking penalities
+ spellPower = spellPower * (penalty * min(1, max(0, 1 - (playerLevel - level - 11) * 0.05)))
+
+ -- Apply zone modifier
+ healModifier = healModifier * HealComm.zoneHealModifier
+
+ -- Do the general factoring
+ return healModifier * (amount + (spellPower * spModifier))
+end
+
+-- For spells like Wild Growth, it's a waste to do the calculations for each tick, easier to calculate spell power now and then manually calculate it all after
+local function calculateSpellPower(level, spellPower)
+ -- Apply downranking penalities for spells below 20
+ local penalty = level > 20 and 1 or (1 - ((20 - level) * 0.0375))
+
+ -- Apply further downranking penalities
+ return spellPower * (penalty * min(1, max(0, 1 - (playerLevel - level - 11) * 0.05)))
+end
+
+-- Yes silly function, just cleaner to look at
+local function avg(a, b)
+ return (a + b) / 2
+end
+
+--[[
+ What the different callbacks do:
+
+ AuraHandler: Specific aura tracking needed for this class, who has Beacon up on them and such
+
+ ResetChargeData: Due to spell "queuing" you can't always rely on aura data for buffs that last one or two casts, for example Divine Favor (+100% crit, one spell)
+ if you cast Holy Light and queue Flash of Light the library would still see they have Divine Favor and give them crits on both spells. The reset means that the flag that indicates
+ they have the aura can be killed and if they interrupt the cast then it will call this and let you reset the flags.
+
+ What happens in terms of what the client thinks and what actually is, is something like this:
+
+ UNIT_SPELLCAST_START, Holy Light -> Divine Favor up
+ UNIT_SPELLCAST_SUCCEEDED, Holy Light -> Divine Favor up (But it was really used)
+ UNIT_SPELLCAST_START, Flash of Light -> Divine Favor up (It's not actually up but auras didn't update)
+ UNIT_AURA -> Divine Favor up (Split second where it still thinks it's up)
+ UNIT_AURA -> Divine Favor faded (Client catches up and realizes it's down)
+
+ CalculateHealing: Calculates the healing value, does all the formula calculations talent modifiers and such
+
+ CalculateHotHealing: Used specifically for calculating the heals of hots
+
+ GetHealTargets: Who the heal is going to hit, used for setting extra targets for Beacon of Light + Paladin heal or Prayer of Healing.
+ The returns should either be:
+
+ "compressedGUID1,compressedGUID2,compressedGUID3,compressedGUID4", healthAmount
+ Or if you need to set specific healing values for one GUID it should be
+ "compressedGUID1,healthAmount1,compressedGUID2,healAmount2,compressedGUID3,healAmount3", -1
+
+ The latter is for cases like Glyph of Healing Wave where you need a heal for 1,000 on A and a heal for 200 on the player for B without sending 2 events.
+ The -1 tells the library to look in the GUId list for the heal amounts
+
+ **NOTE** Any GUID returned from GetHealTargets must be compressed through a call to compressGUID[guid]
+]]
+
+local CalculateHealing, GetHealTargets, AuraHandler, CalculateHotHealing, ResetChargeData, LoadClassData, LoadRaceData
+
+-- DRUIDS
+-- All data is accurate as of 3.2.2 (build 10392)
+if( playerClass == "DRUID" ) then
+ LoadClassData = function()
+ -- Rejuvenation
+ local Rejuvenation = GetSpellInfo(774)
+ hotData[Rejuvenation] = {interval = 3,
+ levels = {4, 10, 16, 22, 28, 34, 40, 46, 52, 58, 60, 63, 69, 75, 80}, averages = {32, 56, 116, 180, 244, 304, 388, 488, 608, 756, 888, 932, 1060, 1192, 1690}}
+ -- Regrowth
+ local Regrowth = GetSpellInfo(8936)
+ hotData[Regrowth] = {interval = 3, ticks = 7, coeff = 1.316,
+ levels = {12, 18, 24, 30, 36, 42, 48, 54, 60, 65, 71, 77}, averages = {98, 175, 259, 343, 427, 546, 686, 861, 1064, 1274, 1792, 2345}}
+ -- Lifebloom
+ local Lifebloom = GetSpellInfo(33763)
+ hotData[Lifebloom] = {interval = 1, ticks = 7, coeff = 0.66626, dhCoeff = 0.34324 * 0.8, levels = {64, 72, 80}, averages = {224, 287, 371}, bomb = {480, 616, 776}}
+ -- Wild Growth
+ local WildGrowth = GetSpellInfo(48438)
+ hotData[WildGrowth] = {interval = 1, ticks = 7, coeff = 0.8056, levels = {60, 70, 75, 80}, averages = {686, 861, 1239, 1442}}
+
+ -- Regrowth
+ spellData[Regrowth] = {coeff = 0.2867,
+ levels = hotData[Regrowth].levels,
+ averages = {avg(84, 98), avg(164, 188), avg(240, 274), avg(318, 360), avg(405, 457), avg(511, 575), avg(646, 724), avg(809, 905), avg(1003, 1119), avg(1215, 1355), avg(1710, 1908), avg(2234, 2494)},
+ increase = {122, 155, 173, 180, 180, 178, 169, 156, 136, 115, 97, 23}}
+ -- Healing Touch
+ local HealingTouch = GetSpellInfo(5185)
+ spellData[HealingTouch] = {
+ levels = {1, 8, 14, 20, 26, 32, 38, 44, 50, 56, 60, 62, 69, 74, 79},
+ averages = {avg(37, 51), avg(88, 112), avg(195, 243), avg(363, 445), avg(490, 594), avg(636, 766), avg(802, 960), avg(1199, 1427), avg(1299, 1539), avg(1620, 1912), avg(1944, 2294), avg(2026, 2392), avg(2321, 2739), avg(3223, 3805), avg(3750, 4428)}}
+ -- Nourish
+ local Nourish = GetSpellInfo(50464)
+ spellData[Nourish] = {coeff = 0.358005, levels = {80}, averages = {avg(1883, 2187)}}
+ -- Tranquility
+ local Tranquility = GetSpellInfo(740)
+ spellData[Tranquility] = {coeff = 1.144681, ticks = 4, levels = {30, 40, 50, 60, 70, 75, 80}, averages = {351, 515, 765, 1097, 1518, 2598, 3035}}
+
+ -- Talent data, these are filled in later and modified on talent changes
+ -- Master Shapeshifter (Multi)
+ local MasterShapeshifter = GetSpellInfo(48411)
+ talentData[MasterShapeshifter] = {mod = 0.02, current = 0}
+ -- Gift of Nature (Add)
+ local GiftofNature = GetSpellInfo(17104)
+ talentData[GiftofNature] = {mod = 0.02, current = 0}
+ -- Empowered Touch (Add, increases spell power HT/Nourish gains)
+ local EmpoweredTouch = GetSpellInfo(33879)
+ talentData[EmpoweredTouch] = {mod = 0.2, current = 0}
+ -- Empowered Rejuvenation (Multi, this ups both the direct heal and the hot)
+ local EmpoweredRejuv = GetSpellInfo(33886)
+ talentData[EmpoweredRejuv] = {mod = 0.04, current = 0}
+ -- Genesis (Add)
+ local Genesis = GetSpellInfo(57810)
+ talentData[Genesis] = {mod = 0.01, current = 0}
+ -- Improved Rejuvenation (Add)
+ local ImprovedRejuv = GetSpellInfo(17111)
+ talentData[ImprovedRejuv] = {mod = 0.05, current = 0}
+ -- Nature's Splendor (+3s Rejuv/+6s Regrowth/+2s Lifebloom)
+ local NaturesSplendor = GetSpellInfo(57865)
+ talentData[NaturesSplendor] = {mod = 1, current = 0}
+
+ local TreeofLife = GetSpellInfo(33891)
+ local Innervate = GetSpellInfo(29166)
+
+ -- Set data
+ -- 2 piece, +6 seconds to Regrowth
+ itemSetsData["T5 Resto"] = {30216, 30217, 30219, 30220, 30221}
+ -- +5% more healing to Nourish per hot
+ itemSetsData["T7 Resto"] = {40460, 40461, 40462, 40463, 40465, 39531, 39538, 39539, 39542, 39543}
+ --itemSetsData["T8 Resto"] = {46183, 46184, 46185, 46186, 46187, 45345, 45346, 45347, 45348, 45349}
+ --itemSetsData["T9 Resto"] = {48102, 48129, 48130, 48131, 48132, 48153, 48154, 48155, 48156, 48157, 48133, 48134, 48135, 48136, 48137, 48142, 48141, 48140, 48139, 48138, 48152, 48151, 48150, 48149, 48148, 48143, 48144, 48145, 48146, 48147}
+ -- 2 piece, 30% less healing lost on WG
+ itemSetsData["T10 Resto"] = {50106, 50107, 50108, 50109, 50113, 51139, 51138, 51137, 51136, 51135, 51300, 51301, 51302, 51303, 51304}
+
+ local bloomBombIdols = {[28355] = 87, [33076] = 105, [33841] = 116, [35021] = 131, [42576] = 188, [42577] = 217, [42578] = 246, [42579] = 294, [42580] = 376, [51423] = 448}
+
+ local hotTotals, hasRegrowth = {}, {}
+ AuraHandler = function(unit, guid)
+ hotTotals[guid] = 0
+ if( unitHasAura(unit, Rejuvenation) ) then hotTotals[guid] = hotTotals[guid] + 1 end
+ if( unitHasAura(unit, Lifebloom) ) then hotTotals[guid] = hotTotals[guid] + 1 end
+ if( unitHasAura(unit, WildGrowth) ) then hotTotals[guid] = hotTotals[guid] + 1 end
+ if( unitHasAura(unit, Regrowth) ) then
+ hasRegrowth[guid] = true
+ hotTotals[guid] = hotTotals[guid] + 1
+ else
+ hasRegrowth[guid] = nil
+ end
+ end
+
+ GetHealTargets = function(bitType, guid, healAmount, spellName, hasVariableTicks)
+ -- Tranquility pulses on everyone within 30 yards, if they are in range of Innervate they'll get Tranquility
+ if( spellName == Tranquility ) then
+ local targets = compressGUID[playerGUID]
+ local playerGroup = guidToGroup[playerGUID]
+
+ for groupGUID, groupID in pairs(guidToGroup) do
+ if( groupID == playerGroup and playerGUID ~= groupGUID and not UnitHasVehicleUI(guidToUnit[groupID]) and IsSpellInRange(Innervate, guidToUnit[groupGUID]) == 1 ) then
+ targets = targets .. "," .. compressGUID[groupGUID]
+ end
+ end
+
+ return targets, healAmount
+ elseif( hasVariableTicks ) then
+ healAmount = tconcat(healAmount, "@")
+ end
+
+ return compressGUID[guid], healAmount
+ end
+
+ -- Calculate hot heals
+ local wgTicks = {}
+ CalculateHotHealing = function(guid, spellID)
+ local spellName, spellRank = GetSpellInfo(spellID)
+ local rank = HealComm.rankNumbers[spellRank]
+ local healAmount = hotData[spellName].averages[rank]
+ local spellPower = GetSpellBonusHealing()
+ local healModifier, spModifier = playerHealModifier, 1
+ local bombAmount, totalTicks
+ healModifier = healModifier + talentData[GiftofNature].current
+ healModifier = healModifier + talentData[Genesis].current
+
+ -- Master Shapeshifter does not apply directly when using Lifebloom
+ if( unitHasAura("player", TreeofLife) ) then
+ healModifier = healModifier * (1 + talentData[MasterShapeshifter].current)
+
+ -- 32387 - Idol of the Raven Godess, +44 SP while in TOL
+ if( playerCurrentRelic == 32387 ) then
+ spellPower = spellPower + 44
+ end
+ end
+
+ -- Rejuvenation
+ if( spellName == Rejuvenation ) then
+ healModifier = healModifier + talentData[ImprovedRejuv].current
+
+ -- 25643 - Harold's Rejuvenation Broach, +86 Rejuv SP
+ if( playerCurrentRelic == 25643 ) then
+ spellPower = spellPower + 86
+ -- 22398 - Idol of Rejuvenation, +50 SP to Rejuv
+ elseif( playerCurrentRelic == 22398 ) then
+ spellPower = spellPower + 50
+ end
+
+ local duration, ticks
+ if( IS_BUILD30300 ) then
+ duration = 15
+ ticks = 5
+ totalTicks = 5
+ else
+ duration = rank > 14 and 15 or 12
+ ticks = duration / hotData[spellName].interval
+ totalTicks = ticks
+ end
+
+ spellPower = spellPower * (((duration / 15) * 1.88) * (1 + talentData[EmpoweredRejuv].current))
+ spellPower = spellPower / ticks
+ healAmount = healAmount / ticks
+
+ --38366 - Idol of Pure Thoughts, +33 SP base per tick
+ if( playerCurrentRelic == 38366 ) then
+ spellPower = spellPower + 33
+ end
+
+ -- Nature's Splendor, +6 seconds
+ if( talentData[NaturesSplendor].mod >= 1 ) then totalTicks = totalTicks + 1 end
+
+ -- Regrowth
+ elseif( spellName == Regrowth ) then
+ spellPower = spellPower * (hotData[spellName].coeff * (1 + talentData[EmpoweredRejuv].current))
+ spellPower = spellPower / hotData[spellName].ticks
+ healAmount = healAmount / hotData[spellName].ticks
+
+ totalTicks = 7
+ -- Nature's Splendor, +6 seconds
+ if( talentData[NaturesSplendor].mod >= 1 ) then totalTicks = totalTicks + 2 end
+ -- T5 Resto, +6 seconds
+ if( equippedSetCache["T5 Resto"] >= 2 ) then totalTicks = totalTicks + 2 end
+
+ -- Lifebloom
+ elseif( spellName == Lifebloom ) then
+ -- Figure out the bomb heal, apparently Gift of Nature double dips and will heal 10% for the HOT + 10% again for the direct heal
+ local bombSpellPower = spellPower
+ if( playerCurrentRelic and bloomBombIdols[playerCurrentRelic] ) then
+ bombSpellPower = bombSpellPower + bloomBombIdols[playerCurrentRelic]
+ end
+
+ local bombSpell = bombSpellPower * (hotData[spellName].dhCoeff * 1.88)
+ bombAmount = ceil(calculateGeneralAmount(hotData[spellName].levels[rank], hotData[spellName].bomb[rank], bombSpell, spModifier, healModifier + talentData[GiftofNature].current))
+
+ -- Figure out the hot tick healing
+ spellPower = spellPower * (hotData[spellName].coeff * (1 + talentData[EmpoweredRejuv].current))
+ spellPower = spellPower / hotData[spellName].ticks
+ healAmount = healAmount / hotData[spellName].ticks
+ -- Figure out total ticks
+ totalTicks = 7
+
+ -- Idol of Lush Moss, +125 SP per tick
+ if( playerCurrentRelic == 40711 ) then
+ spellPower = spellPower + 125
+ -- Idol of the Emerald Queen, +47 SP per tick
+ elseif( playerCurrentRelic == 27886 ) then
+ spellPower = spellPower + 47
+ end
+
+ -- Glyph of Lifebloom, +1 second
+ if( glyphCache[54826] ) then totalTicks = totalTicks + 1 end
+ -- Nature's Splendor, +2 seconds
+ if( talentData[NaturesSplendor].mod >= 1 ) then totalTicks = totalTicks + 1 end
+ -- Wild Growth
+ elseif( spellName == WildGrowth ) then
+ spellPower = spellPower * (hotData[spellName].coeff * (1 + talentData[EmpoweredRejuv].current))
+ spellPower = spellPower / hotData[spellName].ticks
+ spellPower = calculateSpellPower(hotData[spellName].levels[rank], spellPower)
+ healAmount = healAmount / hotData[spellName].ticks
+ healModifier = healModifier * HealComm.zoneHealModifier
+
+ twipe(wgTicks)
+ local tickModifier = equippedSetCache["T10 Resto"] >= 2 and 0.70 or 1
+ local tickAmount = healAmount / hotData[spellName].ticks
+ for i=1, hotData[spellName].ticks do
+ tinsert(wgTicks, ceil(healModifier * ((healAmount + tickAmount * (3 - (i - 1) * tickModifier)) + (spellPower * spModifier))))
+ end
+
+ return HOT_HEALS, wgTicks, hotData[spellName].ticks, hotData[spellName].interval, nil, true
+ end
+
+ healAmount = calculateGeneralAmount(hotData[spellName].levels[rank], healAmount, spellPower, spModifier, healModifier)
+ return HOT_HEALS, ceil(healAmount), totalTicks, hotData[spellName].interval, bombAmount
+ end
+
+ -- Calcualte direct and channeled heals
+ CalculateHealing = function(guid, spellName, spellRank)
+ local healAmount = averageHeal[spellName][spellRank]
+ local spellPower = GetSpellBonusHealing()
+ local healModifier, spModifier = playerHealModifier, 1
+ local rank = HealComm.rankNumbers[spellRank]
+
+ -- Gift of Nature
+ healModifier = healModifier + talentData[GiftofNature].current
+
+ -- Master Shapeshifter does not apply directly when using Lifebloom
+ if( unitHasAura("player", TreeofLife) ) then
+ healModifier = healModifier * (1 + talentData[MasterShapeshifter].current)
+
+ -- 32387 - Idol of the Raven Godess, +44 SP while in TOL
+ if( playerCurrentRelic == 32387 ) then
+ spellPower = spellPower + 44
+ end
+ end
+
+ -- Regrowth
+ if( spellName == Regrowth ) then
+ -- Glyph of Regrowth - +20% if target has Regrowth
+ if( glyphCache[54743] and hasRegrowth[guid] ) then
+ healModifier = healModifier * 1.20
+ end
+
+ spellPower = spellPower * ((spellData[spellName].coeff * 1.88) * (1 + talentData[EmpoweredRejuv].current))
+ -- Nourish
+ elseif( spellName == Nourish ) then
+ -- 46138 - Idol of Flourishing Life, +187 Nourish SP
+ if( playerCurrentRelic == 46138 ) then
+ spellPower = spellPower + 187
+ end
+
+ -- Apply any hot specific bonuses
+ local hots = hotTotals[guid]
+ if( hots and hots > 0 ) then
+ local bonus = 1.20
+
+ -- T7 Resto, +5% healing per each of the players hot on their target
+ if( equippedSetCache["T7 Resto"] >= 2 ) then
+ bonus = bonus + 0.05 * hots
+ end
+
+ -- Glyph of Nourish - 6% per HoT
+ if( glyphCache[62971] ) then
+ bonus = bonus + 0.06 * hots
+ end
+
+ healModifier = healModifier * bonus
+ end
+
+ spellPower = spellPower * ((spellData[spellName].coeff * 1.88) + talentData[EmpoweredTouch].spent * 0.10)
+ -- Healing Touch
+ elseif( spellName == HealingTouch ) then
+ -- Glyph of Healing Touch, -50% healing
+ if( glyphCache[54825] ) then
+ healModifier = healModifier - 0.50
+ end
+
+ -- Idol of the Avian Heart, +136 baseh ealing
+ if( playerCurrentRelic == 28568 ) then
+ healAmount = healAmount + 136
+ -- Idol of Health, +100 base healing
+ elseif( playerCurrentRelic == 22399 ) then
+ healAmount = healAmount + 100
+ end
+
+ -- Rank 1 - 3: 1.5/2/2.5 cast time, Rank 4+: 3 cast time
+ local castTime = rank > 3 and 3 or rank == 3 and 2.5 or rank == 2 and 2 or 1.5
+ spellPower = spellPower * (((castTime / 3.5) * 1.88) + talentData[EmpoweredTouch].current)
+
+ -- Tranquility
+ elseif( spellName == Tranquility ) then
+ healModifier = healModifier + talentData[Genesis].current
+
+ spellPower = spellPower * ((spellData[spellName].coeff * 1.88) * (1 + talentData[EmpoweredRejuv].current))
+ spellPower = spellPower / spellData[spellName].ticks
+ end
+
+ healAmount = calculateGeneralAmount(spellData[spellName].levels[rank], healAmount, spellPower, spModifier, healModifier)
+
+ -- 100% chance to crit with Nature, this mostly just covers fights like Loatheb where you will basically have 100% crit
+ if( GetSpellCritChance(4) >= 100 ) then
+ healAmount = healAmount * 1.50
+ end
+
+ if( spellData[spellName].ticks ) then
+ return CHANNEL_HEALS, ceil(healAmount), spellData[spellName].ticks, spellData[spellName].ticks
+ end
+
+ return DIRECT_HEALS, ceil(healAmount)
+ end
+ end
+end
+
+-- PALADINS
+-- All data is accurate as of 3.2.2 (build 10392)
+if( playerClass == "PALADIN" ) then
+ LoadClassData = function()
+ -- Hot data, this is just so it realizes that FoL can be a hot so it will call the calculator
+ --local FlashofLight = GetSpellInfo(19750)
+ --hotData[FlashofLight] = true
+
+ -- Spell data
+ -- Holy Light
+ local HolyLight = GetSpellInfo(635)
+ spellData[HolyLight] = {coeff = 2.5 / 3.5 * 1.25,
+ levels = {1, 6, 14, 22, 30, 38, 46, 54, 60, 62, 70, 75, 80},
+ averages = {avg(50, 60), avg(96, 116), avg(203, 239), avg(397, 455), avg(628, 708), avg(894, 998), avg(1209, 1349), avg(1595, 1777), avg(2034, 2266), avg(2232, 2486), avg(2818, 3138), avg(4199, 4677), avg(4888, 5444)},
+ increase = {63, 81, 112, 139, 155, 159, 156, 135, 116, 115, 70, 52, 0}}
+ -- Flash of Light
+ local FlashofLight = GetSpellInfo(19750)
+ spellData[FlashofLight] = {coeff = 1.5 / 3.5 * 1.25,
+ levels = {20, 26, 34, 42, 50, 58, 66, 74, 79},
+ averages = {avg(81, 93), avg(124, 144), avg(189, 211), avg(256, 288), avg(346, 390), avg(445, 499), avg(588, 658), avg(682, 764), avg(785, 879)},
+ increase = {60, 70, 73, 72, 66, 57, 42, 20, 3}}
+
+ -- Talent data
+ -- Need to figure out a way of supporting +6% healing from imp devo aura, might not be able to
+ -- Healing Light (Add)
+ local HealingLight = GetSpellInfo(20237)
+ talentData[HealingLight] = {mod = 0.04, current = 0}
+ -- Divinity (Add)
+ local Divinity = GetSpellInfo(63646)
+ talentData[Divinity] = {mod = 0.01, current = 0}
+ -- Touched by the Light (Add?)
+ local TouchedbytheLight = GetSpellInfo(53592)
+ talentData[TouchedbytheLight] = {mod = 0.10, current = 0}
+ -- 100% of your heal on someone within range of your beacon heals the beacon target too
+ local BeaconofLight = GetSpellInfo(53563)
+ -- 100% chance to crit
+ local DivineFavor = GetSpellInfo(20216)
+ -- Seal of Light + Glyph = 5% healing
+ local SealofLight = GetSpellInfo(20165)
+ -- Divine Illumination, used in T10 holy
+ local DivineIllumination = GetSpellInfo(31842)
+
+ local flashLibrams = {[42616] = 436, [42615] = 375, [42614] = 331, [42613] = 293, [42612] = 204, [28592] = 89, [25644] = 79, [23006] = 43, [23201] = 28}
+ local holyLibrams = {[45436] = 160, [40268] = 141, [28296] = 47}
+ local flashSPLibrams = {[51472] = 510}
+
+ -- Holy Shock crits put a hot that heals for 15% of the HS over 9s
+ --itemSetsData["T8 Holy"] = { 45370, 45371, 45372, 45373, 45374, 46178, 46179, 46180, 46181, 46182 }
+ -- +100% to the hot when using Flash of Light + Sacred Shield
+ --itemSetsData["T9 Holy"] = { 48595, 48596, 48597, 48598, 48599, 48564, 48566, 48568, 48572, 48574, 48593, 48591, 48592, 48590, 48594, 48588, 48586, 48587, 48585, 48589, 48576, 48578, 48577, 48579, 48575, 48583, 48581, 48582, 48580, 48584}
+ itemSetsData["T10 Holy"] = {50865, 50866, 50867, 50868, 50869, 51270, 51271, 51272, 51273, 51274, 51165, 51166, 51167, 51168, 51169}
+
+ -- Need the GUID of whoever has beacon on them so we can make sure they are visible to us and so we can check the mapping
+ local activeBeaconGUID, hasDivineFavor
+ AuraHandler = function(unit, guid)
+ if( unitHasAura(unit, BeaconofLight) ) then
+ activeBeaconGUID = guid
+ elseif( activeBeaconGUID == guid ) then
+ activeBeaconGUID = nil
+ end
+
+ -- Check Divine Favor
+ if( unit == "player" ) then
+ hasDivineFavor = unitHasAura("player", DivineFavor)
+ end
+ end
+
+ ResetChargeData = function(guid)
+ hasDivineFavor = unitHasAura("player", DivineFavor)
+ end
+
+ -- Check for beacon when figuring out who to heal
+ GetHealTargets = function(bitType, guid, healAmount, spellName, hasVariableTicks)
+ if( activeBeaconGUID and activeBeaconGUID ~= guid and guidToUnit[activeBeaconGUID] and UnitIsVisible(guidToUnit[activeBeaconGUID]) ) then
+ return format("%s,%s", compressGUID[guid], compressGUID[activeBeaconGUID]), healAmount
+ elseif( hasVariableTicks ) then
+ healAmount = tconcat(healAmount, "@")
+ end
+
+ return compressGUID[guid], healAmount
+ end
+
+ -- If only every other class was as easy as Paladins
+ CalculateHealing = function(guid, spellName, spellRank)
+ local healAmount = averageHeal[spellName][spellRank]
+ local spellPower = GetSpellBonusHealing()
+ local healModifier, spModifier = playerHealModifier, 1
+ local rank = HealComm.rankNumbers[spellRank]
+
+ -- Glyph of Seal of Light, +5% healing if the player has Seal of Light up
+ if( glyphCache[54943] and unitHasAura("player", SealofLight) ) then
+ healModifier = healModifier + 0.05
+ end
+
+ healModifier = healModifier + talentData[HealingLight].current
+ healModifier = healModifier * (1 + talentData[Divinity].current)
+
+ -- Apply extra spell power based on libram
+ if( playerCurrentRelic ) then
+ if( spellName == HolyLight and holyLibrams[playerCurrentRelic] ) then
+ healAmount = healAmount + (holyLibrams[playerCurrentRelic] * 0.805)
+ elseif( spellName == FlashofLight and flashLibrams[playerCurrentRelic] ) then
+ healAmount = healAmount + (flashLibrams[playerCurrentRelic] * 0.805)
+ elseif( spellName == FlashofLight and flashSPLibrams[playerCurrentRelic] ) then
+ spellPower = spellPower + flashSPLibrams[playerCurrentRelic]
+ end
+ end
+
+ -- +35% healing while Divine Illumination is active
+ if( equippedSetCache["T10 Holy"] >= 2 and unitHasAura("player", DivineIllumination) ) then
+ healModifier = healModifier * 1.35
+ end
+
+ -- Normal calculations
+ spellPower = spellPower * (spellData[spellName].coeff * 1.88)
+ healAmount = calculateGeneralAmount(spellData[spellName].levels[rank], healAmount, spellPower, spModifier, healModifier)
+
+ -- Divine Favor, 100% chance to crit
+ -- ... or the player has over a 100% chance to crit with Holy spells
+ if( hasDivineFavor or GetSpellCritChance(2) >= 100 ) then
+ hasDivineFavor = nil
+ healAmount = healAmount * (1.50 * (1 + talentData[TouchedbytheLight].current))
+ end
+
+ return DIRECT_HEALS, ceil(healAmount)
+ end
+ end
+end
+
+-- PRIESTS
+-- Accurate as of 3.2.2 (build 10392)
+if( playerClass == "PRIEST" ) then
+ LoadClassData = function()
+ -- Hot data
+ local Renew = GetSpellInfo(139)
+ hotData[Renew] = {coeff = 1, interval = 3, ticks = 5, levels = {8, 14, 20, 26, 32, 38, 44, 50, 56, 60, 65, 70, 75, 80}, averages = {45, 100, 175, 245, 315, 400, 510, 650, 810, 970, 1010, 1110, 1235, 1400}}
+ --local GlyphofPoH = GetSpellInfo(56161)
+ --hotData[GlyphofPoH] = {isMulti = true, interval = 3}
+
+ -- Spell data
+ -- Greater Heal
+ local GreaterHeal = GetSpellInfo(2060)
+ spellData[GreaterHeal] = {coeff = 3 / 3.5, levels = {40, 46, 52, 58, 60, 63, 68, 73, 78}, increase = {204, 197, 184, 165, 162, 142, 111, 92, 30},
+ averages = {avg(899, 1013), avg(1149, 1289), avg(1437, 1609), avg(1798, 2006), avg(1966, 2194), avg(2074, 2410), avg(2394, 2784), avg(3395, 3945), avg(3950, 4590)}}
+ -- Prayer of Healing
+ local PrayerofHealing = GetSpellInfo(596)
+ spellData[PrayerofHealing] = {coeff = 0.2798, levels = {30, 40, 50, 60, 60, 68, 76}, increase = {65, 64, 60, 48, 50, 33, 18},
+ averages = {avg(301, 321), avg(444, 472), avg(657, 695), avg(939, 991), avg(997, 1053), avg(1246, 1316), avg(2091, 2209)}}
+ -- Flash Heal
+ local FlashHeal = GetSpellInfo(2061)
+ spellData[FlashHeal] = {coeff = 1.5 / 3.5, levels = {20, 26, 32, 38, 44, 52, 58, 61, 67, 73, 79}, increase = {114, 118, 120, 117, 118, 111, 100, 89, 67, 56, 9},
+ averages = {avg(193, 237), avg(258, 314), avg(327, 393), avg(400, 478), avg(518, 616), avg(644, 764), avg(812, 958), avg(913, 1059), avg(1101, 1279), avg(1578, 1832), avg(1887, 2198)}}
+ -- Binding Heal
+ local BindingHeal = GetSpellInfo(32546)
+ spellData[BindingHeal] = {coeff = 1.5 / 3.5, levels = {64, 72, 78}, averages = {avg(1042, 1338), avg(1619, 2081), avg(1952, 2508)}, increase = {30, 24, 7}}
+ -- Penance
+ local Penance = GetSpellInfo(53007)
+ spellData[Penance] = {coeff = 0.857, ticks = 3, levels = {60, 70, 75, 80}, averages = {avg(670, 756), avg(805, 909), avg(1278, 1442), avg(1484, 1676)}}
+ -- Heal
+ local Heal = GetSpellInfo(2054)
+ spellData[Heal] = {coeff = 3 / 3.5, levels = {16, 22, 28, 34}, averages = {avg(295, 341), avg(429, 491), avg(566, 642), avg(712, 804)}, increase = {153, 185, 208, 207}}
+ -- Lesser Heal
+ local LesserHeal = GetSpellInfo(2050)
+ spellData[LesserHeal] = {levels = {1, 4, 10}, averages = {avg(46, 56), avg(71, 85), avg(135, 157)}, increase = {71, 83, 112}}
+
+ -- Talent data
+ local Grace = GetSpellInfo(47517)
+ -- Spiritual Healing (Add)
+ local SpiritualHealing = GetSpellInfo(14898)
+ talentData[SpiritualHealing] = {mod = 0.02, current = 0}
+ -- Empowered Healing (Add, also 0.04 for FH/BH)
+ local EmpoweredHealing = GetSpellInfo(33158)
+ talentData[EmpoweredHealing] = {mod = 0.08, current = 0}
+ -- Blessed Resilience (Add)
+ local BlessedResilience = GetSpellInfo(33142)
+ talentData[BlessedResilience] = {mod = 0.01, current = 0}
+ -- Focused Power (Add)
+ local FocusedPower = GetSpellInfo(33190)
+ talentData[FocusedPower] = {mod = 0.02, current = 0}
+ -- Divine Providence (Add)
+ local DivineProvidence = GetSpellInfo(47567)
+ talentData[DivineProvidence] = {mod = 0.02, current = 0}
+ -- Improved Renew (Add)
+ local ImprovedRenew = GetSpellInfo(14908)
+ talentData[ImprovedRenew] = {mod = 0.05, current = 0}
+ -- Empowered Renew (Multi, spell power)
+ local EmpoweredRenew = GetSpellInfo(63534)
+ talentData[EmpoweredRenew] = {mod = 0.05, current = 0}
+ -- Twin Disciplines (Add)
+ local TwinDisciplines = GetSpellInfo(47586)
+ talentData[TwinDisciplines] = {mod = 0.01, current = 0}
+
+ -- Keep track of who has grace on them
+ local activeGraceGUID, activeGraceModifier
+ AuraHandler = function(unit, guid)
+ local stack, _, _, _, caster = select(4, UnitBuff(unit, Grace))
+ if( caster == "player" ) then
+ activeGraceModifier = stack * 0.03
+ activeGraceGUID = guid
+ elseif( activeGraceGUID == guid ) then
+ activeGraceGUID = nil
+ end
+ end
+
+ -- Check for beacon when figuring out who to heal
+ GetHealTargets = function(bitType, guid, healAmount, spellName, hasVariableTicks)
+ if( spellName == BindingHeal ) then
+ return format("%s,%s", compressGUID[guid], compressGUID[playerGUID]), healAmount
+ elseif( spellName == PrayerofHealing ) then
+ local targets = compressGUID[guid]
+ local group = guidToGroup[guid]
+
+ for groupGUID, id in pairs(guidToGroup) do
+ local unit = guidToUnit[groupGUID]
+ if( id == group and guid ~= groupGUID and UnitIsVisible(unit) and not UnitHasVehicleUI(unit) ) then
+ targets = targets .. "," .. compressGUID[groupGUID]
+ end
+ end
+
+ return targets, healAmount
+ elseif( hasVariableTicks ) then
+ healAmount = tconcat(healAmount, "@")
+ end
+
+ return compressGUID[guid], healAmount
+ end
+
+ CalculateHotHealing = function(guid, spellID)
+ local spellName, spellRank = GetSpellInfo(spellID)
+ local rank = HealComm.rankNumbers[spellRank]
+ local healAmount = hotData[spellName].averages[rank]
+ local spellPower = GetSpellBonusHealing()
+ local healModifier, spModifier = playerHealModifier, 1
+ local totalTicks
+
+ -- Add grace if it's active on them
+ if( activeGraceGUID == guid and activeGraceModifier ) then
+ healModifier = healModifier + activeGraceModifier
+ end
+
+ healModifier = healModifier + talentData[FocusedPower].current
+ healModifier = healModifier + talentData[BlessedResilience].current
+ healModifier = healModifier + talentData[SpiritualHealing].current
+
+ if( spellName == Renew ) then
+ healModifier = healModifier + talentData[ImprovedRenew].current
+ healModifier = healModifier + talentData[TwinDisciplines].current
+
+ -- Glyph of Renew, one less tick for +25% healing per tick. As this heals the same just faster, it has to be a flat 25% modifier
+ if( glyphCache[55674] ) then
+ healModifier = healModifier + 0.25
+ totalTicks = 4
+ else
+ totalTicks = 5
+ end
+
+ spellPower = spellPower * ((hotData[spellName].coeff * 1.88) * (1 + (talentData[EmpoweredRenew].current)))
+ spellPower = spellPower / hotData[spellName].ticks
+ healAmount = healAmount / hotData[spellName].ticks
+
+ end
+
+ healAmount = calculateGeneralAmount(hotData[spellName].levels[rank], healAmount, spellPower, spModifier, healModifier)
+ return HOT_HEALS, ceil(healAmount), totalTicks, hotData[spellName].interval
+ end
+
+ -- If only every other class was as easy as Paladins
+ CalculateHealing = function(guid, spellName, spellRank)
+ local healAmount = averageHeal[spellName][spellRank]
+ local rank = HealComm.rankNumbers[spellRank]
+ local spellPower = GetSpellBonusHealing()
+ local healModifier, spModifier = playerHealModifier, 1
+
+ -- Add grace if it's active on them
+ if( activeGraceGUID == guid ) then
+ healModifier = healModifier + activeGraceModifier
+ end
+
+ healModifier = healModifier + talentData[FocusedPower].current
+ healModifier = healModifier + talentData[BlessedResilience].current
+ healModifier = healModifier + talentData[SpiritualHealing].current
+
+ -- Greater Heal
+ if( spellName == GreaterHeal ) then
+ spellPower = spellPower * ((spellData[spellName].coeff * 1.88) * (1 + talentData[EmpoweredHealing].current))
+ -- Flash Heal
+ elseif( spellName == FlashHeal ) then
+ spellPower = spellPower * ((spellData[spellName].coeff * 1.88) * (1 + talentData[EmpoweredHealing].spent * 0.04))
+ -- Binding Heal
+ elseif( spellName == BindingHeal ) then
+ healModifier = healModifier + talentData[DivineProvidence].current
+ spellPower = spellPower * ((spellData[spellName].coeff * 1.88) * (1 + talentData[EmpoweredHealing].spent * 0.04))
+ -- Penance
+ elseif( spellName == Penance ) then
+ spellPower = spellPower * (spellData[spellName].coeff * 1.88)
+ spellPower = spellPower / spellData[spellName].ticks
+ -- Prayer of Heaing
+ elseif( spellName == PrayerofHealing ) then
+ healModifier = healModifier + talentData[DivineProvidence].current
+ spellPower = spellPower * (spellData[spellName].coeff * 1.88)
+ -- Heal
+ elseif( spellName == Heal ) then
+ spellPower = spellPower * (spellData[spellName].coeff * 1.88)
+ -- Lesser Heal
+ elseif( spellName == LesserHeal ) then
+ local castTime = rank > 3 and 2.5 or rank == 2 and 2 or 1.5
+ spellPower = spellPower * ((castTime / 3.5) * 1.88)
+ end
+
+ healAmount = calculateGeneralAmount(spellData[spellName].levels[rank], healAmount, spellPower, spModifier, healModifier)
+
+ -- Player has over a 100% chance to crit with Holy spells
+ if( GetSpellCritChance(2) >= 100 ) then
+ healAmount = healAmount * 1.50
+ end
+
+ -- Penance ticks 3 times, the player will see all 3 ticks, everyone else should only see the last 2
+ if( spellName == Penance ) then
+ return CHANNEL_HEALS, ceil(healAmount), 2, 3
+ end
+
+ return DIRECT_HEALS, ceil(healAmount)
+ end
+ end
+end
+
+-- SHAMANS
+-- All spells accurate as of 3.2.2 (build 10392)
+if( playerClass == "SHAMAN" ) then
+ LoadClassData = function()
+ -- Hot data
+ -- Riptide
+ local Riptide = GetSpellInfo(61295)
+ hotData[Riptide] = {interval = 3, ticks = 5, coeff = 0.50, levels = {60, 70, 75, 80}, averages = {665, 885, 1435, 1670}}
+ -- Earthliving Weapon proc
+ local Earthliving = GetSpellInfo(52000)
+ hotData[Earthliving] = {interval = 3, ticks = 4, coeff = 0.80, levels = {30, 40, 50, 60, 70, 80}, averages = {116, 160, 220, 348, 456, 652}}
+
+ -- Spell data
+ -- Chain Heal
+ local ChainHeal = GetSpellInfo(1064)
+ spellData[ChainHeal] = {coeff = 2.5 / 3.5, levels = {40, 46, 54, 61, 68, 74, 80}, increase = {100, 95, 85, 72, 45, 22, 0},
+ averages = {avg(320, 368), avg(405, 465), avg(551, 629), avg(605, 691), avg(826, 942), avg(906, 1034), avg(1055, 1205)}}
+ -- Healing Wave
+ local HealingWave = GetSpellInfo(331)
+ spellData[HealingWave] = {levels = {1, 6, 12, 18, 24, 32, 40, 48, 56, 60, 63, 70, 75, 80},
+ averages = {avg(34, 44), avg(64, 78), avg(129, 155), avg(268, 316), avg(376, 440), avg(536, 622), avg(740, 854), avg(1017, 1167), avg(1367, 1561), avg(1620, 1850), avg(1725, 1969), avg(2134, 2438), avg(2624, 2996), avg(3034, 3466)},
+ increase = {55, 74, 102, 142, 151, 158, 156, 150, 132, 110, 107, 71, 40, 0}}
+ -- Lesser Healing Wave
+ local LesserHealingWave = GetSpellInfo(8004)
+ spellData[LesserHealingWave] = {coeff = 1.5 / 3.5, levels = {20, 28, 36, 44, 52, 60, 66, 72, 77}, increase = {102, 109, 110, 108, 100, 84, 58, 40, 18},
+ averages = {avg(162, 186), avg(247, 281), avg(337, 381), avg(458, 514), avg(631, 705), avg(832, 928), avg(1039, 1185), avg(1382, 1578), avg(1606, 1834)}}
+
+ -- Talent data
+ local EarthShield = GetSpellInfo(49284)
+ -- Improved Chain Heal (Multi)
+ local ImpChainHeal = GetSpellInfo(30872)
+ talentData[ImpChainHeal] = {mod = 0.10, current = 0}
+ -- Tidal Waves (Add, this is a buff)
+ local TidalWaves = GetSpellInfo(51566)
+ talentData[TidalWaves] = {mod = 0.04, current = 0}
+ -- Healing Way (Multi, this goes from 8 -> 16 -> 25 so have to manually do the conversion)
+ local HealingWay = GetSpellInfo(29206)
+ talentData[HealingWay] = {mod = 0, current = 0}
+ -- Purification (Add)
+ local Purification = GetSpellInfo(16178)
+ talentData[Purification] = {mod = 0.02, current = 0}
+
+ -- Set bonuses
+ -- T7 Resto 4 piece, +5% healing on Chain Heal and Healing Wave
+ itemSetsData["T7 Resto"] = {40508, 40509, 40510, 40512, 40513, 39583, 39588, 39589, 39590, 39591}
+ -- T9 Resto 2 piece, +20% healing to Riptide
+ itemSetsData["T9 Resto"] = {48280, 48281, 48282, 48283, 48284, 48295, 48296, 48297, 48298, 48299, 48301, 48302, 48303, 48304, 48300, 48306, 48307, 48308, 48309, 48305, 48286, 48287, 48288, 48289, 48285, 48293, 48292, 48291, 48290, 48294}
+
+ -- Totems
+ local lhwTotems = {[42598] = 320, [42597] = 267, [42596] = 236, [42595] = 204, [25645] = 79, [22396] = 80, [23200] = 53}
+ local chTotems = {[45114] = 243, [38368] = 102, [28523] = 87}
+
+ -- Keep track of who has riptide on them
+ local riptideData, earthshieldList = {}, {}
+ AuraHandler = function(unit, guid)
+ riptideData[guid] = unitHasAura(unit, Riptide) and true or nil
+
+ -- Currently, Glyph of Lesser Healing Wave + Any Earth Shield increase the healing not just the players own
+ if( UnitBuff(unit, EarthShield) ) then
+ earthshieldList[guid] = true
+ elseif( earthshieldList[guid] ) then
+ earthshieldList[guid] = nil
+ end
+ end
+
+ -- Cast was interrupted, recheck if we still have the auras up
+ ResetChargeData = function(guid)
+ riptideData[guid] = guidToUnit[guid] and unitHasAura(guidToUnit[guid], Riptide) and true or nil
+ end
+
+ -- Lets a specific override on how many people this will hit
+ GetHealTargets = function(bitType, guid, healAmount, spellName, hasVariableTicks)
+ -- Glyph of Healing Wave, heals you for 20% of your heal when you heal someone else
+ if( glyphCache[55440] and guid ~= playerGUID and spellName == HealingWave ) then
+ return format("%s,%d,%s,%d", compressGUID[guid], healAmount, compressGUID[playerGUID], healAmount * 0.20), -1
+ elseif( hasVariableTicks ) then
+ healAmount = tconcat(healAmount, "@")
+ end
+
+ return compressGUID[guid], healAmount
+ end
+
+ CalculateHotHealing = function(guid, spellID)
+ local spellName, spellRank = GetSpellInfo(spellID)
+ local rank = HealComm.rankNumbers[spellRank]
+ local healAmount = hotData[spellName].averages[rank]
+ local spellPower = GetSpellBonusHealing()
+ local healModifier, spModifier = playerHealModifier, 1
+ local totalTicks
+
+ healModifier = healModifier + talentData[Purification].current
+
+ -- Riptide
+ if( spellName == Riptide ) then
+ if( equippedSetCache["T9 Resto"] >= 2 ) then
+ spModifier = spModifier * 1.20
+ end
+
+ spellPower = spellPower * (hotData[spellName].coeff * 1.88)
+ spellPower = spellPower / hotData[spellName].ticks
+ healAmount = healAmount / hotData[spellName].ticks
+
+ totalTicks = hotData[spellName].ticks
+ -- Glyph of Riptide, +6 seconds
+ if( glyphCache[63273] ) then totalTicks = totalTicks + 2 end
+
+ -- Earthliving Weapon
+ elseif( spellName == Earthliving ) then
+ spellPower = (spellPower * (hotData[spellName].coeff * 1.88) * 0.45)
+ spellPower = spellPower / hotData[spellName].ticks
+ healAmount = healAmount / hotData[spellName].ticks
+
+ totalTicks = hotData[spellName].ticks
+ end
+
+ healAmount = calculateGeneralAmount(hotData[spellName].levels[rank], healAmount, spellPower, spModifier, healModifier)
+ return HOT_HEALS, healAmount, totalTicks, hotData[spellName].interval
+ end
+
+
+ -- If only every other class was as easy as Paladins
+ CalculateHealing = function(guid, spellName, spellRank)
+ local healAmount = averageHeal[spellName][spellRank]
+ local rank = HealComm.rankNumbers[spellRank]
+ local spellPower = GetSpellBonusHealing()
+ local healModifier, spModifier = playerHealModifier, 1
+
+ healModifier = healModifier + talentData[Purification].current
+
+ -- Chain Heal
+ if( spellName == ChainHeal ) then
+ healModifier = healModifier * (1 + talentData[ImpChainHeal].current)
+ healAmount = healAmount + (playerCurrentRelic and chTotems[playerCurrentRelic] or 0)
+
+ if( equippedSetCache["T7 Resto"] >= 4 ) then
+ healModifier = healModifier * 1.05
+ end
+
+ -- Add +25% from Riptide being up and reset the flag
+ if( riptideData[guid] ) then
+ healModifier = healModifier * 1.25
+ riptideData[guid] = nil
+ end
+
+ spellPower = spellPower * (spellData[spellName].coeff * 1.88)
+ -- Heaing Wave
+ elseif( spellName == HealingWave ) then
+ healModifier = healModifier * (talentData[HealingWay].spent == 3 and 1.25 or talentData[HealingWay].spent == 2 and 1.16 or talentData[HealingWay].spent == 1 and 1.08 or 1)
+
+ if( equippedSetCache["T7 Resto"] >= 4 ) then
+ healModifier = healModifier * 1.05
+ end
+
+ -- Totem of Spontaneous Regrowth, +88 Spell Power to Healing Wave
+ if( playerCurrentRelic == 27544 ) then
+ spellPower = spellPower + 88
+ end
+
+ local castTime = rank > 3 and 3 or rank == 3 and 2.5 or rank == 2 and 2 or 1.5
+ spellPower = spellPower * (((castTime / 3.5) * 1.88) + talentData[TidalWaves].current)
+
+ -- Lesser Healing Wave
+ elseif( spellName == LesserHealingWave ) then
+ -- Glyph of Lesser Healing Wave, +20% healing on LHW if target has ES up
+ if( glyphCache[55438] and earthshieldList[guid] ) then
+ healModifier = healModifier * 1.20
+ end
+
+ spellPower = spellPower + (playerCurrentRelic and lhwTotems[playerCurrentRelic] or 0)
+ spellPower = spellPower * ((spellData[spellName].coeff * 1.88) + talentData[TidalWaves].spent * 0.02)
+ end
+
+ healAmount = calculateGeneralAmount(spellData[spellName].levels[rank], healAmount, spellPower, spModifier, healModifier)
+
+ -- Player has over a 100% chance to crit with Nature spells
+ if( GetSpellCritChance(4) >= 100 ) then
+ healAmount = healAmount * 1.50
+ end
+
+ -- Apply the final modifier of any MS or self heal increasing effects
+ return DIRECT_HEALS, ceil(healAmount)
+ end
+ end
+end
+
+if( select(2, UnitRace("player")) == "Draenei") or true then
+ local GetSpellBonusDamage = GetSpellBonusDamage
+ local UnitAttackPower = UnitAttackPower
+ local UnitRangedAttackPower = UnitRangedAttackPower
+
+ LoadRaceData = function()
+ local naaruClassSpells = {
+ [28880] = "WARRIOR",
+ [59542] = "PALADIN",
+ [59543] = "HUNTER",
+ [59544] = "PRIEST",
+ [59545] = "DEATHKNIGHT",
+ [59547] = "SHAMAN",
+ [59548] = "MAGE",
+ }
+ local naaruSpellID, naaruSpellName
+
+ for spellID, class in pairs(naaruClassSpells) do
+ if playerClass == class then
+ naaruSpellID = spellID
+ naaruSpellName = GetSpellInfo(spellID)
+ end
+ end
+
+ if not (naaruSpellID and naaruSpellName) then return end
+
+ hotData[naaruSpellName] = {interval = 3, ticks = 5}
+
+ local FocusedPower, BlessedResilience
+ local Divinity, DivineIllumination
+
+ if playerClass == "PRIEST" then
+ FocusedPower = GetSpellInfo(33190)
+ BlessedResilience = GetSpellInfo(33142)
+ elseif playerClass == "PALADIN" then
+ Divinity = GetSpellInfo(63646)
+ DivineIllumination = GetSpellInfo(31842)
+ end
+
+ local CalculateHotHealing_Naaru = function(guid, spellID)
+ local healAmount = playerLevel * 15 + 35
+ local spellPower, spellModifier
+
+ if playerClass == "MAGE" or playerClass == "PRIEST" then
+ spellPower = GetSpellBonusDamage(2)
+ spellModifier = 1.885
+ elseif playerClass == "PALADIN" or playerClass == "SHAMAN" then
+ local apBase, apPosBuff, apNegBuff = UnitAttackPower("player")
+ local meleeAttackPower = apBase + apPosBuff + apNegBuff
+ local holySpellPower = GetSpellBonusDamage(2)
+
+ if (meleeAttackPower * 1.1) > (holySpellPower * 1.885) then
+ spellPower = meleeAttackPower
+ spellModifier = 1.1
+ else
+ spellPower = holySpellPower
+ spellModifier = 1.885
+ end
+ else
+ local apBase, apPosBuff, apNegBuff = UnitAttackPower("player")
+ local meleeAttackPower = apBase + apPosBuff + apNegBuff
+
+ local rapBase, rapPosBuff, rapNegBuff = UnitRangedAttackPower("player")
+ local rangedAttackPower = rapBase + rapPosBuff + rapNegBuff
+
+ spellModifier = 1.1
+
+ if (meleeAttackPower * spellModifier) > (rangedAttackPower * spellModifier) then
+ spellPower = meleeAttackPower
+ else
+ spellPower = rangedAttackPower
+ end
+ end
+
+ local healModifier = playerHealModifier
+
+ if playerClass == "PRIEST" then
+ healAmount = healAmount * (1 + talentData[FocusedPower].current)
+ healAmount = healAmount * (1 + talentData[BlessedResilience].current)
+ elseif playerClass == "PALADIN" then
+ if talentData[Divinity].current > 0 then
+ healModifier = healModifier + talentData[Divinity].current
+ healAmount = healAmount * (1 + talentData[Divinity].current)
+ end
+
+ if equippedSetCache["T10 Holy"] >= 2 and unitHasAura("player", DivineIllumination) then
+ healAmount = healAmount * 1.35
+ end
+ end
+
+ healAmount = calculateGeneralAmount(playerLevel, healAmount, spellPower, spellModifier, healModifier)
+ healAmount = floor(healAmount / hotData[naaruSpellName].ticks)
+
+ return HOT_HEALS, healAmount, hotData[naaruSpellName].ticks, hotData[naaruSpellName].interval
+ end
+
+ if CalculateHotHealing then
+ local CalculateHotHealing_Orig = CalculateHotHealing
+ function CalculateHotHealing(guid, spellID)
+ if naaruClassSpells[spellID] then
+ return CalculateHotHealing_Naaru(guid, spellID)
+ else
+ return CalculateHotHealing_Orig(guid, spellID)
+ end
+ end
+ else
+ CalculateHotHealing = CalculateHotHealing_Naaru
+ end
+
+ if not GetHealTargets then
+ GetHealTargets = function(bitType, guid, healAmount, spellName, hasVariableTicks)
+ return compressGUID[guid], healAmount
+ end
+ end
+ end
+end
+
+local function getName(spellID)
+ local name = GetSpellInfo(spellID)
+ --[===[@debug@
+ if( not name ) then
+ print(format("%s-r%s: Failed to find spellID %d", major, minor, spellID))
+ end
+ --@end-debug@]===]
+ return name or ""
+end
+
+-- Healing modifiers
+if( not HealComm.aurasUpdated ) then
+ HealComm.aurasUpdated = true
+ HealComm.selfModifiers = nil
+ HealComm.healingModifiers = nil
+end
+
+HealComm.currentModifiers = HealComm.currentModifiers or {}
+
+HealComm.selfModifiers = HealComm.selfModifiers or {
+ [64850] = 0.50, -- Unrelenting Assault
+ [65925] = 0.50, -- Unrelenting Assault
+ [54428] = 0.50, -- Divine Plea
+ [32346] = 0.50, -- Stolen Soul
+ [64849] = 0.75, -- Unrelenting Assault
+ [72221] = 1.05, -- Luck of the Draw
+ [70873] = 1.10, -- Emerald Vigor (Valithria Dreamwalker)
+ [31884] = 1.20, -- Avenging Wrath
+ [72393] = 0.25, -- Hopelessness
+ [72397] = 0.40, -- Hopelessness
+ [72391] = 0.50, -- Hopelessness
+ [72396] = 0.60, -- Hopelessness
+ [72390] = 0.75, -- Hopelessness
+ [72395] = 0.80, -- Hopelessness
+}
+
+-- The only spell in the game with a name conflict is Ray of Pain from the Nagrand Void Walkers
+HealComm.healingModifiers = HealComm.healingModifiers or {
+ [getName(30843)] = 0.00, -- Enfeeble
+ [getName(41292)] = 0.00, -- Aura of Suffering
+ [59513] = 0.00, -- Embrace of the Vampyr
+ [getName(55593)] = 0.00, -- Necrotic Aura
+ [28776] = 0.10, -- Necrotic Poison
+ [getName(34625)] = 0.25, -- Demolish
+ [getName(19716)] = 0.25, -- Gehennas' Curse
+ [getName(24674)] = 0.25, -- Veil of Shadow
+ [69633] = 0.25, -- Veil of Shadow, in German this is translated differently from the one above
+ [46296] = 0.25, -- Necrotic Poison
+ [54121] = 0.25, -- Necrotic Poison
+ -- Wound Poison still uses a unique spellID/spellName despite the fact that it's a static 50% reduction.
+ [getName(13218)] = 0.50, -- 1
+ [getName(13222)] = 0.50, -- 2
+ [getName(13223)] = 0.50, -- 3
+ [getName(13224)] = 0.50, -- 4
+ [getName(27189)] = 0.50, -- 5
+ [getName(57974)] = 0.50, -- 6
+ [getName(57975)] = 0.50, -- 7
+ [getName(20900)] = 0.50, -- Aimed Shot
+ [getName(44534)] = 0.50, -- Wretched Strike
+ [getName(21551)] = 0.50, -- Mortal Strike
+ [getName(40599)] = 0.50, -- Arcing Smash
+ [getName(36917)] = 0.50, -- Magma-Throwser's Curse
+ [getName(23169)] = 0.50, -- Brood Affliction: Green
+ [getName(22859)] = 0.50, -- Mortal Cleave
+ [getName(36023)] = 0.50, -- Deathblow
+ [getName(13583)] = 0.50, -- Curse of the Deadwood
+ [getName(32378)] = 0.50, -- Filet
+ [getName(35189)] = 0.50, -- Solar Strike
+ [getName(32315)] = 0.50, -- Soul Strike
+ [getName(60084)] = 0.50, -- The Veil of Shadow
+ [getName(45885)] = 0.50, -- Shadow Spike
+ [getName(69674)] = 0.50, -- Mutated Infection (Rotface)
+ [36693] = 0.55, -- Necrotic Poison
+ [getName(63038)] = 0.75, -- Dark Volley
+ [getName(52771)] = 0.75, -- Wounding Strike
+ [getName(48291)] = 0.75, -- Fetid Healing
+ [getName(34366)] = 0.75, -- Ebon Poison
+ [getName(54525)] = 0.80, -- Shroud of Darkness (This might be wrong)
+ [getName(48301)] = 0.80, -- Mind Trauma (Improved Mind Blast)
+ [getName(68391)] = 0.80, -- Permafrost, the debuff is generic no way of seeing 7/13/20, go with 20
+ [getName(52645)] = 0.80, -- Hex of Weakness
+ [getName(34073)] = 0.85, -- Curse of the Bleeding Hollow
+ [getName(43410)] = 0.90, -- Chop
+ [getName(70588)] = 0.90, -- Suppression (Valithria Dreamwalker NPCs?)
+ [getName(34123)] = 1.06, -- Tree of Life
+ [getName(64844)] = 1.10, -- Divine Hymn
+ [getName(47788)] = 1.40, -- Guardian Spirit
+ [getName(38387)] = 1.50, -- Bane of Infinity
+ [getName(31977)] = 1.50, -- Curse of Infinity
+ [getName(41350)] = 2.00, -- Aura of Desire
+ [73762] = 1.05, -- Strength of Wrynn (5%)
+ [73816] = 1.05, -- Hellscream's Warsong (5%)
+ [73824] = 1.10, -- Strength of Wrynn (10%)
+ [73818] = 1.10, -- Hellscream's Warsong (10%)
+ [73825] = 1.15, -- Strength of Wrynn (15%)
+ [73819] = 1.15, -- Hellscream's Warsong (15%)
+ [73826] = 1.20, -- Strength of Wrynn (20%)
+ [73820] = 1.20, -- Hellscream's Warsong (20%)
+ [73827] = 1.25, -- Strength of Wrynn (25%)
+ [73821] = 1.25, -- Hellscream's Warsong (25%)
+ [73828] = 1.30, -- Strength of Wrynn (30%)
+ [73822] = 1.30, -- Hellscream's Warsong (30%)
+}
+
+HealComm.healingStackMods = HealComm.healingStackMods or {
+ -- Enervating Band
+ [getName(74502)] = function(name, rank, icon, stacks) return 1 - stacks * 0.02 end,
+ -- Tenacity
+ [getName(58549)] = function(name, rank, icon, stacks) return icon == "Interface\\Icons\\Ability_Warrior_StrengthOfArms" and stacks ^ 1.18 or 1 end,
+ -- Focused Will
+ [getName(45242)] = function(name, rank, icon, stacks) return 1 + (stacks * (0.02 + rankNumbers[rank] / 100)) end,
+ -- Nether Portal - Dominance
+ [getName(30423)] = function(name, rank, icon, stacks) return 1 + stacks * 0.01 end,
+ -- Dark Touched
+ [getName(45347)] = function(name, rank, icon, stacks) return 1 - stacks * 0.04 end,
+ -- Necrotic Strike
+ [getName(60626)] = function(name, rank, icon, stacks) return 1 - stacks * 0.10 end,
+ -- Mortal Wound
+ [getName(28467)] = function(name, rank, icon, stacks) return 1 - stacks * 0.10 end,
+ -- Furious Strikes
+ [getName(56112)] = function(name, rank, icon, stacks) return 1 - stacks * 0.25 end,
+}
+
+local healingStackMods, selfModifiers = HealComm.healingStackMods, HealComm.selfModifiers
+local healingModifiers, currentModifiers = HealComm.healingModifiers, HealComm.currentModifiers
+
+local distribution
+local CTL = ChatThrottleLib
+local function sendMessage(msg)
+ if( distribution and len(msg) <= 240 ) then
+ CTL:SendAddonMessage("BULK", COMM_PREFIX, msg, distribution)
+ end
+end
+
+-- Keep track of where all the data should be going
+local instanceType
+local function updateDistributionChannel()
+ local lastChannel = distribution
+ if( instanceType == "pvp" or instanceType == "arena" ) then
+ distribution = "BATTLEGROUND"
+ elseif( GetNumRaidMembers() > 0 ) then
+ distribution = "RAID"
+ elseif( GetNumPartyMembers() > 0 ) then
+ distribution = "PARTY"
+ else
+ distribution = nil
+ end
+
+ if( distribution == lastChannel ) then return end
+
+ -- If the player is not a healer, some events can be disabled until the players grouped.
+ if( distribution ) then
+ HealComm.eventFrame:RegisterEvent("CHAT_MSG_ADDON")
+ if( not isHealerClass ) then
+ HealComm.eventFrame:RegisterEvent("UNIT_AURA")
+ HealComm.eventFrame:RegisterEvent("UNIT_SPELLCAST_DELAYED")
+ HealComm.eventFrame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
+ HealComm.eventFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+ end
+ else
+ HealComm.eventFrame:UnregisterEvent("CHAT_MSG_ADDON")
+ if( not isHealerClass ) then
+ HealComm.eventFrame:UnregisterEvent("UNIT_AURA")
+ HealComm.eventFrame:UnregisterEvent("UNIT_SPELLCAST_DELAYED")
+ HealComm.eventFrame:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
+ HealComm.eventFrame:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+ end
+ end
+end
+
+-- Figure out where we should be sending messages and wipe some caches
+function HealComm:PLAYER_ENTERING_WORLD()
+ HealComm.eventFrame:UnregisterEvent("PLAYER_ENTERING_WORLD")
+ HealComm:ZONE_CHANGED_NEW_AREA()
+end
+
+function HealComm:ZONE_CHANGED_NEW_AREA()
+ local pvpType = GetZonePVPInfo()
+ local type = select(2, IsInInstance())
+
+ HealComm.zoneHealModifier = 1
+ if( pvpType == "combat" or type == "arena" or type == "pvp" ) then
+ HealComm.zoneHealModifier = 0.90
+ end
+
+ if( type ~= instanceType ) then
+ instanceType = type
+
+ updateDistributionChannel()
+ clearPendingHeals()
+ twipe(activeHots)
+ end
+
+ instanceType = type
+end
+
+local alreadyAdded = {}
+function HealComm:UNIT_AURA(unit)
+ if not unit then return end
+
+ local guid = UnitGUID(unit)
+ if( not guidToUnit[guid] ) then return end
+ local increase, decrease, playerIncrease, playerDecrease = 1, 1, 1, 1
+
+ -- Scan buffs
+ local id = 1
+ while( true ) do
+ local name, rank, icon, stack, _, _, _, _, _, _, spellID = UnitAura(unit, id, "HELPFUL")
+ if( not name ) then break end
+ -- Prevent buffs like Tree of Life that have the same name for the shapeshift/healing increase from being calculated twice
+ if( not alreadyAdded[name] ) then
+ alreadyAdded[name] = true
+
+ if( healingModifiers[spellID] ) then
+ increase = increase * healingModifiers[spellID]
+ elseif( healingModifiers[name] ) then
+ increase = increase * healingModifiers[name]
+ elseif( healingStackMods[name] ) then
+ increase = increase * healingStackMods[name](name, rank, icon, stack)
+ end
+
+ if( unit == "player" and selfModifiers[spellID] ) then
+ playerIncrease = playerIncrease * selfModifiers[spellID]
+ end
+ end
+
+ id = id + 1
+ end
+
+ -- Scan debuffs
+ id = 1
+ while( true ) do
+ local name, rank, icon, stack, _, _, _, _, _, _, spellID = UnitAura(unit, id, "HARMFUL")
+ if( not name ) then break end
+
+ if( healingModifiers[spellID] ) then
+ decrease = min(decrease, healingModifiers[spellID])
+ elseif( healingModifiers[name] ) then
+ decrease = min(decrease, healingModifiers[name])
+ elseif( healingStackMods[name] ) then
+ decrease = min(decrease, healingStackMods[name](name, rank, icon, stack))
+ end
+
+ if( unit == "player" and selfModifiers[spellID] ) then
+ playerDecrease = min(playerDecrease, selfModifiers[spellID])
+ end
+
+ id = id + 1
+ end
+
+ -- Check if modifier changed
+ local modifier = increase * decrease
+ if( modifier ~= currentModifiers[guid] ) then
+ if( currentModifiers[guid] or modifier ~= 1 ) then
+ currentModifiers[guid] = modifier
+ self.callbacks:Fire("HealComm_ModifierChanged", guid, modifier)
+ else
+ currentModifiers[guid] = modifier
+ end
+ end
+
+ twipe(alreadyAdded)
+
+ if( unit == "player" ) then
+ playerHealModifier = playerIncrease * playerDecrease
+ end
+
+ -- Class has a specific monitor it needs for auras
+ if( AuraHandler ) then
+ AuraHandler(unit, guid)
+ end
+end
+
+-- Monitor glyph changes
+function HealComm:GlyphsUpdated(id)
+ local spellID = glyphCache[id]
+
+ -- Invalidate the old cache value
+ if( spellID ) then
+ glyphCache[spellID] = nil
+ glyphCache[id] = nil
+ end
+
+ -- Cache the new one if any
+ local enabled, _, glyphID = GetGlyphSocketInfo(id)
+ if( enabled and glyphID ) then
+ glyphCache[glyphID] = true
+ glyphCache[id] = glyphID
+ end
+end
+
+HealComm.GLYPH_ADDED = HealComm.GlyphsUpdated
+HealComm.GLYPH_REMOVED = HealComm.GlyphsUpdated
+HealComm.GLYPH_UPDATED = HealComm.GlyphsUpdated
+
+-- Invalidate he average cache to recalculate for spells that increase in power due to leveling up (but not training new ranks)
+function HealComm:PLAYER_LEVEL_UP(level)
+ for spell, average in pairs(averageHeal) do
+ twipe(average)
+
+ average.spell = spell
+ end
+
+ -- WoWProgramming says this is a string, why this is a string I do not know.
+ playerLevel = tonumber(level) or UnitLevel("player")
+end
+
+-- Cache player talent data for spells we need
+function HealComm:PLAYER_TALENT_UPDATE()
+ for tabIndex=1, GetNumTalentTabs() do
+ for i=1, GetNumTalents(tabIndex) do
+ local name, _, _, _, spent = GetTalentInfo(tabIndex, i)
+ if( name and talentData[name] ) then
+ talentData[name].current = talentData[name].mod * spent
+ talentData[name].spent = spent
+ end
+ end
+ end
+end
+
+-- Save the currently equipped range weapon
+local RANGED_SLOT = GetInventorySlotInfo("RangedSlot")
+function HealComm:PLAYER_EQUIPMENT_CHANGED()
+ -- Caches set bonus info, as you can't reequip set bonus gear in combat no sense in checking it
+ if( not InCombatLockdown() ) then
+ for name, items in pairs(itemSetsData) do
+ equippedSetCache[name] = 0
+ for _, itemID in pairs(items) do
+ if( IsEquippedItem(itemID) ) then
+ equippedSetCache[name] = equippedSetCache[name] + 1
+ end
+ end
+ end
+ end
+
+ -- Check relic
+ local relic = GetInventoryItemLink("player", RANGED_SLOT)
+ playerCurrentRelic = relic and tonumber(match(relic, "item:(%d+):")) or nil
+end
+
+-- COMM CODE
+local function loadHealAmount(...)
+ local tbl = HealComm:RetrieveTable()
+ for i=1, select("#", ...) do
+ tbl[i] = tonumber((select(i, ...)))
+ end
+
+ return tbl
+end
+
+-- Direct heal started
+local function loadHealList(pending, amount, stack, endTime, ticksLeft, ...)
+ twipe(tempPlayerList)
+
+ -- For the sake of consistency, even a heal doesn't have multiple end times like a hot, it'll be treated as such in the DB
+ if( amount ~= -1 and amount ~= "-1" ) then
+ amount = not pending.hasVariableTicks and amount or loadHealAmount(split("@", amount))
+
+ for i=1, select("#", ...) do
+ local guid = select(i, ...)
+ if( guid ) then
+ updateRecord(pending, decompressGUID[guid], amount, stack, endTime, ticksLeft)
+ tinsert(tempPlayerList, decompressGUID[guid])
+ end
+ end
+ else
+ for i=1, select("#", ...), 2 do
+ local guid = select(i, ...)
+ local amount = not pending.hasVariableTicks and tonumber((select(i + 1, ...))) or loadHealAmount(split("@", amount))
+ if( guid and amount ) then
+ updateRecord(pending, decompressGUID[guid], amount, stack, endTime, ticksLeft)
+ tinsert(tempPlayerList, decompressGUID[guid])
+ end
+ end
+ end
+end
+
+local function parseDirectHeal(casterGUID, spellID, amount, ...)
+ local spellName = GetSpellInfo(spellID)
+ local unit = guidToUnit[casterGUID]
+ if( not unit or not spellName or not amount or select("#", ...) == 0 ) then return end
+
+ local endTime = select(6, UnitCastingInfo(unit))
+ if( not endTime ) then return end
+
+ pendingHeals[casterGUID] = pendingHeals[casterGUID] or {}
+ pendingHeals[casterGUID][spellName] = pendingHeals[casterGUID][spellName] or {}
+
+ local pending = pendingHeals[casterGUID][spellName]
+ twipe(pending)
+ pending.endTime = endTime / 1000
+ pending.spellID = spellID
+ pending.bitType = DIRECT_HEALS
+
+ loadHealList(pending, amount, 1, 0, nil, ...)
+
+ HealComm.callbacks:Fire("HealComm_HealStarted", casterGUID, spellID, pending.bitType, pending.endTime, unpack(tempPlayerList))
+end
+
+HealComm.parseDirectHeal = parseDirectHeal
+
+-- Channeled heal started
+local function parseChannelHeal(casterGUID, spellID, amount, totalTicks, ...)
+ local spellName = GetSpellInfo(spellID)
+ local unit = guidToUnit[casterGUID]
+ if( not unit or not spellName or not totalTicks or not amount or select("#", ...) == 0 ) then return end
+
+ local startTime, endTime = select(5, UnitChannelInfo(unit))
+ if( not startTime or not endTime ) then return end
+
+ pendingHeals[casterGUID] = pendingHeals[casterGUID] or {}
+ pendingHeals[casterGUID][spellName] = pendingHeals[casterGUID][spellName] or {}
+
+ local inc = amount == -1 and 2 or 1
+ local pending = pendingHeals[casterGUID][spellName]
+ twipe(pending)
+ pending.startTime = startTime / 1000
+ pending.endTime = endTime / 1000
+ pending.duration = max(pending.duration or 0, pending.endTime - pending.startTime)
+ pending.totalTicks = totalTicks
+ pending.tickInterval = (pending.endTime - pending.startTime) / totalTicks
+ pending.spellID = spellID
+ pending.isMultiTarget = (select("#", ...) / inc) > 1
+ pending.bitType = CHANNEL_HEALS
+
+ loadHealList(pending, amount, 1, 0, ceil(pending.duration / pending.tickInterval), ...)
+
+ HealComm.callbacks:Fire("HealComm_HealStarted", casterGUID, spellID, pending.bitType, pending.endTime, unpack(tempPlayerList))
+end
+
+-- Hot heal started
+-- When the person is within visible range of us, the aura is available by the time the message reaches the target
+-- as such, we can rely that at least one person is going to have the aura data on them (and that it won't be different, at least for this cast)
+local function findAura(casterGUID, spellName, spellRank, inc, ...)
+ for i=1, select("#", ...), inc do
+ local guid = decompressGUID[select(i, ...)]
+ local unit = guid and guidToUnit[guid]
+ if( unit and UnitIsVisible(unit) ) then
+ local id = 1
+ while( true ) do
+ local name, rank, _, stack, _, duration, endTime, caster = UnitBuff(unit, id)
+ if( not name ) then break end
+
+ if( name == spellName and spellRank == rank and caster and UnitGUID(caster) == casterGUID ) then
+ return (stack and stack > 0 and stack or 1), duration, endTime
+ end
+
+ id = id + 1
+ end
+ end
+ end
+end
+
+local function parseHotHeal(casterGUID, wasUpdated, spellID, tickAmount, totalTicks, tickInterval, ...)
+ local spellName, spellRank = GetSpellInfo(spellID)
+ -- If the user is on 3.3, then anything without a total ticks attached to it is rejected
+ if( ( IS_BUILD30300 and not totalTicks ) or not tickAmount or not spellName or select("#", ...) == 0 ) then return end
+
+ -- Retrieve the hot information
+ local inc = ( tickAmount == -1 or tickAmount == "-1" ) and 2 or 1
+ local stack, duration, endTime = findAura(casterGUID, spellName, spellRank, inc, ...)
+ if( not stack or not duration or not endTime ) then return end
+
+ pendingHeals[casterGUID] = pendingHeals[casterGUID] or {}
+ pendingHeals[casterGUID][spellID] = pendingHeals[casterGUID][spellID] or {}
+
+ local pending = pendingHeals[casterGUID][spellID]
+ pending.duration = duration
+ pending.endTime = endTime
+ pending.stack = stack
+ pending.totalTicks = totalTicks or duration / tickInterval
+ pending.tickInterval = totalTicks and duration / totalTicks or tickInterval
+ pending.spellID = spellID
+ pending.hasVariableTicks = type(tickAmount) == "string"
+ pending.isMutliTarget = (select("#", ...) / inc) > 1
+ pending.bitType = HOT_HEALS
+
+ -- As you can't rely on a hot being the absolutely only one up, have to apply the total amount now :<
+ local ticksLeft = ceil((endTime - GetTime()) / pending.tickInterval)
+ loadHealList(pending, tickAmount, stack, endTime, ticksLeft, ...)
+
+ if( not wasUpdated ) then
+ HealComm.callbacks:Fire("HealComm_HealStarted", casterGUID, spellID, pending.bitType, endTime, unpack(tempPlayerList))
+ else
+ HealComm.callbacks:Fire("HealComm_HealUpdated", casterGUID, spellID, pending.bitType, endTime, unpack(tempPlayerList))
+ end
+end
+
+local function parseHotBomb(casterGUID, wasUpdated, spellID, amount, ...)
+ local spellName, spellRank = GetSpellInfo(spellID)
+ if( not amount or not spellName or select("#", ...) == 0 ) then return end
+
+ -- If we don't have a pending hot then there is no bomb as far as were concerned
+ local hotPending = pendingHeals[casterGUID] and pendingHeals[casterGUID][spellID]
+ if( not hotPending or not hotPending.bitType ) then return end
+ hotPending.hasBomb = true
+
+ pendingHeals[casterGUID][spellName] = pendingHeals[casterGUID][spellName] or {}
+
+ local pending = pendingHeals[casterGUID][spellName]
+ pending.endTime = hotPending.endTime
+ pending.spellID = spellID
+ pending.bitType = BOMB_HEALS
+ pending.stack = hotPending.stack
+
+ loadHealList(pending, amount, pending.stack, pending.endTime, nil, ...)
+
+ if( not wasUpdated ) then
+ HealComm.callbacks:Fire("HealComm_HealStarted", casterGUID, spellID, pending.bitType, pending.endTime, unpack(tempPlayerList))
+ else
+ HealComm.callbacks:Fire("HealComm_HealUpdated", casterGUID, spellID, pending.bitType, pending.endTime, unpack(tempPlayerList))
+ end
+end
+
+-- Heal finished
+local function parseHealEnd(casterGUID, pending, checkField, spellID, interrupted, ...)
+ local spellName = GetSpellInfo(spellID)
+ if( not spellName or not pendingHeals[casterGUID] ) then return end
+
+ -- Hots use spell IDs while everything else uses spell names. Avoids naming conflicts for multi-purpose spells such as Lifebloom or Regrowth
+ if( not pending ) then
+ pending = checkField == "id" and pendingHeals[casterGUID][spellID] or pendingHeals[casterGUID][spellName]
+ end
+ if( not pending or not pending.bitType ) then return end
+
+ twipe(tempPlayerList)
+
+ if( select("#", ...) == 0 ) then
+ for i=#(pending), 1, -5 do
+ tinsert(tempPlayerList, pending[i - 4])
+ removeRecord(pending, pending[i - 4])
+ end
+ else
+ for i=1, select("#", ...) do
+ local guid = decompressGUID[select(i, ...)]
+
+ tinsert(tempPlayerList, guid)
+ removeRecord(pending, guid)
+ end
+ end
+
+ -- Double check and make sure we actually removed at least one person
+ if( #(tempPlayerList) == 0 ) then return end
+
+ -- Heals that also have a bomb associated to them have to end at this point, they will fire there own callback too
+ local bombPending = pending.hasBomb and pendingHeals[casterGUID][spellName]
+ if( bombPending and bombPending.bitType ) then
+ parseHealEnd(casterGUID, bombPending, "name", spellID, interrupted, ...)
+ end
+
+ local bitType = pending.bitType
+ -- Clear data if we're done
+ if( #(pending) == 0 ) then twipe(pending) end
+
+ HealComm.callbacks:Fire("HealComm_HealStopped", casterGUID, spellID, bitType, interrupted, unpack(tempPlayerList))
+end
+
+HealComm.parseHealEnd = parseHealEnd
+
+-- Heal delayed
+local function parseHealDelayed(casterGUID, startTime, endTime, spellName)
+ local pending = pendingHeals[casterGUID][spellName]
+ -- It's possible to get duplicate interrupted due to raid1 = party1, player = raid# etc etc, just block it here
+ if( pending.endTime == endTime and pending.startTime == startTime ) then return end
+
+ -- Casted heal
+ if( pending.bitType == DIRECT_HEALS ) then
+ pending.startTime = startTime
+ pending.endTime = endTime
+ -- Channel heal
+ elseif( pending.bitType == CHANNEL_HEALS ) then
+ pending.startTime = startTime
+ pending.endTime = endTime
+ pending.tickInterval = (pending.endTime - pending.startTime)
+ else
+ return
+ end
+
+ twipe(tempPlayerList)
+ for i=1, #(pending), 5 do
+ tinsert(tempPlayerList, pending[i])
+ end
+
+ HealComm.callbacks:Fire("HealComm_HealDelayed", casterGUID, pending.spellID, pending.bitType, pending.endTime, unpack(tempPlayerList))
+end
+
+-- After checking around 150-200 messages in battlegrounds, server seems to always be passed (if they are from another server)
+-- Channels use tick total because the tick interval varies by haste
+-- Hots use tick interval because the total duration varies but the tick interval stays the same
+function HealComm:CHAT_MSG_ADDON(prefix, message, channel, sender)
+ if( prefix ~= COMM_PREFIX or channel ~= distribution or sender == playerName ) then return end
+
+ local commType, extraArg, spellID, arg1, arg2, arg3, arg4, arg5, arg6 = split(":", message)
+ local casterGUID = UnitGUID(sender)
+ spellID = tonumber(spellID)
+
+ if( not commType or not spellID or not casterGUID ) then return end
+
+ -- New direct heal - D::::target1,target2...
+ if( commType == "D" and arg1 and arg2 ) then
+ parseDirectHeal(casterGUID, spellID, tonumber(arg1), split(",", arg2))
+ -- New channel heal - C:::::target1,target2...
+ elseif( commType == "C" and arg1 and arg3 ) then
+ parseChannelHeal(casterGUID, spellID, tonumber(arg1), tonumber(arg2), split(",", arg3))
+ -- New hot with a "bomb" component - B::::target1,target2::::target1,target2...
+ elseif( commType == "B" and arg1 and arg6 ) then
+ parseHotHeal(casterGUID, false, spellID, tonumber(arg3), tonumber(extraArg), tonumber(arg5), split(",", arg6))
+ parseHotBomb(casterGUID, false, spellID, tonumber(arg1), split(",", arg2))
+ -- New hot - H::::::target1,target2...
+ elseif( commType == "H" and arg1 and arg4 ) then
+ parseHotHeal(casterGUID, false, spellID, tonumber(arg1), tonumber(extraArg), tonumber(arg3), split(",", arg4))
+ -- New updated heal somehow before ending - U:::::target1,target2...
+ elseif( commType == "U" and arg1 and arg3 ) then
+ parseHotHeal(casterGUID, true, spellID, tonumber(arg1), tonumber(extraArg), tonumber(arg2), split(",", arg3))
+ -- New variable tick hot - VH::::::target1,target2...
+ elseif( commType == "VH" and arg1 and arg4 ) then
+ parseHotHeal(casterGUID, false, spellID, arg1, tonumber(arg3), nil, split(",", arg4))
+ -- New updated variable tick hot - U:::amount1@amount2@amount3::target1,target2...
+ elseif( commType == "VU" and arg1 and arg3 ) then
+ parseHotHeal(casterGUID, true, spellID, arg1, tonumber(arg2), nil, split(",", arg3))
+ -- New updated bomb hot - UB::::target1,target2:::target1,target2...
+ elseif( commType == "UB" and arg1 and arg5 ) then
+ parseHotHeal(casterGUID, true, spellID, tonumber(arg3), tonumber(extraArg), tonumber(arg4), split(",", arg5))
+ parseHotBomb(casterGUID, true, spellID, tonumber(arg1), split(",", arg2))
+ -- Heal stopped - S::::target1,target2...
+ elseif( commType == "S" or commType == "HS" ) then
+ local interrupted = arg1 == "1" and true or false
+ local type = commType == "HS" and "id" or "name"
+
+ if( arg2 and arg2 ~= "" ) then
+ parseHealEnd(casterGUID, nil, type, spellID, interrupted, split(",", arg2))
+ else
+ parseHealEnd(casterGUID, nil, type, spellID, interrupted)
+ end
+ end
+end
+
+-- Bucketing reduces the number of events triggered for heals such as Tranquility that hit multiple targets
+-- instead of firing 5 events * ticks it will fire 1 (maybe 2 depending on lag) events
+HealComm.bucketHeals = HealComm.bucketHeals or {}
+local bucketHeals = HealComm.bucketHeals
+local BUCKET_FILLED = 0.30
+
+HealComm.bucketFrame = HealComm.bucketFrame or CreateFrame("Frame")
+HealComm.bucketFrame:Hide()
+
+HealComm.bucketFrame:SetScript("OnUpdate", function(self, elapsed)
+ local totalLeft = 0
+ for casterGUID, spells in pairs(bucketHeals) do
+ for id, data in pairs(spells) do
+ if( data.timeout ) then
+ data.timeout = data.timeout - elapsed
+
+ if( data.timeout <= 0 ) then
+ -- This shouldn't happen, on the offhand chance it does then don't bother sending an event
+ if( #(data) == 0 or not data.spellID or not data.spellName ) then
+ twipe(data)
+ -- We're doing a bucket for a tick heal like Tranquility or Wild Growth
+ elseif( data.type == "tick" ) then
+ local pending = pendingHeals[casterGUID] and ( pendingHeals[casterGUID][data.spellID] or pendingHeals[casterGUID][data.spellName] )
+ if( pending and pending.bitType ) then
+ local endTime = select(3, getRecord(pending, data[1]))
+ HealComm.callbacks:Fire("HealComm_HealUpdated", casterGUID, pending.spellID, pending.bitType, endTime, unpack(data))
+ end
+
+ twipe(data)
+ -- We're doing a bucket for a cast thats a multi-target heal like Wild Growth or Prayer of Healing
+ elseif( data.type == "heal" ) then
+ local type, amount, totalTicks, tickInterval, _, hasVariableTicks = CalculateHotHealing(data[1], data.spellID)
+ if( type ) then
+ local targets, amount = GetHealTargets(type, data[1], hasVariableTicks and amount or max(amount, 0), data.spellName, data, hasVariableTicks)
+ parseHotHeal(playerGUID, false, data.spellID, amount, totalTicks, tickInterval, split(",", targets))
+
+ if( not hasVariableTicks ) then
+ sendMessage(format("H:%d:%d:%d::%d:%s", totalTicks, data.spellID, amount, tickInterval, targets))
+ else
+ sendMessage(format("VH::%d:%s::%d:%s", data.spellID, amount, totalTicks, targets))
+ end
+ end
+
+ twipe(data)
+ end
+ else
+ totalLeft = totalLeft + 1
+ end
+ end
+ end
+ end
+
+ if( totalLeft <= 0 ) then
+ self:Hide()
+ end
+end)
+
+-- Monitor aura changes as well as new hots being cast
+local eventRegistered = {["SPELL_HEAL"] = true, ["SPELL_PERIODIC_HEAL"] = true}
+if( isHealerClass ) then
+ eventRegistered["SPELL_AURA_REMOVED"] = true
+ eventRegistered["SPELL_AURA_APPLIED"] = true
+ eventRegistered["SPELL_AURA_REFRESH"] = true
+ eventRegistered["SPELL_AURA_APPLIED_DOSE"] = true
+ eventRegistered["SPELL_AURA_REMOVED_DOSE"] = true
+end
+
+local COMBATLOG_OBJECT_AFFILIATION_MINE = COMBATLOG_OBJECT_AFFILIATION_MINE
+local CAN_HEAL = bor(COMBATLOG_OBJECT_REACTION_FRIENDLY, COMBATLOG_OBJECT_REACTION_NEUTRAL)
+function HealComm:COMBAT_LOG_EVENT_UNFILTERED(timestamp, eventType, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, ...)
+ if( not eventRegistered[eventType] ) then return end
+
+ -- Heal or hot ticked that the library is tracking
+ -- It's more efficient/accurate to have the library keep track of this locally, spamming the comm channel would not be a very good thing especially when a single player can have 4 - 8 hots/channels going on them.
+ if( eventType == "SPELL_HEAL" or eventType == "SPELL_PERIODIC_HEAL" ) then
+ local spellID, spellName, spellSchool = ...
+ local pending = sourceGUID and pendingHeals[sourceGUID] and (pendingHeals[sourceGUID][spellID] or pendingHeals[sourceGUID][spellName])
+ if( pending and pending[destGUID] and pending.bitType and band(pending.bitType, OVERTIME_HEALS) > 0 ) then
+ local amount, stack, endTime, ticksLeft = getRecord(pending, destGUID)
+ ticksLeft = ticksLeft - 1
+ endTime = GetTime() + pending.tickInterval * ticksLeft
+ if( pending.hasVariableTicks ) then tremove(amount, 1) end
+
+ updateRecord(pending, destGUID, amount, stack, endTime, ticksLeft)
+
+ if( pending.isMultiTarget ) then
+ bucketHeals[sourceGUID] = bucketHeals[sourceGUID] or {}
+ bucketHeals[sourceGUID][spellID] = bucketHeals[sourceGUID][spellID] or {}
+
+ local spellBucket = bucketHeals[sourceGUID][spellID]
+ if( not spellBucket[destGUID] ) then
+ spellBucket.timeout = BUCKET_FILLED
+ spellBucket.type = "tick"
+ spellBucket.spellName = spellName
+ spellBucket.spellID = spellID
+ spellBucket[destGUID] = true
+ tinsert(spellBucket, destGUID)
+
+ self.bucketFrame:Show()
+ end
+ else
+ HealComm.callbacks:Fire("HealComm_HealUpdated", sourceGUID, spellID, pending.bitType, endTime, destGUID)
+ end
+ end
+
+ -- New hot was applied
+ elseif( ( eventType == "SPELL_AURA_APPLIED" or eventType == "SPELL_AURA_REFRESH" or eventType == "SPELL_AURA_APPLIED_DOSE" ) and band(sourceFlags, COMBATLOG_OBJECT_AFFILIATION_MINE) == COMBATLOG_OBJECT_AFFILIATION_MINE ) then
+ local spellID, spellName, spellSchool, auraType = ...
+ if( hotData[spellName] ) then
+ -- Multi target heal so put it in the bucket
+ if( hotData[spellName].isMulti ) then
+ bucketHeals[sourceGUID] = bucketHeals[sourceGUID] or {}
+ bucketHeals[sourceGUID][spellName] = bucketHeals[sourceGUID][spellName] or {}
+
+ -- For some reason, Glyph of Prayer of Healing fires a SPELL_AURA_APPLIED then a SPELL_AURA_REFRESH right after
+ local spellBucket = bucketHeals[sourceGUID][spellName]
+ if( not spellBucket[destGUID] ) then
+ spellBucket.timeout = BUCKET_FILLED
+ spellBucket.type = "heal"
+ spellBucket.spellName = spellName
+ spellBucket.spellID = spellID
+ spellBucket[destGUID] = true
+ tinsert(spellBucket, destGUID)
+
+ self.bucketFrame:Show()
+ end
+ return
+ end
+
+ -- Single target so we can just send it off now thankfully
+ local type, amount, totalTicks, tickInterval, bombAmount, hasVariableTicks = CalculateHotHealing(destGUID, spellID)
+ if( type ) then
+ local targets, amount = GetHealTargets(type, destGUID, hasVariableTicks and amount or max(amount, 0), spellName, hasVariableTicks)
+ parseHotHeal(sourceGUID, false, spellID, amount, totalTicks, tickInterval, split(",", targets))
+
+ -- Hot with a bomb!
+ if( bombAmount ) then
+ local bombTargets, bombAmount = GetHealTargets(BOMB_HEALS, destGUID, max(bombAmount, 0), spellName)
+ parseHotBomb(sourceGUID, false, spellID, bombAmount, split(",", bombTargets))
+ sendMessage(format("B:%d:%d:%d:%s:%d::%d:%s", totalTicks, spellID, bombAmount, bombTargets, amount, tickInterval, targets))
+ elseif( hasVariableTicks ) then
+ sendMessage(format("VH::%d:%s::%d:%s", spellID, amount, totalTicks, targets))
+ -- Normal hot, nothing fancy
+ else
+ sendMessage(format("H:%d:%d:%d::%d:%s", totalTicks, spellID, amount, tickInterval, targets))
+ end
+ end
+ end
+ -- Single stack of a hot was removed, this only applies when going from 2 -> 1, when it goes from 1 -> 0 it fires SPELL_AURA_REMOVED
+ elseif( eventType == "SPELL_AURA_REMOVED_DOSE" and band(sourceFlags, COMBATLOG_OBJECT_AFFILIATION_MINE) == COMBATLOG_OBJECT_AFFILIATION_MINE ) then
+ local spellID, spellName, spellSchool, auraType, stacks = ...
+ local pending = sourceGUID and pendingHeals[sourceGUID] and pendingHeals[sourceGUID][spellID]
+ if( pending and pending.bitType ) then
+ local amount = getRecord(pending, destGUID)
+ if( amount ) then
+ parseHotHeal(sourceGUID, true, spellID, amount, pending.totalTicks, pending.tickInterval, compressGUID[destGUID])
+
+ -- Plant the bomb
+ local bombPending = pending.hasBomb and pendingHeals[sourceGUID][spellName]
+ if( bombPending and bombPending.bitType ) then
+ local bombAmount = getRecord(bombPending, destGUID)
+ if( bombAmount ) then
+ parseHotBomb(sourceGUID, true, spellID, bombAmount, compressGUID[destGUID])
+
+ sendMessage(format("UB:%s:%d:%d:%s:%d:%d:%s", pending.totalTicks, spellID, bombAmount, compressGUID[destGUID], amount, pending.tickInterval, compressGUID[destGUID]))
+ return
+ end
+ end
+
+ -- Failed to find any sort of bomb-y info we needed or it doesn't have a bomb anyway
+ if( pending.hasVariableTicks ) then
+ sendMessage(format("VU::%d:%s:%d:%s", spellID, amount, pending.totalTicks, compressGUID[destGUID]))
+ else
+ sendMessage(format("U:%s:%d:%d:%d:%s", spellID, amount, pending.totalTicks, pending.tickInterval, compressGUID[destGUID]))
+ end
+ end
+ end
+
+ -- Aura faded
+ elseif( eventType == "SPELL_AURA_REMOVED" ) then
+ local spellID, spellName, spellSchool, auraType = ...
+
+ -- Hot faded that we cast
+ if( hotData[spellName] and band(sourceFlags, COMBATLOG_OBJECT_AFFILIATION_MINE) == COMBATLOG_OBJECT_AFFILIATION_MINE ) then
+ parseHealEnd(sourceGUID, nil, "id", spellID, false, compressGUID[destGUID])
+ sendMessage(format("HS::%d::%s", spellID, compressGUID[destGUID]))
+ end
+ end
+end
+
+-- Spell cast magic
+-- When auto self cast is on, the UNIT_SPELLCAST_SENT event will always come first followed by the funciton calls
+-- Otherwise either SENT comes first then function calls, or some function calls then SENT then more function calls
+local castTarget, castID, mouseoverGUID, mouseoverName, hadTargetingCursor, lastSentID, lastTargetGUID, lastTargetName
+local lastFriendlyGUID, lastFriendlyName, lastGUID, lastName, lastIsFriend
+local castGUIDs, guidPriorities = {}, {}
+
+-- Deals with the fact that functions are called differently
+-- Why a table when you can only cast one spell at a time you ask? When you factor in lag and mash clicking it's possible to:
+-- cast A, interrupt it, cast B and have A fire SUCEEDED before B does, the tables keeps it from bugging out
+local function setCastData(priority, name, guid)
+ if( not guid or not lastSentID ) then return end
+ if( guidPriorities[lastSentID] and guidPriorities[lastSentID] >= priority ) then return end
+
+ -- This is meant as a way of locking a cast in because which function has accurate data can be called into question at times, one of them always does though
+ -- this means that as soon as it finds a name match it locks the GUID in until another SENT is fired. Technically it's possible to get a bad GUID but it first requires
+ -- the functions to return different data and it requires the messed up call to be for another name conflict.
+ if( castTarget and castTarget == name ) then priority = 99 end
+
+ castGUIDs[lastSentID] = guid
+ guidPriorities[lastSentID] = priority
+end
+
+-- When the game tries to figure out the UnitID from the name it will prioritize players over non-players
+-- if there are conflicts in names it will pull the one with the least amount of current health
+function HealComm:UNIT_SPELLCAST_SENT(unit, spellName, spellRank, castOn)
+ if( unit ~= "player" or not spellData[spellName] or not averageHeal[spellName][spellRank] ) then return end
+
+ castTarget = gsub(castOn, "(.-)%-(.*)$", "%1")
+ lastSentID = spellName .. spellRank
+
+ -- Self cast is off which means it's possible to have a spell waiting for a target.
+ -- It's possible that it's the mouseover unit, but if a Target, TargetLast or AssistUnit call comes right after it means it's casting on that instead instead.
+ if( hadTargetingCursor ) then
+ hadTargetingCursor = nil
+ self.resetFrame:Show()
+
+ guidPriorities[lastSentID] = nil
+ setCastData(5, mouseoverName, mouseoverGUID)
+ else
+ -- If the player is ungrouped and healing, you can't take advantage of the name -> "unit" map, look in the UnitIDs that would most likely contain the information that's needed.
+ local guid = UnitGUID(castOn)
+ if( not guid ) then
+ guid = UnitName("target") == castTarget and UnitGUID("target") or UnitName("focus") == castTarget and UnitGUID("focus") or UnitName("mouseover") == castTarget and UnitGUID("mouseover") or UnitName("targettarget") == castTarget and UnitGUID("target") or UnitName("focustarget") == castTarget and UnitGUID("focustarget")
+ end
+
+ guidPriorities[lastSentID] = nil
+ setCastData(0, nil, guid)
+ end
+end
+
+function HealComm:UNIT_SPELLCAST_START(unit, spellName, spellRank, id)
+ if( unit ~= "player" or not spellData[spellName] or not averageHeal[spellName][spellRank] or UnitIsCharmed("player") or not UnitPlayerControlled("player") ) then return end
+ local nameID = spellName .. spellRank
+ local castGUID = castGUIDs[nameID]
+ if( not castGUID ) then
+ return
+ end
+
+ castID = id
+
+ -- Figure out who we are healing and for how much
+ local type, amount, ticks, localTicks = CalculateHealing(castGUID, spellName, spellRank)
+ local targets, amount = GetHealTargets(type, castGUID, max(amount, 0), spellName)
+
+ if( type == DIRECT_HEALS ) then
+ parseDirectHeal(playerGUID, self.spellToID[nameID], amount, split(",", targets))
+ sendMessage(format("D::%d:%d:%s", self.spellToID[nameID] or 0, amount or "", targets))
+ elseif( type == CHANNEL_HEALS ) then
+ parseChannelHeal(playerGUID, self.spellToID[nameID], amount, localTicks, split(",", targets))
+ sendMessage(format("C::%d:%d:%s:%s", self.spellToID[nameID] or 0, amount, ticks, targets))
+ end
+end
+
+HealComm.UNIT_SPELLCAST_CHANNEL_START = HealComm.UNIT_SPELLCAST_START
+
+function HealComm:UNIT_SPELLCAST_SUCCEEDED(unit, spellName, spellRank, id)
+ if( unit ~= "player" or not spellData[spellName] or id ~= castID or id == 0 ) then return end
+ local nameID = spellName .. spellRank
+
+ castID = nil
+ parseHealEnd(playerGUID, nil, "name", self.spellToID[nameID], false)
+ sendMessage(format("S::%d:0", self.spellToID[nameID] or 0))
+end
+
+function HealComm:UNIT_SPELLCAST_STOP(unit, spellName, spellRank, id)
+ if( unit ~= "player" or not spellData[spellName] or id ~= castID ) then return end
+ local nameID = spellName .. spellRank
+
+ castID = nil
+ parseHealEnd(playerGUID, nil, "name", self.spellToID[nameID], true)
+ sendMessage(format("S::%d:1", self.spellToID[nameID] or 0))
+end
+
+function HealComm:UNIT_SPELLCAST_CHANNEL_STOP(unit, spellName, spellRank, id)
+ if( unit ~= "player" or not spellData[spellName] or id ~= castID ) then return end
+ local nameID = spellName .. spellRank
+
+ castID = nil
+ parseHealEnd(playerGUID, nil, "name", self.spellToID[nameID], false)
+ sendMessage(format("S::%d:0", self.spellToID[nameID] or 0))
+end
+
+-- Cast didn't go through, recheck any charge data if necessary
+function HealComm:UNIT_SPELLCAST_INTERRUPTED(unit, spellName, spellRank, id)
+ if( unit ~= "player" or not spellData[spellName] or castID ~= id ) then return end
+
+ local guid = castGUIDs[spellName .. spellRank]
+ if( guid ) then
+ ResetChargeData(guid, spellName, spellRank)
+ end
+end
+
+-- It's faster to do heal delays locally rather than through syncing, as it only has to go from WoW -> Player instead of Caster -> WoW -> Player
+function HealComm:UNIT_SPELLCAST_DELAYED(unit, spellName, spellRank, id)
+ local casterGUID = UnitGUID(unit)
+ if( unit == "focus" or unit == "target" or not pendingHeals[casterGUID] or not pendingHeals[casterGUID][spellName] ) then return end
+
+ -- Direct heal delayed
+ if( pendingHeals[casterGUID][spellName].bitType == DIRECT_HEALS ) then
+ local startTime, endTime = select(5, UnitCastingInfo(unit))
+ if( startTime and endTime ) then
+ parseHealDelayed(casterGUID, startTime / 1000, endTime / 1000, spellName)
+ end
+ -- Channel heal delayed
+ elseif( pendingHeals[casterGUID][spellName].bitType == CHANNEL_HEALS ) then
+ local startTime, endTime = select(5, UnitChannelInfo(unit))
+ if( startTime and endTime ) then
+ parseHealDelayed(casterGUID, startTime / 1000, endTime / 1000, spellName)
+ end
+ end
+end
+
+HealComm.UNIT_SPELLCAST_CHANNEL_UPDATE = HealComm.UNIT_SPELLCAST_DELAYED
+
+-- Need to keep track of mouseover as it can change in the split second after/before casts
+function HealComm:UPDATE_MOUSEOVER_UNIT()
+ mouseoverGUID = UnitCanAssist("player", "mouseover") and UnitGUID("mouseover")
+ mouseoverName = UnitCanAssist("player", "mouseover") and UnitName("mouseover")
+end
+
+-- Keep track of our last target/friendly target for the sake of /targetlast and /targetlastfriend
+function HealComm:PLAYER_TARGET_CHANGED()
+ if( lastGUID and lastName ) then
+ if( lastIsFriend ) then
+ lastFriendlyGUID, lastFriendlyName = lastGUID, lastName
+ end
+
+ lastTargetGUID, lastTargetName = lastGUID, lastName
+ end
+
+ -- Despite the fact that it's called target last friend, UnitIsFriend won't actually work
+ lastGUID = UnitGUID("target")
+ lastName = UnitName("target")
+ lastIsFriend = UnitCanAssist("player", "target")
+end
+
+-- Unit was targeted through a function
+function HealComm:Target(unit)
+ if( self.resetFrame:IsShown() and UnitCanAssist("player", unit) ) then
+ setCastData(6, UnitName(unit), UnitGUID(unit))
+ end
+
+ self.resetFrame:Hide()
+ hadTargetingCursor = nil
+end
+
+-- This is only needed when auto self cast is off, in which case this is called right after UNIT_SPELLCAST_SENT
+-- because the player got a waiting-for-cast icon up and they pressed a key binding to target someone
+HealComm.TargetUnit = HealComm.Target
+
+-- Works the same as the above except it's called when you have a cursor icon and you click on a secure frame with a target attribute set
+HealComm.SpellTargetUnit = HealComm.Target
+
+-- Used in /assist macros
+function HealComm:AssistUnit(unit)
+ if( self.resetFrame:IsShown() and UnitCanAssist("player", unit .. "target") ) then
+ setCastData(6, UnitName(unit .. "target"), UnitGUID(unit .. "target"))
+ end
+
+ self.resetFrame:Hide()
+ hadTargetingCursor = nil
+end
+
+-- Target last was used, the only reason this is called with reset frame being shown is we're casting on a valid unit
+-- don't have to worry about the GUID no longer being invalid etc
+function HealComm:TargetLast(guid, name)
+ if( name and guid and self.resetFrame:IsShown() ) then
+ setCastData(6, name, guid)
+ end
+
+ self.resetFrame:Hide()
+ hadTargetingCursor = nil
+end
+
+function HealComm:TargetLastFriend()
+ self:TargetLast(lastFriendlyGUID, lastFriendlyName)
+end
+
+function HealComm:TargetLastTarget()
+ self:TargetLast(lastTargetGUID, lastTargetName)
+end
+
+-- Spell was cast somehow
+function HealComm:CastSpell(arg, unit)
+ -- If the spell is waiting for a target and it's a spell action button then we know that the GUID has to be mouseover or a key binding cast.
+ if( unit and UnitCanAssist("player", unit) ) then
+ setCastData(4, UnitName(unit), UnitGUID(unit))
+ -- No unit, or it's a unit we can't assist
+ elseif( not SpellIsTargeting() ) then
+ if( UnitCanAssist("player", "target") ) then
+ setCastData(4, UnitName("target"), UnitGUID("target"))
+ else
+ setCastData(4, playerName, playerGUID)
+ end
+
+ hadTargetingCursor = nil
+ else
+ hadTargetingCursor = true
+ end
+end
+
+HealComm.CastSpellByName = HealComm.CastSpell
+HealComm.CastSpellByID = HealComm.CastSpell
+HealComm.UseAction = HealComm.CastSpell
+
+-- Make sure we don't have invalid units in this
+local function sanityCheckMapping()
+ for guid, unit in pairs(guidToUnit) do
+ -- Unit no longer exists, remove all healing for them
+ if( not UnitExists(unit) ) then
+ -- Check for (and remove) any active heals
+ if( pendingHeals[guid] ) then
+ for id, pending in pairs(pendingHeals[guid]) do
+ if( pending.bitType ) then
+ parseHealEnd(guid, pending, nil, pending.spellID, true)
+ end
+ end
+
+ pendingHeals[guid] = nil
+ end
+
+ -- Remove any heals that are on them
+ removeAllRecords(guid)
+
+ guidToUnit[guid] = nil
+ guidToGroup[guid] = nil
+ end
+ end
+end
+
+-- 5s poll that tries to solve the problem of X running out of range while a HoT is ticking
+-- this is not really perfect far from it in fact. If I can find a better solution I will switch to that.
+if( not HealComm.hotMonitor ) then
+ HealComm.hotMonitor = CreateFrame("Frame")
+ HealComm.hotMonitor:Hide()
+ HealComm.hotMonitor.timeElapsed = 0
+ HealComm.hotMonitor:SetScript("OnUpdate", function(self, elapsed)
+ self.timeElapsed = self.timeElapsed + elapsed
+ if( self.timeElapsed < 5 ) then return end
+ self.timeElapsed = self.timeElapsed - 5
+
+ -- For the time being, it will only remove them if they don't exist and it found a valid unit
+ -- units that leave the raid are automatically removed
+ local found
+ for guid in pairs(activeHots) do
+ if( guidToUnit[guid] and not UnitIsVisible(guidToUnit[guid]) ) then
+ removeAllRecords(guid)
+ else
+ found = true
+ end
+ end
+
+ if( not found ) then
+ self:Hide()
+ end
+ end)
+end
+
+-- After the player leaves a group, tables are wiped out or released for GC
+local wasInParty, wasInRaid
+local function clearGUIDData()
+ clearPendingHeals()
+
+ twipe(compressGUID)
+ twipe(decompressGUID)
+ twipe(activePets)
+
+ playerGUID = playerGUID or UnitGUID("player")
+ HealComm.guidToUnit = {[playerGUID] = "player"}
+ guidToUnit = HealComm.guidToUnit
+
+ HealComm.guidToGroup = {}
+ guidToGroup = HealComm.guidToGroup
+
+ HealComm.activeHots = {}
+ activeHots = HealComm.activeHots
+
+ HealComm.pendingHeals = {}
+ pendingHeals = HealComm.pendingHeals
+
+ HealComm.bucketHeals = {}
+ bucketHeals = HealComm.bucketHeals
+
+ wasInParty, wasInRaid = nil, nil
+end
+
+-- Keeps track of pet GUIDs, as pets are considered vehicles this will also map vehicle GUIDs to unit
+function HealComm:UNIT_PET(unit)
+ local pet = self.unitToPet[unit]
+ local guid = pet and UnitGUID(pet)
+
+ -- We have an active pet guid from this user and it's different, kill it
+ local activeGUID = activePets[unit]
+ if( activeGUID and activeGUID ~= guid ) then
+ removeAllRecords(activeGUID)
+
+ guidToUnit[activeGUID] = nil
+ guidToGroup[activeGUID] = nil
+ activePets[unit] = nil
+ end
+
+ -- Add the new record
+ if( guid ) then
+ guidToUnit[guid] = pet
+ guidToGroup[guid] = guidToGroup[UnitGUID(unit)]
+ activePets[unit] = guid
+ end
+end
+
+-- Keep track of party GUIDs, ignored in raids as RRU will handle that mapping
+function HealComm:PARTY_MEMBERS_CHANGED()
+ if( GetNumRaidMembers() > 0 ) then return end
+ updateDistributionChannel()
+
+ if( GetNumPartyMembers() == 0 ) then
+ if( wasInParty ) then
+ clearGUIDData()
+ end
+ return
+ end
+
+ -- Parties are not considered groups in terms of API, so fake it and pretend they are all in group 0
+ guidToGroup[playerGUID or UnitGUID("player")] = 0
+ if( not wasInParty ) then self:UNIT_PET("player") end
+
+ for i=1, MAX_PARTY_MEMBERS do
+ local unit = "party" .. i
+ if( UnitExists(unit) ) then
+ local guid = UnitGUID(unit)
+ local lastGroup = guidToGroup[guid]
+ guidToUnit[guid] = unit
+ guidToGroup[guid] = 0
+
+ if( not wasInParty or lastGroup ~= guidToGroup[guid] ) then
+ self:UNIT_PET(unit)
+ end
+ end
+ end
+
+ sanityCheckMapping()
+ wasInParty = true
+end
+
+-- Keep track of raid GUIDs
+function HealComm:RAID_ROSTER_UPDATE()
+ updateDistributionChannel()
+
+ -- Left raid, clear any cache we had
+ if( GetNumRaidMembers() == 0 ) then
+ if( wasInRaid ) then
+ clearGUIDData()
+ end
+ return
+ end
+
+ -- Add new members
+ for i=1, MAX_RAID_MEMBERS do
+ local unit = "raid" .. i
+ if( UnitExists(unit) ) then
+ local guid = UnitGUID(unit)
+ local lastGroup = guidToGroup[guid]
+ guidToUnit[guid] = unit
+ guidToGroup[guid] = select(3, GetRaidRosterInfo(i))
+
+ -- If the pets owners group changed then the pets group should be updated too
+ if( not wasInRaid or guidToGroup[guid] ~= lastGroup ) then
+ self:UNIT_PET(unit)
+ end
+ end
+ end
+
+ sanityCheckMapping()
+ wasInRaid = true
+end
+
+-- PLAYER_ALIVE = got talent data
+function HealComm:PLAYER_ALIVE()
+ self:PLAYER_TALENT_UPDATE()
+ self.eventFrame:UnregisterEvent("PLAYER_ALIVE")
+end
+
+-- Initialize the library
+function HealComm:OnInitialize()
+ -- If another instance already loaded then the tables should be wiped to prevent old data from persisting
+ -- in case of a spell being removed later on, only can happen if a newer LoD version is loaded
+ twipe(spellData)
+ twipe(hotData)
+ twipe(itemSetsData)
+ twipe(talentData)
+ twipe(averageHeal)
+
+ -- Load all of the classes formulas and such
+ LoadClassData()
+
+ -- Setup the metatables for average healing
+ for spell in pairs(spellData) do
+ averageHeal[spell] = setmetatable({spell = spell}, self.averageHealMT)
+ end
+
+ -- Cache glyphs initially
+ for id=1, GetNumGlyphSockets() do
+ local enabled, _, glyphID = GetGlyphSocketInfo(id)
+ if( enabled and glyphID ) then
+ glyphCache[glyphID] = true
+ glyphCache[id] = glyphID
+ end
+ end
+
+ self:PLAYER_EQUIPMENT_CHANGED()
+
+ -- When first logging in talent data isn't available until at least PLAYER_ALIVE, so if we don't have data
+ -- will wait for that event otherwise will just cache it right now
+ if( GetNumTalentTabs() == 0 ) then
+ self.eventFrame:RegisterEvent("PLAYER_ALIVE")
+ else
+ self:PLAYER_TALENT_UPDATE()
+ end
+
+ if( ResetChargeData ) then
+ HealComm.eventFrame:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
+ end
+
+ -- Finally, register it all
+ self.eventFrame:RegisterEvent("UNIT_SPELLCAST_SENT")
+ self.eventFrame:RegisterEvent("UNIT_SPELLCAST_START")
+ self.eventFrame:RegisterEvent("UNIT_SPELLCAST_STOP")
+ self.eventFrame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
+ self.eventFrame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
+ self.eventFrame:RegisterEvent("UNIT_SPELLCAST_DELAYED")
+ self.eventFrame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
+ self.eventFrame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
+ self.eventFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+ self.eventFrame:RegisterEvent("PLAYER_TALENT_UPDATE")
+ self.eventFrame:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
+ self.eventFrame:RegisterEvent("PLAYER_TARGET_CHANGED")
+ self.eventFrame:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
+ self.eventFrame:RegisterEvent("PLAYER_LEVEL_UP")
+ self.eventFrame:RegisterEvent("GLYPH_ADDED")
+ self.eventFrame:RegisterEvent("GLYPH_REMOVED")
+ self.eventFrame:RegisterEvent("GLYPH_UPDATED")
+ self.eventFrame:RegisterEvent("UNIT_AURA")
+
+ if( self.initialized ) then return end
+ self.initialized = true
+
+ self.resetFrame = CreateFrame("Frame")
+ self.resetFrame:Hide()
+ self.resetFrame:SetScript("OnUpdate", function(self) self:Hide() end)
+
+ -- You can't unhook secure hooks after they are done, so will hook once and the HealComm table will update with the latest functions
+ -- automagically. If a new function is ever used it'll need a specific variable to indicate those set of hooks.
+ -- By default most of these are mapped to a more generic function, but I call separate ones so I don't have to rehook
+ -- if it turns out I need to know something specific
+ hooksecurefunc("TargetUnit", function(...) HealComm:TargetUnit(...) end)
+ hooksecurefunc("SpellTargetUnit", function(...) HealComm:SpellTargetUnit(...) end)
+ hooksecurefunc("AssistUnit", function(...) HealComm:AssistUnit(...) end)
+ hooksecurefunc("UseAction", function(...) HealComm:UseAction(...) end)
+ hooksecurefunc("TargetLastFriend", function(...) HealComm:TargetLastFriend(...) end)
+ hooksecurefunc("TargetLastTarget", function(...) HealComm:TargetLastTarget(...) end)
+ hooksecurefunc("CastSpellByName", function(...) HealComm:CastSpellByName(...) end)
+
+ -- Fixes hook error for people who are not on 3.2 yet
+ if( CastSpellByID ) then
+ hooksecurefunc("CastSpellByID", function(...) HealComm:CastSpellByID(...) end)
+ end
+end
+
+-- General event handler
+local function OnEvent(self, event, ...)
+ HealComm[event](HealComm, ...)
+end
+
+-- Event handler
+HealComm.eventFrame = HealComm.frame or HealComm.eventFrame or CreateFrame("Frame")
+HealComm.eventFrame:UnregisterAllEvents()
+HealComm.eventFrame:RegisterEvent("UNIT_PET")
+HealComm.eventFrame:SetScript("OnEvent", OnEvent)
+HealComm.frame = nil
+
+-- At PLAYER_LEAVING_WORLD (Actually more like MIRROR_TIMER_STOP but anyway) UnitGUID("player") returns nil, delay registering
+-- events and set a playerGUID/playerName combo for all players on PLAYER_LOGIN not just the healers.
+function HealComm:PLAYER_LOGIN()
+ playerGUID = UnitGUID("player")
+ playerName = UnitName("player")
+ playerLevel = UnitLevel("player")
+
+ -- Oddly enough player GUID is not available on file load, so keep the map of player GUID to themselves too
+ guidToUnit[playerGUID] = "player"
+
+ if( isHealerClass ) then
+ self:OnInitialize()
+ LoadRaceData()
+ elseif LoadRaceData then
+ twipe(hotData)
+ eventRegistered["SPELL_AURA_APPLIED"] = true
+ self.eventFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+ LoadRaceData()
+ end
+
+ self.eventFrame:UnregisterEvent("PLAYER_LOGIN")
+ self.eventFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
+ self.eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
+ self.eventFrame:RegisterEvent("PARTY_MEMBERS_CHANGED")
+ self.eventFrame:RegisterEvent("RAID_ROSTER_UPDATE")
+
+ self:ZONE_CHANGED_NEW_AREA()
+ self:RAID_ROSTER_UPDATE()
+ self:PARTY_MEMBERS_CHANGED()
+end
+
+if( not IsLoggedIn() ) then
+ HealComm.eventFrame:RegisterEvent("PLAYER_LOGIN")
+else
+ HealComm:PLAYER_LOGIN()
+end
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/oUF_HealComm4.lua b/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/oUF_HealComm4.lua
new file mode 100644
index 0000000..6125287
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/oUF_HealComm4.lua
@@ -0,0 +1,216 @@
+--[[
+# Element: Health Prediction Bars
+
+Handles the visibility and updating of incoming heals and heal/damage absorbs.
+
+## Widget
+
+HealthPrediction - A `table` containing references to sub-widgets and options.
+
+## Sub-Widgets
+
+myBar - A `StatusBar` used to represent incoming heals from the player.
+otherBar - A `StatusBar` used to represent incoming heals from others.
+
+## Notes
+
+A default texture will be applied to the StatusBar widgets if they don't have a texture set.
+A default texture will be applied to the Texture widgets if they don't have a texture or a color set.
+
+## Options
+
+.maxOverflow - The maximum amount of overflow past the end of the health bar. Set this to 1 to disable the overflow.
+ Defaults to 1.05 (number)
+
+## Examples
+
+ -- Position and size
+ local myBar = CreateFrame('StatusBar', nil, self.Health)
+ myBar:SetPoint('TOP')
+ myBar:SetPoint('BOTTOM')
+ myBar:SetPoint('LEFT', self.Health:GetStatusBarTexture(), 'RIGHT')
+ myBar:SetWidth(200)
+
+ local otherBar = CreateFrame('StatusBar', nil, self.Health)
+ otherBar:SetPoint('TOP')
+ otherBar:SetPoint('BOTTOM')
+ otherBar:SetPoint('LEFT', myBar:GetStatusBarTexture(), 'RIGHT')
+ otherBar:SetWidth(200)
+
+ -- Register with oUF
+ self.HealthPrediction = {
+ myBar = myBar,
+ otherBar = otherBar,
+ maxOverflow = 1.05
+ }
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF or oUF
+assert(oUF, "oUF_HealComm4 was unable to locate oUF install")
+
+local healpredict = HealPredict
+assert(healpredict, "oUF_HealComm4 was unable to locate HealPredict")
+
+local UnitHealth = UnitHealth
+local UnitHealthMax = UnitHealthMax
+local UnitName = UnitName
+
+local enabledUF, enabled = {}, nil
+
+local function Update(self)
+ local unit = self.unit
+ local element = self.HealCommBar
+
+ --[[ Callback: HealthPrediction:PreUpdate(unit)
+ Called before the element has been updated.
+
+ * self - the HealthPrediction element
+ * unit - the unit for which the update has been triggered (string)
+ --]]
+ if element.PreUpdate then
+ element:PreUpdate(unit)
+ end
+
+ local myIncomingHeal = healpredict.UnitGetIncomingHeals(unit, UnitName("player")) or 0
+ local allIncomingHeal = healpredict.UnitGetIncomingHeals(unit) or 0
+ local health = UnitHealth(unit)
+ local maxHealth = UnitHealthMax(unit)
+ local maxOverflowHP = maxHealth * element.maxOverflow
+ local otherIncomingHeal = 0
+
+ if health + allIncomingHeal > maxOverflowHP then
+ allIncomingHeal = maxOverflowHP - health
+ end
+
+ if allIncomingHeal < myIncomingHeal then
+ myIncomingHeal = allIncomingHeal
+ else
+ otherIncomingHeal = allIncomingHeal - myIncomingHeal
+ end
+
+ if element.myBar then
+ element.myBar:SetMinMaxValues(0, maxHealth)
+ element.myBar:SetValue(myIncomingHeal)
+ element.myBar:Show()
+ end
+
+ if element.otherBar then
+ element.otherBar:SetMinMaxValues(0, maxHealth)
+ element.otherBar:SetValue(otherIncomingHeal)
+ element.otherBar:Show()
+ end
+
+ --[[ Callback: HealthPrediction:PostUpdate(unit, myIncomingHeal, otherIncomingHeal)
+ Called after the element has been updated.
+
+ * self - the HealthPrediction element
+ * unit - the unit for which the update has been triggered (string)
+ * myIncomingHeal - the amount of incoming healing done by the player (number)
+ * otherIncomingHeal - the amount of incoming healing done by others (number)
+ --]]
+ if element.PostUpdate then
+ return element:PostUpdate(unit, myIncomingHeal, otherIncomingHeal)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: HealthPrediction.Override(self, event, unit)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event
+ --]]
+ return (self.HealCommBar.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, "ForceUpdate", element.__owner.unit)
+end
+
+local function UpdateAllUnits(...)
+ local all_units = {...}
+ local units = { }
+
+ for _, unit in pairs(all_units) do
+ units[unit] = true
+ end
+
+ for j = 1, #enabledUF do
+ local frame = enabledUF[j]
+
+ if units[UnitName(frame.unit)] and frame:IsVisible() then
+ Path(frame)
+ end
+ end
+end
+
+local function ToggleCallbacks(toggle)
+ if toggle and not enabled and #enabledUF > 0 then
+ healpredict.RegisterCallback("oUF_HealComm", UpdateAllUnits)
+
+ enabled = true
+ elseif not toggle and enabled and #enabledUF == 0 then
+ healpredict.UnregisterCallback("oUF_HealComm")
+
+ enabled = nil
+ end
+end
+
+local function Enable(self)
+ local element = self.HealCommBar
+
+ if element then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent("UNIT_HEALTH", Path)
+ self:RegisterEvent("UNIT_MAXHEALTH", Path)
+
+ if not element.maxOverflow then
+ element.maxOverflow = 1.05
+ end
+
+ if element.myBar and element.myBar:IsObjectType("StatusBar") and not element.myBar:GetStatusBarTexture() then
+ element.myBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
+ end
+
+ if element.otherBar and element.otherBar:IsObjectType("StatusBar") and not element.otherBar:GetStatusBarTexture() then
+ element.otherBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
+ end
+
+ enabledUF[#enabledUF + 1] = self
+ ToggleCallbacks(true)
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.HealCommBar
+
+ if element then
+ if element.myBar then
+ element.myBar:Hide()
+ end
+
+ if element.otherBar then
+ element.otherBar:Hide()
+ end
+
+ self:UnregisterEvent("UNIT_HEALTH", Path)
+ self:UnregisterEvent("UNIT_MAXHEALTH", Path)
+
+ for i = 1, #enabledUF do
+ if enabledUF[i] == self then
+ table.remove(enabledUF, i)
+ break
+ end
+ end
+
+ ToggleCallbacks(false)
+ end
+end
+
+oUF:AddElement("HealComm4", Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/oUF_HealComm4.xml b/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/oUF_HealComm4.xml
new file mode 100644
index 0000000..8403476
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/oUF_HealComm4.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_Plugins.xml b/ElvUI/Libraries/oUF_Plugins/oUF_Plugins.xml
new file mode 100644
index 0000000..063fc71
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_Plugins.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_RaidDebuffs/oUF_RaidDebuffs.lua b/ElvUI/Libraries/oUF_Plugins/oUF_RaidDebuffs/oUF_RaidDebuffs.lua
new file mode 100644
index 0000000..a424865
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_RaidDebuffs/oUF_RaidDebuffs.lua
@@ -0,0 +1,245 @@
+local _, ns = ...
+local oUF = ns.oUF or oUF
+
+local select, pairs, type = select, pairs, type
+local abs = math.abs
+local format = string.format
+local wipe = table.wipe
+
+local GetSpellInfo = GetSpellInfo
+local GetTime = GetTime
+local UnitAura = UnitAura
+
+local addon = {}
+ns.oUF_RaidDebuffs = addon
+oUF_RaidDebuffs = ns.oUF_RaidDebuffs
+if not _G.oUF_RaidDebuffs then
+ _G.oUF_RaidDebuffs = addon
+end
+
+local debuff_data = {}
+addon.DebuffData = debuff_data
+
+addon.ShowDispellableDebuff = true
+addon.MatchBySpellName = false
+
+addon.priority = 10
+
+local function add(spell, priority, stackThreshold)
+ if addon.MatchBySpellName and type(spell) == "number" then
+ spell = GetSpellInfo(spell)
+ end
+
+ if spell then
+ debuff_data[spell] = {
+ priority = (addon.priority + priority),
+ stackThreshold = (stackThreshold or 0),
+ }
+ end
+end
+
+function addon:RegisterDebuffs(t)
+ for spell, value in pairs(t) do
+ if type(value) == "boolean" then
+ t[spell] = {
+ ["enable"] = value,
+ ["priority"] = 0,
+ ["stackThreshold"] = 0
+ }
+ else
+ if t[spell].enable then
+ add(spell, t[spell].priority, t[spell].stackThreshold)
+ end
+ end
+ end
+end
+
+function addon:ResetDebuffData()
+ wipe(debuff_data)
+end
+
+local DispellColor = {
+ ["Magic"] = {.2, .6, 1},
+ ["Curse"] = {.6, 0, 1},
+ ["Disease"] = {.6, .4, 0},
+ ["Poison"] = {0, .6, 0}
+}
+
+local DispellPriority = {
+ ["Magic"] = 4,
+ ["Curse"] = 3,
+ ["Disease"] = 2,
+ ["Poison"] = 1
+}
+
+local function formatTime(s)
+ if s < 10 then
+ return format("%.1f", s)
+ elseif s > 60 then
+ return format("%dm", s / 60)
+ else
+ return format("%d", s)
+ end
+end
+
+local function OnUpdate(self, elapsed)
+ self.elapsed = self.elapsed + elapsed
+
+ if self.elapsed >= 0.1 then
+ local timeLeft
+
+ if self.reverse then
+ timeLeft = abs((self.endTime - GetTime()) - self.duration)
+ else
+ timeLeft = self.endTime - GetTime()
+ end
+
+ if timeLeft > 0 then
+ self.time:SetText(formatTime(timeLeft))
+ else
+ self:SetScript("OnUpdate", nil)
+ self.time:Hide()
+ end
+
+ self.elapsed = 0
+ end
+end
+
+local function UpdateDebuff(self, name, icon, count, debuffType, duration, endTime, spellId, stackThreshold)
+ local element = self.RaidDebuffs
+
+ if name and count >= stackThreshold then
+ element.icon:SetTexture(icon)
+ element.icon:Show()
+ element.duration = duration
+
+ if element.count then
+ if count and count > 1 then
+ element.count:SetText(count)
+ element.count:Show()
+ else
+ element.count:SetText("")
+ element.count:Hide()
+ end
+ end
+
+ if spellId and ElvUI[1].ReverseTimer[spellId] then
+ element.reverse = true
+ else
+ element.reverse = nil
+ end
+
+ if element.time then
+ if duration and (duration > 0) then
+ element.endTime = endTime
+ element.nextUpdate = 0
+ element.elapsed = 0
+ element:SetScript("OnUpdate", OnUpdate)
+ element.time:Show()
+ else
+ element:SetScript("OnUpdate", nil)
+ element.time:Hide()
+ end
+ end
+
+ if element.cd then
+ if duration and (duration > 0) then
+ element.cd:SetCooldown(endTime - duration, duration)
+ element.cd:Show()
+ else
+ element.cd:Hide()
+ end
+ end
+
+ local c = DispellColor[debuffType] or ElvUI[1].media.bordercolor
+ element:SetBackdropBorderColor(c[1], c[2], c[3])
+
+ element:Show()
+ else
+ element:Hide()
+ end
+end
+
+local function Update(self, event, unit)
+ if unit ~= self.unit then return end
+
+ local element = self.RaidDebuffs
+
+ local _name, _icon, _count, _dtype, _duration, _endTime, _spellId
+ local _stackThreshold = 0
+
+ if element.forceShow then
+ _spellId = 47540
+ _name, _, _icon = GetSpellInfo(_spellId)
+ _count = 5
+ _dtype = "Magic"
+ _duration = 0
+ _endTime = 60
+ _stackThreshold = 0
+ else
+ local _, name, icon, count, debuffType, duration, expirationTime, spellId
+ local _priority, priority = 0, 0
+
+ for i = 1, 40 do
+ name, _, icon, count, debuffType, duration, expirationTime, _, _, _, spellId = UnitAura(unit, i, "HARMFUL")
+ if not name then break end
+
+ --we couldn't dispell if the unit its charmed, or its not friendly
+ if addon.ShowDispellableDebuff and (element.showDispellableDebuff ~= false) and debuffType then
+ priority = DispellPriority[debuffType] or 0
+
+ if priority > _priority then
+ _priority, _name, _icon, _count, _dtype, _duration, _endTime, _spellId = priority, name, icon, count, debuffType, duration, expirationTime, spellId
+ end
+ end
+
+ local debuff
+ if element.onlyMatchSpellID then
+ debuff = debuff_data[spellId]
+ else
+ if debuff_data[spellId] then
+ debuff = debuff_data[spellId]
+ else
+ debuff = debuff_data[name]
+ end
+ end
+
+ priority = debuff and debuff.priority
+
+ if priority and priority > _priority then
+ _priority, _name, _icon, _count, _dtype, _duration, _endTime, _spellId = priority, name, icon, count, debuffType, duration, expirationTime, spellId
+ end
+ end
+ end
+
+ if _name then
+ local data = debuff_data[addon.MatchBySpellName and _name or _spellId]
+ _stackThreshold = data and data.stackThreshold or _stackThreshold
+ end
+
+ UpdateDebuff(self, _name, _icon, _count, _dtype, _duration, _endTime, _spellId, _stackThreshold)
+
+ --Reset the DispellPriority
+ DispellPriority["Magic"] = 4
+ DispellPriority["Curse"] = 3
+ DispellPriority["Disease"] = 2
+ DispellPriority["Poison"] = 1
+end
+
+local function Enable(self)
+ if self.RaidDebuffs then
+ self:RegisterEvent("UNIT_AURA", Update)
+
+ return true
+ end
+end
+
+local function Disable(self)
+ if self.RaidDebuffs then
+ self:UnregisterEvent("UNIT_AURA", Update)
+
+ self.RaidDebuffs:Hide()
+ end
+end
+
+oUF:AddElement("RaidDebuffs", Update, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_ResComm/LibResComm-1.0/LibResComm-1.0.lua b/ElvUI/Libraries/oUF_Plugins/oUF_ResComm/LibResComm-1.0/LibResComm-1.0.lua
new file mode 100644
index 0000000..c478767
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_ResComm/LibResComm-1.0/LibResComm-1.0.lua
@@ -0,0 +1,411 @@
+--[[
+ Name: LibResComm-1.0
+ Revision: $Revision: 91 $
+ Author(s): DathRarhek (Polleke) (polleke@gmail.com)
+ Documentation: http://www.wowace.com/index.php/LibResComm-1.0
+ SVN: svn://svn.wowace.com/wow/librescomm-1-0/mainline/trunk
+ Description: Keeps track of resurrection spells cast in the raid group
+ Dependencies: LibStub, CallbackHandler-1.0
+]]
+
+local MAJOR_VERSION = "LibResComm-1.0"
+local MINOR_VERSION = 90000 + tonumber(("$Revision: 92 $"):match("%d+"))
+
+local lib = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION)
+if not lib then return end
+
+if lib.disable then
+ lib.disable()
+end
+
+------------------------------------------------------------------------
+-- Localization
+--
+
+local L = {
+ -- use global string for locale independence
+ CORPSE_OF = "^" .. CORPSE_TOOLTIP:gsub("%%s", "(.+)"),
+
+ -- needs to match return values from HasSoulstone()
+ ["Reincarnate"] = "Reincarnate",
+ ["Twisting Nether"] = "Twisting Nether",
+ ["Use Soulstone"] = "Use Soulstone",
+
+ -- sensible text to show
+ ["Soulstone"] = "Soulstone",
+}
+
+local LOCALE = GetLocale()
+if LOCALE == "deDE" then
+-- L["Reincarnate"] = "Reinkarnation"
+ L["Soulstone"] = "Seelenstein"
+-- L["Twisting Nether"] = "Wirbelnder Nether"
+-- L["Use Soulstone"] = "Seelenstein benutzen"
+elseif LOCALE == "esES" or LOCALE == "esMX" then
+-- L["Reincarnate"] = "Reencarnación"
+ L["Soulstone"] = "Piedra de alma"
+-- L["Twisting Nether"] = "Vacío Abisal"
+-- L["Use Soulstone"] = "Usar piedra de alma"
+elseif LOCALE == "frFR" then
+-- L["Reincarnate"] = "Réincarner"
+ L["Soulstone"] = "Pierre d'âme"
+-- L["Twisting Nether"] = "Néant distordu"
+-- L["Use Soulstone"] = "Utilisez Pierre d'âme"
+elseif LOCALE == "ruRU" then
+ L.CORPSE_OF = "^" .. CORPSE_TOOLTIP:gsub("%|%S+%(%%s%)", "(.+)")
+
+-- L["Reincarnate"] = "Возродиться"
+ L["Soulstone"] = "Камень души"
+-- L["Twisting Nether"] = "Круговерть Пустоты"
+-- L["Use Soulstone"] = "Использование камня души"
+elseif LOCALE == "koKR" then
+-- L["Reincarnate"] = "윤회"
+ L["Soulstone"] = "영혼석"
+-- L["Twisting Nether"] = "뒤틀린 황천"
+-- L["Use Soulstone"] = "영혼석 사용"
+elseif LOCALE == "zhCN" then
+-- L["Reincarnate"] = "复生"
+ L["Soulstone"] = "灵魂石"
+-- L["Twisting Nether"] = "扭曲虚空"
+-- L["Use Soulstone"] = "使用灵魂石"
+elseif LOCALE == "zhTW" then
+-- L["Reincarnate"] = "復生效果"
+ L["Soulstone"] = "靈魂石"
+-- L["Twisting Nether"] = "扭曲虛空"
+-- L["Use Soulstone"] = "靈魂石復活效果"
+end
+
+local soulstoneToken = {
+ [L["Use Soulstone"]] = "SS",
+ [L["Reincarnate"]] = "RE",
+ [L["Twisting Nether"]] = "TN",
+}
+
+local soulstoneText = {
+ ["SS"] = L["Soulstone"],
+ ["RE"] = GetSpellInfo(20608), -- just use Reincarnation spell name
+ ["TN"] = L["Twisting Nether"],
+}
+
+------------------------------------------------------------------------
+-- Event frame
+--
+
+lib.eventFrame = lib.eventFrame or CreateFrame("Frame")
+lib.eventFrame:SetScript("OnEvent", function(this, event, ...)
+ this[event](this, ...)
+end)
+lib.eventFrame:UnregisterAllEvents()
+
+------------------------------------------------------------------------
+-- Embed CallbackHandler-1.0
+--
+
+if not lib.Callbacks then
+ lib.Callbacks = LibStub("CallbackHandler-1.0"):New(lib)
+end
+
+------------------------------------------------------------------------
+-- Locals
+--
+
+local playerName = UnitName("player")
+
+-- Last target name from UNIT_SPELLCAST_SENT
+local sentTargetName = nil
+
+-- Mouse down target
+local mouseDownTarget = nil
+local worldFrameHook = nil
+
+-- Battleground/Arena/Group Indicators
+local inBattlegroundOrArena = nil
+
+-- For tracking STOP messages
+local isCasting = nil
+
+-- Tracking resses
+local activeRes = {}
+
+local resSpells = {
+ [GetSpellInfo(50769)]=true, -- Revive
+ [GetSpellInfo(20484)]=true, -- Rebirth
+ [GetSpellInfo(7328)]=true, -- Redemption
+ [GetSpellInfo(2006)]=true, -- Resurrection
+ [GetSpellInfo(2008)]=true, -- Ancestral Spirit
+}
+
+------------------------------------------------------------------------
+-- Utilities
+--
+
+local function commSend(contents, distribution, target)
+ if not (oRA and oRA:HasModule("ParticipantPassive") and oRA:IsModuleActive("ParticipantPassive") or CT_RA_Stats) then
+ SendAddonMessage("CTRA", contents, distribution or (inBattlegroundOrArena and "BATTLEGROUND" or "RAID"), target)
+ end
+end
+
+------------------------------------------------------------------------
+-- Event Handlers
+--
+
+function lib.eventFrame:UNIT_SPELLCAST_SENT(unit, _, _, targetName)
+ sentTargetName = targetName:match("^([^%-]+)")
+end
+
+function lib.eventFrame:UNIT_SPELLCAST_START(unit, spellName)
+ if unit ~= "player" then return end
+ if not resSpells[spellName] then return end
+
+ isCasting = true
+
+ local target = sentTargetName
+ if not sentTargetName or sentTargetName == UNKNOWN then
+ target = mouseDownTarget
+ end
+
+ if not target and GameTooltipTextLeft1:IsVisible() then
+ -- check tooltip in case of mouseover casting on a corpse whose spirit has been released
+ target = GameTooltipTextLeft1:GetText():match(L.CORPSE_OF)
+ end
+
+ if not target then
+ -- still nothing :(
+ return
+ end
+
+ local endTime = select(6, UnitCastingInfo(unit)) or (GetTime() + 10) * 1000
+ endTime = endTime / 1000
+
+ activeRes[playerName] = target
+
+ lib.Callbacks:Fire("ResComm_ResStart", playerName, endTime, target)
+ commSend(("RES %s"):format(target))
+end
+
+function lib.eventFrame:CHAT_MSG_ADDON(prefix, msg, distribution, sender)
+ if prefix ~= "CTRA" then return end
+ if sender == playerName then return end
+ sender = sender:match("^([^%-]+)")
+
+ local target
+ for cmd, targetName in msg:gmatch("(%a+)%s?([^#]*)") do
+ -- A lot of garbage can come in, make absolutely sure we have a decent message
+ if cmd == "RES" and targetName ~= "" and targetName ~= UNKNOWN then
+
+ local endTime = select(6, UnitCastingInfo(sender)) or (GetTime() + 10)*1000
+
+ if endTime and targetName then
+ endTime = endTime / 1000
+ activeRes[sender] = targetName
+ lib.Callbacks:Fire("ResComm_ResStart", sender, endTime, targetName)
+ end
+ elseif cmd == "RESNO" or cmd == "RESYES" then
+ if activeRes[sender] then
+ target = activeRes[sender]
+ activeRes[sender] = nil
+ end
+ lib.Callbacks:Fire("ResComm_ResEnd", sender, target, cmd == "RESYES" and true)
+ elseif cmd == "RESSED" then
+ if activeRes[sender] then
+ target = activeRes[sender]
+ activeRes[sender] = nil
+ end
+ lib.Callbacks:Fire("ResComm_Ressed", sender)
+ elseif cmd == "CANRES" then
+ lib.Callbacks:Fire("ResComm_CanRes", sender, targetName, targetName and soulstoneText[targetName]) -- send token and text with callback
+ elseif cmd == "NORESSED" then
+ lib.Callbacks:Fire("ResComm_ResExpired", sender)
+ end
+ end
+end
+
+function lib.eventFrame:UNIT_SPELLCAST_SUCCEEDED(unit, spellName)
+ if unit ~= "player" or not isCasting then return end
+
+ local target = activeRes[playerName]
+ if activeRes[playerName] then
+ activeRes[playerName] = nil
+ end
+
+ lib.Callbacks:Fire("ResComm_ResEnd", playerName, target, true)
+ commSend("RESYES")
+ isCasting = false
+end
+
+function lib.eventFrame:UNIT_SPELLCAST_STOP(unit, spellName)
+ if unit ~= "player" or not isCasting then return end
+
+ local target = activeRes[playerName]
+ if activeRes[playerName] then
+ activeRes[playerName] = nil
+ end
+
+ lib.Callbacks:Fire("ResComm_ResEnd", playerName, target, false)
+ commSend("RESNO")
+ isCasting = false
+end
+
+lib.eventFrame.UNIT_SPELLCAST_FAILED = lib.eventFrame.UNIT_SPELLCAST_STOP
+lib.eventFrame.UNIT_SPELLCAST_INTERRUPTED = lib.eventFrame.UNIT_SPELLCAST_STOP
+
+function lib.eventFrame:PLAYER_ENTERING_WORLD()
+ local it = select(2, IsInInstance())
+ inBattlegroundOrArena = (it == "pvp") or (it == "arena")
+end
+
+------------------------------------------------------------------------
+-- Public Functions
+
+--[[
+ IsUnitBeingRessed(unit)
+ Checks if a unit is being ressurected at that moment.
+ Arguments:
+ unit - string; name of a friendly player
+ Returns:
+ isBeingRessed - boolean; true when unit is being ressed, false otherwise
+ resser - string; name of the player ressing the unit
+]]--
+
+function lib:IsUnitBeingRessed(unit)
+ for resser, ressed in pairs(activeRes) do
+ if unit == ressed then
+ return true, resser
+ end
+ end
+ return false
+end
+
+------------------------------------------------------------------------
+-- Hooks
+--
+
+-- Credits to Ora2
+function lib:worldFrameOnMouseDown()
+ if GameTooltipTextLeft1:IsVisible() then
+ mouseDownTarget = GameTooltipTextLeft1:GetText():match(L.CORPSE_OF)
+ end
+end
+
+function lib:popupFuncRessed()
+ lib.Callbacks:Fire("ResComm_Ressed", playerName)
+ commSend("RESSED")
+end
+
+function lib:popupFuncCanRes()
+ local kind = HasSoulstone()
+ if not kind then return end
+
+ lib.Callbacks:Fire("ResComm_CanRes", playerName)
+ commSend("CANRES")
+
+ local token = soulstoneToken[kind]
+ if token then
+ -- send a second comm with a token representing the type of self-res available
+ commSend("CANRES " .. token)
+ end
+end
+
+function lib:popupFuncExpired()
+ lib.Callbacks:Fire("ResComm_ResExpired", playerName)
+ commSend("NORESSED")
+end
+
+function lib:noop()
+end
+
+------------------------------------------------------------------------
+-- Register events and hooks
+--
+
+function lib:start()
+ lib.eventFrame:RegisterEvent("CHAT_MSG_ADDON")
+
+ lib.eventFrame:RegisterEvent("UNIT_SPELLCAST_FAILED")
+ lib.eventFrame:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
+ lib.eventFrame:RegisterEvent("UNIT_SPELLCAST_SENT")
+ lib.eventFrame:RegisterEvent("UNIT_SPELLCAST_START")
+ lib.eventFrame:RegisterEvent("UNIT_SPELLCAST_STOP")
+ lib.eventFrame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
+
+ lib.eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
+
+ worldFrameHook = WorldFrame:GetScript("OnMouseDown")
+ if not worldFrameHook then
+ worldFrameHook = lib.noop
+ end
+
+ WorldFrame:SetScript("OnMouseDown", function(...)
+ lib:worldFrameOnMouseDown()
+ worldFrameHook(...)
+ end)
+
+ local res = StaticPopupDialogs["RESURRECT"].OnShow
+ StaticPopupDialogs["RESURRECT"].OnShow = function(...)
+ lib:popupFuncRessed()
+ res(...)
+ end
+
+ local resNoSick = StaticPopupDialogs["RESURRECT_NO_SICKNESS"].OnShow
+ StaticPopupDialogs["RESURRECT_NO_SICKNESS"].OnShow = function(...)
+ lib:popupFuncRessed()
+ resNoSick(...)
+ end
+
+ local resNoTimer = StaticPopupDialogs["RESURRECT_NO_TIMER"].OnShow
+ StaticPopupDialogs["RESURRECT_NO_TIMER"].OnShow = function(...)
+ lib:popupFuncRessed()
+ resNoTimer(...)
+ end
+
+ local death = StaticPopupDialogs["DEATH"].OnShow
+ StaticPopupDialogs["DEATH"].OnShow = function(...)
+ lib:popupFuncCanRes()
+ death(...)
+ end
+
+ if not StaticPopupDialogs["RESURRECT"].OnCancel then
+ StaticPopupDialogs["RESURRECT"].OnCancel = function() lib:popupFuncExpired() end
+ else
+ local resurrect = StaticPopupDialogs["RESURRECT"].OnCancel
+ StaticPopupDialogs["RESURRECT"].OnCancel = function(...)
+ lib:popupFuncExpired()
+ resurrect(...)
+ end
+ end
+
+ if not StaticPopupDialogs["RESURRECT_NO_SICKNESS"].OnCancel then
+ StaticPopupDialogs["RESURRECT_NO_SICKNESS"].OnCancel = function() lib:popupFuncExpired() end
+ else
+ local resNoSick = StaticPopupDialogs["RESURRECT_NO_SICKNESS"].OnCancel
+ StaticPopupDialogs["RESURRECT_NO_SICKNESS"].OnCancel = function(...)
+ lib:popupFuncExpired()
+ resNoSick(...)
+ end
+ end
+
+ if not StaticPopupDialogs["RESURRECT_NO_TIMER"].OnCancel then
+ StaticPopupDialogs["RESURRECT_NO_TIMER"].OnCancel = function()
+ if not StaticPopup_FindVisible("DEATH") then lib:popupFuncExpired() end
+ end
+ else
+ local resNoTimer = StaticPopupDialogs["RESURRECT_NO_TIMER"].OnCancel
+ StaticPopupDialogs["RESURRECT_NO_TIMER"].OnCancel = function(...)
+ if not StaticPopup_FindVisible("DEATH") then lib:popupFuncExpired() end
+ resNoTimer(...)
+ end
+ end
+end
+
+------------------------------------------------------------------------
+-- Start library
+--
+
+lib.disable = function()
+ lib.worldFrameOnMouseDown = lib.noop
+ lib.popupFuncRessed = lib.noop
+ lib.popupFuncCanRes = lib.noop
+ lib.popupFuncExpired = lib.noop
+ lib.eventFrame:UnregisterAllEvents()
+end
+lib:start()
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_ResComm/oUF_ResComm.lua b/ElvUI/Libraries/oUF_Plugins/oUF_ResComm/oUF_ResComm.lua
new file mode 100644
index 0000000..3de1ceb
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_ResComm/oUF_ResComm.lua
@@ -0,0 +1,175 @@
+--[[
+# Element: Resurrect Indicator
+
+Handles the visibility and updating of an indicator based on the unit's incoming resurrect status.
+
+## Widget
+
+ResurrectIndicator - A `Texture` used to display if the unit has an incoming resurrect.
+
+## Notes
+
+A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
+
+## Examples
+
+ -- Position and size
+ local ResurrectIndicator = self:CreateTexture(nil, 'OVERLAY')
+ ResurrectIndicator:SetSize(16, 16)
+ ResurrectIndicator:SetPoint('TOPRIGHT', self)
+
+ -- Register it with oUF
+ self.ResurrectIndicator = ResurrectIndicator
+--]]
+
+local _, ns = ...
+local oUF = ns.oUF
+assert(oUF, "oUF_ResComm was unable to locate oUF install")
+
+local LRC = LibStub("LibResComm-1.0")
+
+local tremove = table.remove
+
+local UnitIsDead = UnitIsDead
+local UnitIsGhost = UnitIsGhost
+local UnitName = UnitName
+
+local enabledUF, enabled = {}
+
+local function Update(self, event, unit, succeeded)
+ if not unit or self.unit ~= unit then return end
+
+ local element = self.ResurrectIndicator
+
+ --[[ Callback: ResurrectIndicator:PreUpdate()
+ Called before the element has been updated.
+
+ * self - the ResurrectIndicator element
+ --]]
+ if element.PreUpdate then
+ element:PreUpdate()
+ end
+
+ local incomingResurrect
+ if UnitIsDead(unit) or UnitIsGhost(unit) then
+ if event == "ResComm_ResStart" or event == "ResComm_CanRes" or event == "ResComm_Ressed" or (event == "ResComm_ResEnd" and succeeded) then
+ if event ~= "ResComm_ResStart" then
+ element.ressed = true
+ end
+
+ element:Show()
+ incomingResurrect = true
+ elseif (event == "ResComm_ResEnd" and not succeeded and not element.ressed) or event == "ResComm_ResExpired" then
+ element:Hide()
+ element.ressed = nil
+ end
+ else
+ element:Hide()
+ end
+
+ --[[ Callback: ResurrectIndicator:PostUpdate(incomingResurrect)
+ Called after the element has been updated.
+
+ * self - the ResurrectIndicator element
+ * incomingResurrect - indicates if the unit has an incoming resurrection (boolean)
+ --]]
+ if element.PostUpdate then
+ return element:PostUpdate(incomingResurrect)
+ end
+end
+
+local function Path(self, ...)
+ --[[ Override: ResurrectIndicator.Override(self, event, unit)
+ Used to completely override the internal update function.
+
+ * self - the parent object
+ * event - the event triggering the update (string)
+ * unit - the unit accompanying the event (string)
+ --]]
+ return (self.ResurrectIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+ return Path(element.__owner, "ForceUpdate", element.__owner.unit)
+end
+
+local function ResComm_Update(event, ...)
+ local sender, endTime, target, succeeded
+
+ if event == "ResComm_ResStart" then
+ sender, endTime, target = ...
+ elseif event == "ResComm_ResEnd" then
+ sender, target, succeeded = ...
+ else
+ target = ...
+ end
+
+ for i = 1, #enabledUF do
+ local frame = enabledUF[i]
+
+ if frame.unit and UnitName(frame.unit) == target then
+ Path(frame, event, frame.unit, succeeded)
+ end
+ end
+end
+
+local function ToggleCallbacks(toggle)
+ if toggle and not enabled and #enabledUF > 0 then
+ LRC.RegisterCallback("oUF_ResComm", "ResComm_CanRes", ResComm_Update)
+ LRC.RegisterCallback("oUF_ResComm", "ResComm_Ressed", ResComm_Update)
+ LRC.RegisterCallback("oUF_ResComm", "ResComm_ResExpired", ResComm_Update)
+ LRC.RegisterCallback("oUF_ResComm", "ResComm_ResStart", ResComm_Update)
+ LRC.RegisterCallback("oUF_ResComm", "ResComm_ResEnd", ResComm_Update)
+
+ enabled = true
+ elseif not toggle and enabled and #enabledUF == 0 then
+ LRC.UnregisterCallback("oUF_ResComm", "ResComm_CanRes")
+ LRC.UnregisterCallback("oUF_ResComm", "ResComm_Ressed")
+ LRC.UnregisterCallback("oUF_ResComm", "ResComm_ResExpired")
+ LRC.UnregisterCallback("oUF_ResComm", "ResComm_ResStart")
+ LRC.UnregisterCallback("oUF_ResComm", "ResComm_ResEnd")
+
+ enabled = nil
+ end
+end
+
+local function Enable(self)
+ local element = self.ResurrectIndicator
+
+ if element then
+ element.__owner = self
+ element.ForceUpdate = ForceUpdate
+
+ self:RegisterEvent("UNIT_HEALTH", Path)
+
+ if element:IsObjectType("Texture") and not element:GetTexture() then
+ element:SetTexture([[Interface\Icons\Spell_Holy_Resurrection]])
+ end
+
+ enabledUF[#enabledUF + 1] = self
+ ToggleCallbacks(true)
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.ResurrectIndicator
+
+ if element then
+ element:Hide()
+
+ self:UnregisterEvent("UNIT_HEALTH", Path)
+
+ for i = 1, #enabledUF do
+ if enabledUF[i] == self then
+ tremove(enabledUF, i)
+ break
+ end
+ end
+
+ ToggleCallbacks(false)
+ end
+end
+
+oUF:AddElement("ResurrectIndicator", Path, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_ResComm/oUF_ResComm.xml b/ElvUI/Libraries/oUF_Plugins/oUF_ResComm/oUF_ResComm.xml
new file mode 100644
index 0000000..0e87af1
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_ResComm/oUF_ResComm.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_Trinkets/oUF_Trinkets.lua b/ElvUI/Libraries/oUF_Plugins/oUF_Trinkets/oUF_Trinkets.lua
new file mode 100644
index 0000000..5da47b9
--- /dev/null
+++ b/ElvUI/Libraries/oUF_Plugins/oUF_Trinkets/oUF_Trinkets.lua
@@ -0,0 +1,100 @@
+local _, ns = ...
+local oUF = ns.oUF or oUF
+assert(oUF, "oUF_Trinkets was unable to locate oUF install")
+
+local GetTime = GetTime
+local IsInInstance = IsInInstance
+local UnitExists = UnitExists
+local UnitFactionGroup = UnitFactionGroup
+local UnitIsPlayer = UnitIsPlayer
+local UnitGUID = UnitGUID
+
+local trinketSpells = {
+ [7744] = 45,
+ [42292] = 120,
+ [59752] = 120,
+}
+
+local function GetTrinketIcon(unit)
+ if UnitFactionGroup(unit) == "Horde" then
+ return "Interface\\Icons\\INV_Jewelry_TrinketPVP_02"
+ else
+ return "Interface\\Icons\\INV_Jewelry_TrinketPVP_01"
+ end
+end
+
+local function Update(self, event, ...)
+ local element = self.Trinket
+
+ local _, instanceType = IsInInstance()
+ if instanceType ~= "arena" then
+ element:Hide()
+ return
+ else
+ element:Show()
+ end
+
+ if element.PreUpdate then
+ element:PreUpdate(event)
+ end
+
+ if event == "COMBAT_LOG_EVENT_UNFILTERED" then
+ local _, eventType, sourceGUID, _, _, _, _, _, spellID = ...
+
+ if eventType == "SPELL_CAST_SUCCESS" and trinketSpells[spellID] and sourceGUID == UnitGUID(self.unit) then
+ CooldownFrame_SetTimer(element.cooldownFrame, GetTime(), trinketSpells[spellID], 1)
+ end
+ elseif event == "ARENA_OPPONENT_UPDATE" then
+ local unit, type = ...
+
+ if type == "seen" then
+ if UnitExists(unit) and UnitIsPlayer(unit) then
+ element.Icon:SetTexture(GetTrinketIcon(unit))
+ end
+ end
+ elseif event == "PLAYER_ENTERING_WORLD" then
+ CooldownFrame_SetTimer(element.cooldownFrame, 1, 1, 1)
+ end
+
+ if element.PostUpdate then
+ element:PostUpdate(event)
+ end
+end
+
+local function Enable(self)
+ local element = self.Trinket
+
+ if element then
+ self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED", Update, true)
+ self:RegisterEvent("ARENA_OPPONENT_UPDATE", Update, true)
+ self:RegisterEvent("PLAYER_ENTERING_WORLD", Update, true)
+
+ if not element.cooldownFrame then
+ element.cooldownFrame = CreateFrame("Cooldown", nil, element)
+ element.cooldownFrame:SetAllPoints(element)
+ ElvUI[1]:RegisterCooldown(element.cooldownFrame)
+ end
+
+ if not element.Icon then
+ element.Icon = element:CreateTexture(nil, "BORDER")
+ element.Icon:SetAllPoints(element)
+ element.Icon:SetTexture(GetTrinketIcon("player"))
+ element.Icon:SetTexCoord(unpack(ElvUI[1].TexCoords))
+ end
+
+ return true
+ end
+end
+
+local function Disable(self)
+ local element = self.Trinket
+
+ if element then
+ self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED", Update)
+ self:UnregisterEvent("ARENA_OPPONENT_UPDATE", Update)
+ self:UnregisterEvent("PLAYER_ENTERING_WORLD", Update)
+ element:Hide()
+ end
+end
+
+oUF:AddElement("Trinket", Update, Enable, Disable)
\ No newline at end of file
diff --git a/ElvUI/Locales/Load_Locales.xml b/ElvUI/Locales/Load_Locales.xml
new file mode 100644
index 0000000..68ff9ba
--- /dev/null
+++ b/ElvUI/Locales/Load_Locales.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Locales/deDE.lua b/ElvUI/Locales/deDE.lua
new file mode 100644
index 0000000..51f901b
--- /dev/null
+++ b/ElvUI/Locales/deDE.lua
@@ -0,0 +1,331 @@
+-- German localization file for deDE.
+local E = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "deDE")
+
+L[" |cff00ff00bound to |r"] = " |cff00ff00gebunden zu |r"
+L["%s frame(s) has a conflicting anchor point, please change either the buff or debuff anchor point so they are not attached to each other. Forcing the debuffs to be attached to the main unitframe until fixed."] = "Es liegt ein Konflikt bei den Ankerpunkten des Rahmens %s vor. Bitte ändere entweder den Ankerpunkt des Stärkungs- oder Schwächungszaubers, damit diese nicht länger mit einander verbunden sind. Verbinde die Schwächungszauber mit dem Hauptrahmen, damit dieses Problem behoben wird."
+L["%s is attempting to share his filters with you. Would you like to accept the request?"] = "%s möchte seine Filter Einstellungen mit dir teilen. Möchtest du die Anfrage annehmen?"
+L["%s is attempting to share the profile %s with you. Would you like to accept the request?"] = "%s versucht das Profil %s mit dir zu teilen. Möchtest du die Anfrage annehmen?"
+L["%s: %s tried to call the protected function '%s'."] = "%s: %s versucht die geschützte Funktion aufrufen '%s'."
+L["(Hold Shift) Memory Usage"] = "(Shift gedrückt) Speichernutzung"
+L["(Modifer Click) Collect Garbage"] = "(Modifikator Klick) Müll säubern"
+L["A raid marker feature is available by pressing Escape -> Keybinds scroll to the bottom under ElvUI and setting a keybind for the raid marker."] = "Ein Feature für Schlachtzugsmarkierung ist verfügbar, wenn du Escape drückst und Tastaturbelegung wählst, scrolle anschließend bis unter die Kategorie ElvUI und wähle eine Tastenbelegung für die Schlachtzugsmarkierung."
+L["A setting you have changed will change an option for this character only. This setting that you have changed will be uneffected by changing user profiles. Changing this setting requires that you reload your User Interface."] = "Eine Einstellung, die du geändert hast, betrifft nur einen Charakter. Diese Einstellung, die du verändert hast, wird die Benutzerprofile unbeeinflusst lassen. Eine Änderung dieser Einstellung erfordert, dass du dein Interface neu laden musst."
+L["ABOVE_THREAT_FORMAT"] = "%s: %.0f%% [%.0f%% above |cff%02x%02x%02x%s|r]"
+L["AFK"] = "AFK"
+L["Accepting this will reset the UnitFrame settings for %s. Are you sure?"] = "Wenn du aktzeptierst wird die Einstellung des Einheitenfensters für %s auf Standard zurückgesetzt. Bist du sicher?"
+L["Accepting this will reset your Filter Priority lists for all auras on NamePlates. Are you sure?"] = "Wenn du aktzeptierst wird die Filter Priorität für alle Namensplaketten auf Standard zurückgesetzt. Bist du sicher?"
+L["Accepting this will reset your Filter Priority lists for all auras on UnitFrames. Are you sure?"] = "Wenn du aktzeptierst wird die Filter Priorität für alle Einheitenfenster auf Standard zurückgesetzt. Bist du sicher?"
+L["Adjust the UI Scale to fit your screen, press the autoscale button to set the UI Scale automatically."] = "Passt die UI-Skallierung für deine Auflöstung an, drücke den Auto-Skallierung Knopf um die UI-Skallierung automatisch anzupassen."
+L["All keybindings cleared for |cff00ff00%s|r."] = "Alle Tastaturbelegungen gelöscht für |cff00ff00%s|r."
+L["Already Running.. Bailing Out!"] = "Bereits ausgeführt.. Warte ab!"
+L["Are you sure you want to apply this font to all ElvUI elements?"] = "Bist du sicher, dass du diese Schrifart auf alle ElvUI Elemente anwenden möchtest?"
+L["Are you sure you want to disband the group?"] = "Bist du dir sicher, dass du die Gruppe auflösen willst?"
+L["Are you sure you want to reset all the settings on this profile?"] = "Bist du dir sicher dass du alle Einstellungen dieses Profils zurücksetzen willst?"
+L["Are you sure you want to reset every mover back to it's default position?"] = "Bist du dir sicher, dass du jeden Beweger an die Standard-Position zurücksetzen möchtest?"
+L["Arena Frames"] = "Arena Fenster"
+L["Aura Bars & Icons"] = "Aurenleisten & Symbole"
+L["Auras Set"] = "Auren gesetzt"
+L["Auras"] = "Auren"
+L["Auto Scale"] = "Auto-Skalierung"
+L["Avoidance Breakdown"] = "Vermeidung Aufgliederung"
+L["BG"] = true
+L["BGL"] = true
+L["BNet Frame"] = "BNet-Fenster"
+L["Bag Mover (Grow Down)"] = "Taschen Anker (Nach unten wachsen)"
+L["Bag Mover (Grow Up)"] = "Taschen Anker (Nach oben wachsen)"
+L["Bag Mover"] = "Taschen Anker"
+L["Bags"] = "Taschen"
+L["Bank Mover (Grow Down)"] = "Bank Anker (Nach unten wachsen)"
+L["Bank Mover (Grow Up)"] = "Bank Anker (Nach oben wachsen)"
+L["Bank"] = true --No need to translate
+L["Bar "] = "Leiste "
+L["Bars"] = "Leisten"
+L["Battleground datatexts temporarily hidden, to show type /bgstats or right click the 'C' icon near the minimap."] = "Schlachtfeld-Infotexte sind kurzzeitig versteckt, um sie wieder anzuzeigen tippe /bgstats oder rechtsklicke auf das 'C' Symbol nahe der Minimap."
+L["Battleground datatexts will now show again if you are inside a battleground."] = "Schlachtfeld-Infotexte werden wieder angezeigt, solange du dich in einem Schlachtfeld befindest."
+L["Binding"] = "Belegung"
+L["Binds Discarded"] = "Tastaturbelegungen verworfen"
+L["Binds Saved"] = "Tastaturbelegungen gespeichert"
+L["BoE"] = true
+L["BoU"] = true
+L["Boss Frames"] = "Boss Fenster"
+L["Buffs"] = "Stärkungszauber"
+L["CVars Set"] = "CVars gesetzt"
+L["CVars"] = "CVars"
+L["Calendar"] = "Kalender"
+L["Can't Roll"] = "Es kann nicht gewürfelt werden."
+L["Can't buy anymore slots!"] = "Kann keine Slots mehr kaufen"
+L["Caster DPS"] = "Fernkampf DD"
+L["Character: "] = "Charakter: "
+L["Chat Set"] = "Chat gesetzt"
+L["Chat"] = "Chat"
+L["Choose a theme layout you wish to use for your initial setup."] = "Wähle ein Layout, welches du bei deinem ersten Setup verwenden möchtest."
+L["Classbar"] = "Klassenleiste"
+L["Classic"] = "Klassisch"
+L["Combat Time"] = "Kampf Zeit"
+L["Combobar"] = "Kombopunkte Leiste"
+L["Config Mode:"] = "Konfigurationsmodus:"
+L["Confused.. Try Again!"] = "Verwirrt.. Versuche es erneut!"
+L["Continue"] = "Fortfahren"
+L["Coords"] = "Koordinaten"
+L["Count"] = "Zähler"
+L["DND"] = "DND"
+L["DPS"] = "DPS"
+L["Dark"] = "Dunkel"
+L["Data From: %s"] = "Datei von: %s"
+L["Data To: %s"] = true
+L["Dead"] = "Tot"
+L["Debuffs"] = "Schwächungszauber"
+L["Deficit:"] = "Defizit:"
+L["Delete gray items?"] = "Graue Gegenstände löschen?"
+L["Detected that your ElvUI OptionsUI addon is out of date. This may be a result of your Tukui Client being out of date. Please visit our download page and update your Tukui Client, then reinstall ElvUI. Not having your ElvUI OptionsUI addon up to date will result in missing options."] = "Es wurde erkannt dass dein ElvUI Konfigurations-Addon veraltet ist. Dies kann das Ergebnis eines veralteten Tukui Clients sein. Bitte besuche unsere Downloadseite und update deinen Tukui Client, dann installiere ElvUI neu. Das nicht auf dem neuesten Stand haben des ElvUI Konfigurations-Addons wird in fehlenden Optionen resultieren."
+L["Disable Warning"] = "Deaktiviere Warnung"
+L["Disable"] = "Deaktivieren"
+L["Disband Group"] = "Gruppe auflösen"
+L["Discard"] = "Verwerfen"
+L["Discord"] = true --No need to translate
+L["Do you enjoy the new ElvUI?"] = "Gefällt dir das neue ElvUI?"
+L["Do you swear not to post in technical support about something not working without first disabling the addon/module combination first?"] = "Schwörst du, dass du keinen Beitrag im Supportforum posten wirst, ohne vorher alle anderen Addons/Module zu deaktivieren?"
+L["Earned:"] = "Verdient:"
+L["ElvUI Installation"] = "ElvUI Installation"
+L["ElvUI Plugin Installation"] = true --No need to translate
+L["ElvUI has a dual spec feature which allows you to load different profiles based on your current spec on the fly. You can enable this from the profiles tab."] = "ElvUI hat ein Feature für Dualspezialisierungen, welches dich abhängig von deiner momentanen Spezialisierung verschiedene Profile laden lässt. Dieses Feature kannst du im Abschnitt Profil aktivieren."
+L["ElvUI is five or more revisions out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI ist seit fünf oder mehr Revisionen nicht aktuell. Du kannst die neuste Version bei https://github.com/BanditTech/ElvUI-Ascension herunterladen"
+L["ElvUI is out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI ist nicht aktuell. Du kannst die neuste Version bei https://github.com/BanditTech/ElvUI-Ascension herunterladen"
+L["ElvUI needs to perform database optimizations please be patient."] = "ElvUI muss eine Datenbank Optimierung durchführen. Bitte warte eine Moment."
+L["ElvUI was updated while the game is still running. Please relaunch the game, as this is required for the files to be properly updated."] = "ElvUI wurde upgedated während das Spiel noch läuft. Bitte starte das Spiel neu, damit alle Dateien richtig geupdated werden."
+L["Empty Slot"] = "Leerer Platz"
+L["Enable"] = "Eingeschaltet"
+L["Error resetting UnitFrame."] = "Fehler beim Zurücksetzen des Einheitenfesters."
+L["Experience Bar"] = "Erfahrungsleiste"
+L["Experience"] = "Erfahrung"
+L["Export Now"] = "Jetzt exportieren"
+L["Farm Mode"] = true
+L["Filter download complete from %s, would you like to apply changes now?"] = "Filter komplett heruntergeladen von %s, möchtest du die Änderungen nun vornehmen?"
+L["Finished"] = "Abgeschlossen"
+L["Fishy Loot"] = "Faule Beute"
+L["Focus Castbar"] = "Fokus Zauberbalken"
+L["Focus Frame"] = "Fokusfenster"
+L["FocusTarget Frame"] = "Fokus-Ziel Fenster"
+L["For technical support visit us at https://github.com/ElvUI-WotLK."] = "Für technische Hilfe besuche uns unter https://github.com/ElvUI-WotLK."
+L["Frame"] = "Fenster"
+L["Friends List"] = "Freundesliste"
+L["G"] = "G"
+L["GM Ticket Frame"] = "GM-Ticket-Fenster"
+L["General"] = "Allgemein"
+L["Ghost"] = "Geist"
+L["Gold"] = true --No need to translate
+L["Grid Size:"] = "Rastergröße:"
+L["HP"] = "HP"
+L["HPS"] = "HPS"
+L["Healer"] = "Heiler"
+L["Hit"] = true
+L["Hold Control + Right Click:"] = "Halte Steuerung + Rechtsklick:"
+L["Hold Shift + Drag:"] = "Halte Shift + Ziehen:"
+L["Hold Shift + Right Click:"] = "Halte Umschalt + Rechts Klick:"
+L["Home Latency:"] = "Standort Latenz"
+L["Hover your mouse over any actionbutton or spellbook button to bind it. Press the ESC key to clear the current actionbutton's keybinding."] = "Bewege deine Maus über einen Aktionsbutton oder dein Zauberbuch um ihn mit einem Hotkey zu belegen. Drücke Escape um die aktuelle Tastenbelegung des Buttons zu löschen."
+L["I Swear"] = "Ich schwöre"
+L["INCOMPATIBLE_ADDON"] = "Das Addon %s ist nicht mit dem ElvUI %s Modul kompatibel. Bitte deaktiviere entweder das Addon oder deaktiviere das ElvUI Modul."
+L["Icons Only"] = "Nur Symbole"
+L["If you accidently remove a chat frame you can always go the in-game configuration menu, press install, go to the chat portion and reset them."] = "Wenn du ausversehen das Chatfenster entfernen solltest, kannst du ganz einfach in die Ingame-Konfiguration gehen und den Installationsprozess erneut aufrufen. Drücke Installieren und gehe zu den Chateinstellungen und setze diese zurück."
+L["If you are experiencing issues with ElvUI try disabling all your addons except ElvUI, remember ElvUI is a full UI replacement addon, you cannot run two addons that do the same thing."] = "Wenn du Probleme mit ElvUI hast, deaktiviere alle Addons außer ElvUI. Denke auch daran, dass ElvUI die komplette Benutzeroberfläche ersetzt, d.h. du kannst kein Addon verwenden, welches die gleichen Funktionen wie ElvUI nutzt."
+L["If you have an icon or aurabar that you don't want to display simply hold down shift and right click the icon for it to disapear."] = "Wenn du ein Symbol oder eine Auraleiste nicht angezeigt haben möchtest, halte einfach Shift und rechtsklick auf das Symbol um zu verstecken."
+L["Import Now"] = "Jetzt importieren"
+L["Importance: |cff07D400High|r"] = "Bedeutung: |cff07D400Hoch|r"
+L["Importance: |cffD3CF00Medium|r"] = "Bedeutung: |cffD3CF00Mittel|r"
+L["Importance: |cffFF0000Low|r"] = "Bedeutung: |cffD3CF00Niedrig|r"
+L["In Progress"] = "In Bearbeitung"
+L["Installation Complete"] = "Installation komplett"
+L["Invalid Target"] = "Ungültiges Ziel"
+L["Item Level:"] = "Gegenstandsstufe:"
+L["KEY_ALT"] = "A"
+L["KEY_CTRL"] = "C"
+L["KEY_DELETE"] = "Del"
+L["KEY_HOME"] = "Hm"
+L["KEY_INSERT"] = "Ins"
+L["KEY_MOUSEBUTTON"] = "M"
+L["KEY_MOUSEWHEELDOWN"] = "MwD"
+L["KEY_MOUSEWHEELUP"] = "MwU"
+L["KEY_NUMPAD"] = "N"
+L["KEY_PAGEDOWN"] = "PD"
+L["KEY_PAGEUP"] = "PU"
+L["KEY_SHIFT"] = "S"
+L["KEY_SPACE"] = "SpB"
+L["Key"] = "Taste"
+L["LOGIN_MSG"] = "Willkommen zu %sElvUI|r Version %s%s|r, Tippe /ec um das Konfigurationsmenü aufzurufen. Für technische Hilfe, besuche das Supportforum unter https://github.com/BanditTech/ElvUI-Ascension oder trete unserem Discord bei: https://discord.gg/UXSc7nt"
+L["Layout Set"] = "Layout gesetzt"
+L["Layout"] = "Layout"
+L["Left Chat"] = "Linker Chat"
+L["Left Click:"] = "Linksklick:"
+L["List of installations in queue:"] = "Liste der Installationen in der Warteschlange:"
+L["Lock"] = "Sperren"
+L["Loot / Alert Frames"] = "Beute-/Alarmfenster"
+L["Loot Frame"] = "Beute-Fenster"
+L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"] = "Herr! Es ist ein Wunder! Der Download verschwand wie ein Furz im Wind! Versuche es nochmal!"
+L["MA Frames"] = "MA-Fenster"
+L["MT Frames"] = "MT-Fenster"
+L["Micro Bar"] = "Mikroleiste"
+L["Minimap"] = "Minimap"
+L["MirrorTimer"] = "Spiegel Zeitgeber"
+L["Miss Chance"] = true
+L["Mitigation By Level: "] = "Milderung durch Stufe: "
+L["Movers"] = "Ankerpunkte"
+L["Must be in group with the player if he isn't on the same server as you."] = "Du musst mit dem Spieler in einer Gruppe sein wenn dieser nicht auf deinem Server ist wie du."
+L["No Guild"] = "Keine Gilde"
+L["No bindings set."] = "Keine Belegungen gesetzt."
+L["No gray items to delete."] = "Es sind keine grauen Gegenstände zum Löschen vorhanden."
+L["No, Revert Changes!"] = "Nein, Änderungen verwerfen!"
+L["Nudge"] = "Stoß"
+L["O"] = "O"
+L["Objective Frame"] = "Questfenster"
+L["Offline"] = "Offline"
+L["Oh lord, you have got ElvUI and Tukui both enabled at the same time. Select an addon to disable."] = "Oh Gott, du hast ElvUI und Tukui zur gleichen Zeit aktiviert. Wähle ein Addon um es zu deaktivieren."
+L["On screen positions for different elements."] = "Position der verschiedenen Elemente."
+L["One or more of the changes you have made require a ReloadUI."] = "Eine oder mehrere Einstellungen, die du vorgenommen hast, benötigen ein Neuladen des Benutzerinterfaces um in Effekt zu treten."
+L["One or more of the changes you have made will effect all characters using this addon. You will have to reload the user interface to see the changes you have made."] = "Eine oder mehrere Änderungen, die du getroffen hast, betrifft alle Charaktere die dieses Addon benutzen. Du musst das Benutzerinterface neu laden um die Änderungen, die du durchgeführt hast, zu sehen."
+L["P"] = "P"
+L["PL"] = "PL"
+L["Party Frames"] = "Gruppenfenster"
+L["Pending"] = "Ausstehend"
+L["Pet Bar"] = "Begleiterleiste"
+L["Pet Castbar"] = "Begleiter Zauberleiste"
+L["Pet Frame"] = "Begleiterfenster"
+L["PetTarget Frame"] = "Begleiter-Ziel Fenster"
+L["Player Buffs"] = "Spieler Buffs"
+L["Player Castbar"] = "Spieler Zauberbalken"
+L["Player Debuffs"] = "Spieler Debuffs"
+L["Player Frame"] = "Spieler Fenster"
+L["Player Powerbar"] = "Spieler Kraftleiste"
+L["Please click the button below so you can setup variables and ReloadUI."] = "Bitte klicke die Taste unten um den Installationsprozess abzuschließen und das Benutzerinterface neu zu laden."
+L["Please click the button below to setup your CVars."] = "Klicke 'Installiere CVars' um die CVars einzurichten."
+L["Please press the continue button to go onto the next step."] = "Bitte drücke die Weiter-Taste um zum nächsten Schritt zu gelangen."
+L["Preview Changes"] = "Änderungsvorschau"
+L["Preview"] = "Vorschau"
+L["Profile download complete from %s, but the profile %s already exists. Change the name or else it will overwrite the existing profile."] = "Profil komplett heruntergeladen von %s, allerdings ist das Profil %s bereits vorhanden. Ändere den Namen oder das bereits existierende Profil wird überschrieben."
+L["Profile download complete from %s, would you like to load the profile %s now?"] = "Profil komplett heruntergeladen von %s, möchtest du das Profil %s nun laden?"
+L["Profile request sent. Waiting for response from player."] = "Profil Anfrage gesendet. Warte auf die Antwort des Spielers."
+L["Profit:"] = "Gewinn:"
+L["Purchase Bags"] = "Taschen kaufen"
+L["PvP"] = true
+L["R"] = "R"
+L["RL"] = "RL"
+L["RW"] = "RW"
+L["Raid Frames"] = "Schlachtzugsfenster"
+L["Raid Menu"] = "Schlachtzugsmenü"
+L["Raid Pet Frames"] = true
+L["Raid-40 Frames"] = "40er Schlachtzugsfenster"
+L["Reload UI"] = true
+L["Remaining:"] = "Verbleibend:"
+L["Remove Bar %d Action Page"] = "Entferne Leiste %d Aktion Seite"
+L["Reputation Bar"] = "Rufleiste"
+L["Request was denied by user."] = "Die Anfrage wurde vom Benutzer abgelehnt."
+L["Reset Counters: Hold Shift + Left Click"] = "Zähler zurücksetzen: Halte Shift + Linksklick"
+L["Reset Data: Hold Shift + Right Click"] = "Daten zurücksetzen: Halte Shift + Rechtsklick"
+L["Reset Position"] = "Position zurücksetzen"
+L["Rested:"] = "Ausgeruht:"
+L["Right Chat"] = "Rechter Chat"
+L["Right Click:"] = "Rechtsklick:"
+L["SP"] = "SP"
+L["Save"] = "Speichern"
+L["Saved Dungeon(s)"] = "Gespeicherte Instanz(en)"
+L["Saved Raid(s)"] = "Gespeicherte Schlachtzüge"
+L["Select the type of aura system you want to use with ElvUI's unitframes. Set to Aura Bar & Icons to use both aura bars and icons, set to icons only to only see icons."] = "Wähle eine Aurensystem aus dass du für die ElvUI Einheitenfenster benutzen möchtest. Setze Aurenleiste & Symbole um beides zu nutzen. Setze zu Symbole um nur Symbole zu verwenden."
+L["Server: "] = "Server: "
+L["Session:"] = "Sitzung:"
+L["Setup CVars"] = "Installiere CVars"
+L["Setup Chat"] = "Chateinstellungen"
+L["Show BG Texts"] = true
+L["Skip Process"] = "Schritt überspringen"
+L["Sort Bags"] = "Taschen sortieren"
+L["Spell/Heal Power"] = "Zauber-/Heilungskraft"
+L["Spent:"] = "Ausgegeben:"
+L["Stance Bar"] = "Haltungsleiste"
+L["Stats For:"] = "Stats Für:"
+L["Steps"] = "Schritte"
+L["Sticky Frames"] = "Anheftende Fenster"
+L["System"] = true --No need to translate
+L["Talent Specialization:"] = "Talent spezialisierung:"
+L["Tank / Physical DPS"] = "Tank / Pyhisische DPS"
+L["Target Castbar"] = "Ziel Zauberbalken"
+L["Target Frame"] = "Ziel Fenster"
+L["Target Powerbar"] = "Ziel Kraftleiste"
+L["TargetTarget Frame"] = "Ziel des Ziels Fenster"
+L["TargetTargetTarget Frame"] = "Ziel des Ziels des Ziels Fenster"
+L["Targeted By:"] = "Ziel von:"
+L["Temporary Move"] = "Temporäres Bewegen"
+L["The UI Scale has been changed, if you would like to preview the change press the preview button. It is recommended that you reload your User Interface for the best appearance."] = "Die UI Skallierung hat sich verändert, wenn du die Änderungen anschauen möchtest drücke bitte den Vorschau Knopf. Es wird empfohlen dass du dein UI neulädst für die besten Ergebnise."
+L["The chat windows function the same as Blizzard standard chat windows, you can right click the tabs and drag them around, rename, etc. Please click the button below to setup your chat windows."] = "Die Chatfensterfunktionen sind die gleichen, wie die Chatfenster von Blizzard. Du kannst auf die Tabs rechtsklicken und sie z.B. neu zu positionieren, umzubenennen, etc. Bitte klicke den Button unten um das Chatfenster einzurichten."
+L["The focus unit can be set by typing /focus when you are targeting the unit you want to focus. It is recommended you make a macro to do this."] = "Du kannst, während du ein Ziel hast, das Fokusfenster durch die Eingabe von /fokus setzen. Es wird empfohlen ein Makro dafür zu nutzen."
+L["The in-game configuration menu can be accessed by typing the /ec command or by clicking the 'C' button on the minimap. Press the button below if you wish to skip the installation process."] = "Das ElvUI-Konfigurationsmenü kannst du entweder mit /ec oder durch das Anklicken der 'C' Taste an der Minimap aufrufen. Drücke 'Schritt überspringen' um zum nächsten Schritt zu gelangen."
+L["The profile you tried to import already exists. Choose a new name or accept to overwrite the existing profile."] = "Das Profil, dass du versuchst zu importieren existiert bereits. Wähle einen neuen Namen oder aktzeptiere dass das vorhandene Profile überschrieben wird."
+L["The spell '%s' has been added to the Blacklist unitframe aura filter."] = "Der Zauber '%s' wurde zur schwarzen Liste der Einheitenfenster hinzugefügt."
+L["Theme Set"] = "Thema gesetzt"
+L["Theme Setup"] = "Thema Setup"
+L["This install process will help you learn some of the features in ElvUI has to offer and also prepare your user interface for usage."] = "Dieser Installationsprozess wird dir helfen, die Funktionen von ElvUI für deine Benutzeroberfläche besser kennenzulernen."
+L["This part of the installation process sets up your World of Warcraft default options it is recommended you should do this step for everything to behave properly."] = "Dieser Installationsprozess richtet alle wichtigen Cvars deines World of Warcrafts ein, um eine problemlose Nutzung zu ermöglichen."
+L["This part of the installation process sets up your chat windows names, positions and colors."] = "Dieser Abschnitt der Installation stellt die Chat Fenster Namen, Positionen und Farben ein."
+L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."] = "Diese Einstellungen haben einen Konflikt mit einem Ankerpunkt, wo '%s' an sich selbst angehaftet sein soll. Bitte kontrolliere deine Ankerpunkte. Einstellung '%s' angehaftet an '%s'."
+L["This will change the layout of your unitframes and actionbars."] = "Dies wird das Layout der Einheitenfenster und Aktionsleisten ändern."
+L["To move abilities on the actionbars by default hold shift + drag. You can change the modifier key from the actionbar options menu."] = "Um Fähigkeiten auf der Aktionsleiste zu verschieben nutze Shift und bewege zeitgleich die Maus. Du kannst die Modifier-Taste im Aktionsleistenmenü umstellen."
+L["To setup which channels appear in which chat frame, right click the chat tab and go to settings."] = "Um einzustellen welcher Kanal im welchem Chatfenster angezeigt werden soll, klicke rechts auf das Chattab und gehe auf Einstellungen."
+L["Toggle Bags"] = "Taschen umschalten"
+L["Toggle Chat Frame"] = "Chatfenster an-/ausschalten"
+L["Toggle Configuration"] = "Konfiguration an-/ausschalten"
+L["Tooltip"] = "Tooltip"
+L["Total CPU:"] = "Gesamt CPU:"
+L["Total Memory:"] = "Gesamte Speichernutzung:"
+L["Total: "] = "Gesamt: "
+L["Trigger"] = "Auslöser"
+L["Type /hellokitty to revert to old settings."] = "Tippe /hellokitty um die alten Einstellungen zu verwenden."
+L["UI Scale"] = true
+L["Unhittable:"] = "Unschlagbar:"
+L["Vehicle Seat Frame"] = "Fahrzeugfenster"
+L["Vendor / Delete Grays"] = "Verkaufe / Lösche graue Gegenstände"
+L["Vendored gray items for: %s"] = "Graue Gegenstände verkauft für: %s"
+L["Vendoring Grays"] = "Verkaufe graue Gegenstände"
+L["Welcome to ElvUI version %s!"] = "Willkommen bei ElvUI Version %s!"
+L["Wintergrasp"] = true
+L["XP:"] = "EP:"
+L["Yes, Keep Changes!"] = "Ja, Änderungen behalten!"
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"] = "Du möchtest Einstellungen für |cffD3CF00\"%s\"|r von deinem derzeitigen |cff4beb2c\"%s\"|r Profil zu |cff4beb2c\"%s\"|r Profil kopieren. Bist du sicher?"
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"] = "Du möchtest Einstellungen für |cffD3CF00\"%s\"|r Profil zu deinem aktuellem |cff4beb2c\"%s\"|r Profil kopieren. Bist du sicher?"
+L["You are now finished with the installation process. If you are in need of technical support please visit us at https://github.com/ElvUI-WotLK."] = "Du hast den Installationsprozess abgeschlossen. Solltest du technische Hilfe benötigen, besuche uns auf https://github.com/ElvUI-WotLK."
+L["You are using CPU Profiling. This causes decreased performance. Do you want to disable it or continue?"] = "Du benutzt CPU Profiling. Dieses verringert deine Performance. Willst du es deaktivieren oder fortfahren."
+L["You can access copy chat and chat menu functions by mouse over the top right corner of chat panel and left/right click on the button that will appear."] = "Du kannst die Funktionen Chat Kopieren und Chatmenü aufrufen, wenn du die Maus in die obere rechte Ecke des Chatfensters bewegst und links-/rechtsklickst."
+L["You can always change fonts and colors of any element of ElvUI from the in-game configuration."] = "Du kannst jederzeit in der Ingame-Konfiguration Schriften und Farben von jedem Element des Interfaces ändern."
+L["You can now choose what layout you wish to use based on your combat role."] = "Du kannst nun auf Basis deiner Rolle im Kampf ein Layout wählen."
+L["You can see someones average item level of their gear by holding shift and mousing over them. It should appear inside the tooltip."] = "Du kannst die durchschnittliche Gegenstandsstufe von jemanden sehen, wenn du bei gedrückter Shift-Taste mit der Maus über ihn fährst. Die Gegenstandsstufe wird dann im Tooltip angezeigt."
+L["You can set your keybinds quickly by typing /kb."] = "Du kannst deine Tastaturbelegung schnell ändern, wenn du /kb eintippst."
+L["You can toggle the microbar by using your middle mouse button on the minimap you can also accomplish this by enabling the actual microbar located in the actionbar settings."] = "Du kannst die Mikroleiste durch mittleren Mausklick auf der Minimap aufrufen oder auch die tatsächliche Mikroleiste in den Aktionsleisten Optionen aktivieren."
+L["You can use the /resetui command to reset all of your movers. You can also use the command to reset a specific mover, /resetui .\nExample: /resetui Player Frame"] = "Du kannst durch benutzen von /resetui alle Ankerpunkte zurücksetzen. Du kannst das Kommando auch benutzen um spezielle Anker zurückzusetzen, /resetui .\nBeispiel: /resetui Player Frame"
+L["You cannot copy settings from the same unit."] = "Du kannst keine Einstellungen von der gleichen Einheit kopieren."
+L["You don't have enough money to repair all items."] = true
+L["You don't have enough money to repair."] = "Du hast nicht genügend Gold für die Reparatur."
+L["You don't have permission to mark targets."] = "Du hast keine Rechte ein Ziel zu markieren."
+L["You have imported settings which may require a UI reload to take effect. Reload now?"] = "Du hast Einstellungen importiert die wahrscheinlich ein Neuladen des UI erfordern. Jetzt neu laden?"
+L["You must purchase a bank slot first!"] = "Du musst erst ein Bankfach kaufen!"
+L["You still have ElvUI_Config installed. ElvUI_Config has been renamed to ElvUI_OptionsUI, please remove it."] = true
+L["Your items have been repaired for: "] = "Deine Gegenstände wurden repariert für: "
+L["Your items have been repaired using guild bank funds for: "] = "Deine Gegenstände wurden repariert. Die Gildenbank kostete das: "
+L["Your profile was successfully recieved by the player."] = "Dein Profil wurde erfolgreich von dem Spieler empfangen."
+L["copperabbrev"] = "|cffeda55fc|r"
+L["goldabbrev"] = "|cffffd700g|r"
+L["lvl"] = "lvl"
+L["says"] = "sagen"
+L["silverabbrev"] = "|cffc7c7cfs|r"
+L["whispers"] = "flüstern"
+L["yells"] = "schreien"
+L["|cFFE30000Lua error recieved. You can view the error message when you exit combat."] = "|cFFE30000Lua Fehler erhalten. Du kannst die Fehlermeldung ansehen, wenn du den Kampf verlässt."
+
+----------------------------------
+L["RED_ENABLE"] = "|cFFff3333Eingeschaltet|r"
+L["GREEN_ENABLE"] = "|cFF33ff33Eingeschaltet|r"
+L["DESC_MOVERCONFIG"] = [=[Ankerpunkte entriegelt. Bewege die Ankerpunkte und klicke 'sperren', wenn du fertig bist.
+
+Options:
+ Linksklick - Öffnet das Fenster zum Verschieben.
+ Rechtsklick - Öffnet Konfigurationsbereich.
+ Shift + Rechtsklick - Blendet den Anker vorübergehend aus.
+ Strg + Rechtsklick - Setzt den Anker auf Ursprungsposition zurück.
+]=]
\ No newline at end of file
diff --git a/ElvUI/Locales/enUS.lua b/ElvUI/Locales/enUS.lua
new file mode 100644
index 0000000..5071a23
--- /dev/null
+++ b/ElvUI/Locales/enUS.lua
@@ -0,0 +1,333 @@
+-- English localization file for enUS and enGB.
+local E = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "enUS", true, true)
+
+L[" |cff00ff00bound to |r"] = true
+L["%s frame(s) has a conflicting anchor point, please change either the buff or debuff anchor point so they are not attached to each other. Forcing the debuffs to be attached to the main unitframe until fixed."] = true
+L["%s is attempting to share his filters with you. Would you like to accept the request?"] = true
+L["%s is attempting to share the profile %s with you. Would you like to accept the request?"] = true
+L["%s: %s tried to call the protected function '%s'."] = true
+L["(Hold Shift) Memory Usage"] = true
+L["(Modifer Click) Collect Garbage"] = true
+L["A raid marker feature is available by pressing Escape -> Keybinds scroll to the bottom under ElvUI and setting a keybind for the raid marker."] = true
+L["A setting you have changed will change an option for this character only. This setting that you have changed will be uneffected by changing user profiles. Changing this setting requires that you reload your User Interface."] = true
+L["ABOVE_THREAT_FORMAT"] = "%s: %.0f%% [%.0f%% above |cff%02x%02x%02x%s|r]"
+L["AFK"] = true
+L["Accepting this will reset the UnitFrame settings for %s. Are you sure?"] = true
+L["Accepting this will reset your Filter Priority lists for all auras on NamePlates. Are you sure?"] = true
+L["Accepting this will reset your Filter Priority lists for all auras on UnitFrames. Are you sure?"] = true
+L["Adjust the UI Scale to fit your screen, press the autoscale button to set the UI Scale automatically."] = true
+L["All keybindings cleared for |cff00ff00%s|r."] = true
+L["Already Running.. Bailing Out!"] = true
+L["Are you sure you want to apply this font to all ElvUI elements?"] = true
+L["Are you sure you want to disband the group?"] = true
+L["Are you sure you want to reset all the settings on this profile?"] = true
+L["Are you sure you want to reset every mover back to it's default position?"] = true
+L["Arena Frames"] = true
+L["Aura Bars & Icons"] = true
+L["Auras Set"] = true
+L["Auras"] = true
+L["Auto Scale"] = true
+L["Avoidance Breakdown"] = true
+L["BG"] = true
+L["BGL"] = true
+L["BNet Frame"] = true
+L["Bag Mover (Grow Down)"] = true
+L["Bag Mover (Grow Up)"] = true
+L["Bag Mover"] = true
+L["Bags"] = true
+L["Bank Mover (Grow Down)"] = true
+L["Bank Mover (Grow Up)"] = true
+L["Bank"] = true
+L["Bar "] = true
+L["Bars"] = true
+L["Battleground datatexts temporarily hidden, to show type /bgstats or right click the 'C' icon near the minimap."] = true
+L["Battleground datatexts will now show again if you are inside a battleground."] = true
+L["Binding"] = true
+L["Binds Discarded"] = true
+L["Binds Saved"] = true
+L["BoE"] = true
+L["BoU"] = true
+L["Boss Frames"] = true
+L["Buffs"] = true
+L["CVars Set"] = true
+L["CVars"] = true
+L["Calendar"] = true
+L["Can't Roll"] = true
+L["Can't buy anymore slots!"] = true
+L["Caster DPS"] = true
+L["Character: "] = true
+L["Chat Set"] = true
+L["Chat"] = true
+L["Choose a theme layout you wish to use for your initial setup."] = true
+L["Classbar"] = true
+L["Classic"] = true
+L["Combat Time"] = true
+L["Combobar"] = true
+L["Config Mode:"] = true
+L["Confused.. Try Again!"] = true
+L["Continue"] = true
+L["Coords"] = true
+L["Count"] = true
+L["DND"] = true
+L["DPS"] = true
+L["Dark"] = true
+L["Data From: %s"] = true
+L["Data To: %s"] = true
+L["Dead"] = true
+L["Debuffs"] = true
+L["Deficit:"] = true
+L["Delete gray items?"] = true
+L["Detected that your ElvUI OptionsUI addon is out of date. This may be a result of your Tukui Client being out of date. Please visit our download page and update your Tukui Client, then reinstall ElvUI. Not having your ElvUI OptionsUI addon up to date will result in missing options."] = true
+L["Disable Warning"] = true
+L["Disable"] = true
+L["Disband Group"] = true
+L["Discard"] = true
+L["Discord"] = true
+L["Do you enjoy the new ElvUI?"] = true
+L["Do you swear not to post in technical support about something not working without first disabling the addon/module combination first?"] = true
+L["Earned:"] = true
+L["ElvUI Installation"] = true
+L["ElvUI Plugin Installation"] = true
+L["ElvUI has a dual spec feature which allows you to load different profiles based on your current spec on the fly. You can enable this from the profiles tab."] = true
+L["ElvUI is five or more revisions out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = true
+L["ElvUI is out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = true
+L["ElvUI needs to perform database optimizations please be patient."] = true
+L["ElvUI was updated while the game is still running. Please relaunch the game, as this is required for the files to be properly updated."] = true
+L["Empty Slot"] = true
+L["Enable"] = true
+L["Error resetting UnitFrame."] = true
+L["Experience Bar"] = true
+L["Experience"] = true
+L["Export Now"] = true
+L["Farm Mode"] = true
+L["Filter download complete from %s, would you like to apply changes now?"] = true
+L["Finished"] = true
+L["Fishy Loot"] = true
+L["Focus Castbar"] = true
+L["Focus Frame"] = true
+L["FocusTarget Frame"] = true
+L["For technical support visit us at https://github.com/ElvUI-WotLK."] = true
+L["Frame"] = true
+L["Friends List"] = true
+L["G"] = true
+L["GM Ticket Frame"] = true
+L["General"] = true
+L["Ghost"] = true
+L["Gold"] = true
+L["Grid Size:"] = true
+L["HP"] = true
+L["HPS"] = true
+L["Healer"] = true
+L["Hit"] = true
+L["Hold Control + Right Click:"] = true
+L["Hold Shift + Drag:"] = true
+L["Hold Shift + Right Click:"] = true
+L["Home Latency:"] = true
+L["Hover your mouse over any actionbutton or spellbook button to bind it. Press the ESC key to clear the current actionbutton's keybinding."] = true
+L["I Swear"] = true
+L["INCOMPATIBLE_ADDON"] = "The addon %s is not compatible with ElvUI's %s module. Please select either the addon or the ElvUI module to disable."
+L["Icons Only"] = true
+L["If you accidently remove a chat frame you can always go the in-game configuration menu, press install, go to the chat portion and reset them."] = true
+L["If you are experiencing issues with ElvUI try disabling all your addons except ElvUI, remember ElvUI is a full UI replacement addon, you cannot run two addons that do the same thing."] = true
+L["If you have an icon or aurabar that you don't want to display simply hold down shift and right click the icon for it to disapear."] = true
+L["Import Now"] = true
+L["Importance: |cff07D400High|r"] = true
+L["Importance: |cffD3CF00Medium|r"] = true
+L["Importance: |cffFF0000Low|r"] = true
+L["In Progress"] = true
+L["Installation Complete"] = true
+L["Invalid Target"] = true
+L["Item Level:"] = true
+L["KEY_ALT"] = "A"
+L["KEY_CTRL"] = "C"
+L["KEY_DELETE"] = "Del"
+L["KEY_HOME"] = "Hm"
+L["KEY_INSERT"] = "Ins"
+L["KEY_MOUSEBUTTON"] = "M"
+L["KEY_MOUSEWHEELDOWN"] = "MwD"
+L["KEY_MOUSEWHEELUP"] = "MwU"
+L["KEY_NUMPAD"] = "N"
+L["KEY_PAGEDOWN"] = "PD"
+L["KEY_PAGEUP"] = "PU"
+L["KEY_SHIFT"] = "S"
+L["KEY_SPACE"] = "SpB"
+L["Key"] = true
+L["LOGIN_MSG"] = "Welcome to %sElvUI|r version %s%s|r, type /ec to access the in-game configuration menu. If you are in need of technical support you can visit us at https://github.com/BanditTech/ElvUI-Ascension or join our Discord: https://discord.gg/UXSc7nt"
+L["Layout Set"] = true
+L["Layout"] = true
+L["Left Chat"] = true
+L["Left Click:"] = true
+L["List of installations in queue:"] = true
+L["Lock"] = true
+L["Loot / Alert Frames"] = true
+L["Loot Frame"] = true
+L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"] = true
+L["MA Frames"] = true
+L["MT Frames"] = true
+L["Micro Bar"] = true
+L["Minimap"] = true
+L["MirrorTimer"] = true
+L["Miss Chance"] = true
+L["Mitigation By Level: "] = true
+L["Movers"] = true
+L["Must be in group with the player if he isn't on the same server as you."] = true
+L["No Guild"] = true
+L["No bindings set."] = true
+L["No gray items to delete."] = true
+L["No, Revert Changes!"] = true
+L["Nudge"] = true
+L["O"] = true
+L["Objective Frame"] = true
+L["Offline"] = true
+L["Oh lord, you have got ElvUI and Tukui both enabled at the same time. Select an addon to disable."] = true
+L["On screen positions for different elements."] = true
+L["One or more of the changes you have made require a ReloadUI."] = true
+L["One or more of the changes you have made will effect all characters using this addon. You will have to reload the user interface to see the changes you have made."] = true
+L["P"] = true
+L["PL"] = true
+L["Party Frames"] = true
+L["Pending"] = true
+L["Pet Bar"] = true
+L["Pet Castbar"] = true
+L["Pet Frame"] = true
+L["PetTarget Frame"] = true
+L["Player Buffs"] = true
+L["Player Castbar"] = true
+L["Player Debuffs"] = true
+L["Player Frame"] = true
+L["Player Powerbar"] = true
+L["Player Energybar"] = true
+L["Player Ragebar"] = true
+L["Please click the button below so you can setup variables and ReloadUI."] = true
+L["Please click the button below to setup your CVars."] = true
+L["Please press the continue button to go onto the next step."] = true
+L["Preview Changes"] = true
+L["Preview"] = true
+L["Profile download complete from %s, but the profile %s already exists. Change the name or else it will overwrite the existing profile."] = true
+L["Profile download complete from %s, would you like to load the profile %s now?"] = true
+L["Profile request sent. Waiting for response from player."] = true
+L["Profit:"] = true
+L["Purchase Bags"] = true
+L["PvP"] = true
+L["R"] = true
+L["RL"] = true
+L["RW"] = true
+L["Raid Frames"] = true
+L["Raid Menu"] = true
+L["Raid Pet Frames"] = true
+L["Raid-40 Frames"] = true
+L["Reload UI"] = true
+L["Remaining:"] = true
+L["Remove Bar %d Action Page"] = true
+L["Reputation Bar"] = true
+L["Request was denied by user."] = true
+L["Reset Counters: Hold Shift + Left Click"] = true
+L["Reset Data: Hold Shift + Right Click"] = true
+L["Reset Position"] = true
+L["Rested:"] = true
+L["Right Chat"] = true
+L["Right Click:"] = true
+L["SP"] = true
+L["Save"] = true
+L["Saved Dungeon(s)"] = true
+L["Saved Raid(s)"] = true
+L["Select the type of aura system you want to use with ElvUI's unitframes. Set to Aura Bar & Icons to use both aura bars and icons, set to icons only to only see icons."] = true
+L["Server: "] = true
+L["Session:"] = true
+L["Setup CVars"] = true
+L["Setup Chat"] = true
+L["Show BG Texts"] = true
+L["Skip Process"] = true
+L["Sort Bags"] = true
+L["Spell/Heal Power"] = true
+L["Spent:"] = true
+L["Stance Bar"] = true
+L["Stats For:"] = true
+L["Steps"] = true
+L["Sticky Frames"] = true
+L["System"] = true
+L["Talent Specialization:"] = true
+L["Tank / Physical DPS"] = true
+L["Target Castbar"] = true
+L["Target Frame"] = true
+L["Target Powerbar"] = true
+L["TargetTarget Frame"] = true
+L["TargetTargetTarget Frame"] = true
+L["Targeted By:"] = true
+L["Temporary Move"] = true
+L["The UI Scale has been changed, if you would like to preview the change press the preview button. It is recommended that you reload your User Interface for the best appearance."] = true
+L["The chat windows function the same as Blizzard standard chat windows, you can right click the tabs and drag them around, rename, etc. Please click the button below to setup your chat windows."] = true
+L["The focus unit can be set by typing /focus when you are targeting the unit you want to focus. It is recommended you make a macro to do this."] = true
+L["The in-game configuration menu can be accessed by typing the /ec command or by clicking the 'C' button on the minimap. Press the button below if you wish to skip the installation process."] = true
+L["The profile you tried to import already exists. Choose a new name or accept to overwrite the existing profile."] = true
+L["The spell '%s' has been added to the Blacklist unitframe aura filter."] = true
+L["Theme Set"] = true
+L["Theme Setup"] = true
+L["This install process will help you learn some of the features in ElvUI has to offer and also prepare your user interface for usage."] = true
+L["This part of the installation process sets up your World of Warcraft default options it is recommended you should do this step for everything to behave properly."] = true
+L["This part of the installation process sets up your chat windows names, positions and colors."] = true
+L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."] = true
+L["This will change the layout of your unitframes and actionbars."] = true
+L["To move abilities on the actionbars by default hold shift + drag. You can change the modifier key from the actionbar options menu."] = true
+L["To setup which channels appear in which chat frame, right click the chat tab and go to settings."] = true
+L["Toggle Bags"] = true
+L["Toggle Chat Frame"] = true
+L["Toggle Configuration"] = true
+L["Tooltip"] = true
+L["Total CPU:"] = true
+L["Total Memory:"] = true
+L["Total: "] = true
+L["Trigger"] = true
+L["Type /hellokitty to revert to old settings."] = true
+L["UI Scale"] = true
+L["Unhittable:"] = true
+L["Vehicle Seat Frame"] = true
+L["Vendor / Delete Grays"] = true
+L["Vendored gray items for: %s"] = true
+L["Vendoring Grays"] = true
+L["Welcome to ElvUI version %s!"] = true
+L["Wintergrasp"] = true
+L["XP:"] = true
+L["Yes, Keep Changes!"] = true
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"] = true
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"] = true
+L["You are now finished with the installation process. If you are in need of technical support please visit us at https://github.com/ElvUI-WotLK."] = true
+L["You are using CPU Profiling. This causes decreased performance. Do you want to disable it or continue?"] = true
+L["You can access copy chat and chat menu functions by mouse over the top right corner of chat panel and left/right click on the button that will appear."] = true
+L["You can always change fonts and colors of any element of ElvUI from the in-game configuration."] = true
+L["You can now choose what layout you wish to use based on your combat role."] = true
+L["You can see someones average item level of their gear by holding shift and mousing over them. It should appear inside the tooltip."] = true
+L["You can set your keybinds quickly by typing /kb."] = true
+L["You can toggle the microbar by using your middle mouse button on the minimap you can also accomplish this by enabling the actual microbar located in the actionbar settings."] = true
+L["You can use the /resetui command to reset all of your movers. You can also use the command to reset a specific mover, /resetui .\nExample: /resetui Player Frame"] = true
+L["You cannot copy settings from the same unit."] = true
+L["You don't have enough money to repair all items."] = true
+L["You don't have enough money to repair."] = true
+L["You don't have permission to mark targets."] = true
+L["You have imported settings which may require a UI reload to take effect. Reload now?"] = true
+L["You must purchase a bank slot first!"] = true
+L["You still have ElvUI_Config installed. ElvUI_Config has been renamed to ElvUI_OptionsUI, please remove it."] = true
+L["Your items have been repaired for: "] = true
+L["Your items have been repaired using guild bank funds for: "] = true
+L["Your profile was successfully recieved by the player."] = true
+L["copperabbrev"] = "|cffeda55fc|r"
+L["goldabbrev"] = "|cffffd700g|r"
+L["lvl"] = true
+L["says"] = true
+L["silverabbrev"] = "|cffc7c7cfs|r"
+L["whispers"] = true
+L["yells"] = true
+L["|cFFE30000Lua error recieved. You can view the error message when you exit combat."] = true
+
+----------------------------------
+L["RED_ENABLE"] = "|cFFff3333Enable|r"
+L["GREEN_ENABLE"] = "|cFF33ff33Enable|r"
+L["DESC_MOVERCONFIG"] = [=[Movers unlocked. Move them now and click Lock when you are done.
+
+Options:
+ LeftClick - Toggle Nudge Frame.
+ RightClick - Open Config Section.
+ Shift + RightClick - Hides mover temporarily.
+ Ctrl + RightClick - Resets mover position to default.
+]=]
\ No newline at end of file
diff --git a/ElvUI/Locales/esMX.lua b/ElvUI/Locales/esMX.lua
new file mode 100644
index 0000000..51a787c
--- /dev/null
+++ b/ElvUI/Locales/esMX.lua
@@ -0,0 +1,330 @@
+-- Spanish localization file for esES and esMX.
+local E = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "esMX")
+
+L[" |cff00ff00bound to |r"] = " |cff00ff00ligado(a) a |r"
+L["%s frame(s) has a conflicting anchor point, please change either the buff or debuff anchor point so they are not attached to each other. Forcing the debuffs to be attached to the main unitframe until fixed."] = "El marco(s) %s tiene un punto de fijación en conflicto, por favor cambia el punto de fijación de los beneficios o los perjuicios para que no estén adjuntos entre ellos. Se forzará a los perjuicios para que se adjunten al marco de unidad principal hasta que se corrija."
+L["%s is attempting to share his filters with you. Would you like to accept the request?"] = "%s quiere compartir sus filtros contigo. ¿Aceptas la petición?"
+L["%s is attempting to share the profile %s with you. Would you like to accept the request?"] = "%s quiere compartir el perfil %s contigo. ¿Aceptas la petición?"
+L["%s: %s tried to call the protected function '%s'."] = "%s: %s intentó llamar a la función protegida '%s'."
+L["(Hold Shift) Memory Usage"] = "(Mantén Shift) Uso de Memoria"
+L["(Modifer Click) Collect Garbage"] = "(Clic Mod) Recolectar basura"
+L["A raid marker feature is available by pressing Escape -> Keybinds scroll to the bottom under ElvUI and setting a keybind for the raid marker."] = "La opción de marcador de banda está disponible pulsando Escape -> Asignar teclas -> Recorrer hacia abajo hasta ElvUI y establecer la tecla para el marcador de banda."
+L["A setting you have changed will change an option for this character only. This setting that you have changed will be uneffected by changing user profiles. Changing this setting requires that you reload your User Interface."] = "La opción que has cambiado se aplicará sólo para este personaje. Esta opción no se verá alterada al cambiar el perfil de usuario. Cambiar esta opción requiere que recargues tu Interfaz de Usuario."
+L["ABOVE_THREAT_FORMAT"] = "%s: %.0f%% [%.0f%% above |cff%02x%02x%02x%s|r]"
+L["AFK"] = "Ausente"
+L["Accepting this will reset the UnitFrame settings for %s. Are you sure?"] = "Al aceptar esto, se restablecerá la configuración de UnitFrame para %s. ¿Estás seguro?"
+L["Accepting this will reset your Filter Priority lists for all auras on NamePlates. Are you sure?"] = "Al aceptar esto, se restablecerán las listas de Prioridad de filtro para todas las auras en NamePlates. ¿Estás seguro?"
+L["Accepting this will reset your Filter Priority lists for all auras on UnitFrames. Are you sure?"] = "Al aceptar esto, se restablecerán las listas de Prioridad de filtro para todas las auras en UnitFrames. ¿Estás seguro?"
+L["Adjust the UI Scale to fit your screen, press the autoscale button to set the UI Scale automatically."] = "Ajuste la escala de la IU para que se ajuste a su pantalla, presione el botón de escala automática para configurar la escala de la IU automáticamente."
+L["All keybindings cleared for |cff00ff00%s|r."] = "Todos los atajos borrados para |cff00ff00%s|r."
+L["Already Running.. Bailing Out!"] = "Ya está en ejecución... ¡Cancelando!"
+L["Are you sure you want to apply this font to all ElvUI elements?"] = "¿Estás seguro de que deseas aplicar esta fuente a todos los elementos de ElvUI?"
+L["Are you sure you want to disband the group?"] = "¿Estás seguro que quieres deshacer el grupo?"
+L["Are you sure you want to reset all the settings on this profile?"] = "¿Estás seguro que deseas restablecer todos los ajustes de este perfil?"
+L["Are you sure you want to reset every mover back to it's default position?"] = "¿Estás seguro que quieres resetear cada fijador a su posición por defecto?"
+L["Arena Frames"] = "Marcos de Arena"
+L["Aura Bars & Icons"] = "Barras de Aura y Iconos"
+L["Auras Set"] = "Conjunto de Auras"
+L["Auras"] = true
+L["Auto Scale"] = "Escalado Automático"
+L["Avoidance Breakdown"] = "Desglose de Evasión"
+L["BG"] = true
+L["BGL"] = true
+L["BNet Frame"] = "Marco BNet"
+L["Bag Mover (Grow Down)"] = "Fijador de Bolsa (Crecer hacia abajo)"
+L["Bag Mover (Grow Up)"] = "Fijador de Bolsa (Crecer hacia arriba)"
+L["Bag Mover"] = "Fijador de Bolsa"
+L["Bags"] = "Bolsas"
+L["Bank Mover (Grow Down)"] = "Fijador de Banco (Crecer hacia abajo)"
+L["Bank Mover (Grow Up)"] = "Fijador de Banco (Crecer hacia arriba)"
+L["Bank"] = "Banco"
+L["Bar "] = "Barra "
+L["Bars"] = "Barras"
+L["Battleground datatexts temporarily hidden, to show type /bgstats or right click the 'C' icon near the minimap."] = "Textos de datos de los campos de batalla temporalmente ocultos, para mostrarlos escribe /bgstats o clic derecho en 'C' donde el minimapa."
+L["Battleground datatexts will now show again if you are inside a battleground."] = "Los textos de datos de los campos de batalla serán visibles de nuevo si estás en un campo de batalla."
+L["Binding"] = "Controles"
+L["Binds Discarded"] = "Teclas Descartadas"
+L["Binds Saved"] = "Teclas Guardadas"
+L["BoE"] = true
+L["BoU"] = true
+L["Boss Frames"] = "Marco de Jefe"
+L["Buffs"] = "Beneficios"
+L["CVars Set"] = "CVars Configuradas"
+L["CVars"] = "CVars"
+L["Calendar"] = "Calendario"
+L["Can't Roll"] = "No puede tirar dados"
+L["Can't buy anymore slots!"] = "¡No puedes comprar más espacios!"
+L["Caster DPS"] = "DPS Hechizos"
+L["Character: "] = "Personaje: "
+L["Chat Set"] = "Chat Configurado"
+L["Chat"] = "Chat"
+L["Choose a theme layout you wish to use for your initial setup."] = "Elige un tema de distribución para usar en tu configuración inicial."
+L["Classbar"] = "Barra de Clase"
+L["Classic"] = "Clásico"
+L["Combat Time"] = "Tiempo en combate"
+L["Combobar"] = "Barra de combos"
+L["Config Mode:"] = "Modo de Configuración"
+L["Confused.. Try Again!"] = "Confundido... ¡Intenta de Nuevo!"
+L["Continue"] = "Continuar"
+L["Coords"] = true
+L["Count"] = "Contador"
+L["DND"] = "Oc"
+L["DPS"] = "DPS"
+L["Dark"] = "Oscuro"
+L["Data From: %s"] = "Datos De: %s"
+L["Data To: %s"] = true
+L["Dead"] = "Muerto"
+L["Debuffs"] = "Perjuicios"
+L["Deficit:"] = "Déficit:"
+L["Delete gray items?"] = "¿Eliminar objetos grises?"
+L["Detected that your ElvUI OptionsUI addon is out of date. This may be a result of your Tukui Client being out of date. Please visit our download page and update your Tukui Client, then reinstall ElvUI. Not having your ElvUI OptionsUI addon up to date will result in missing options."] = "Se ha detectado que tu addon de ElvUI OptionsUI está desactualizado. Ésto puede darse como resultado de que tu cliente Tukui esté desactualizado. Por favor visita nuestra página de descargas y actualiza tu cliente Tukui y entonces reinstala ElvUI. No tener tu addon ElvUI OptionsUI actualizado podría resultar en opciones faltantes."
+L["Disable Warning"] = "Deshabilitar Advertencia"
+L["Disable"] = "Desactivar"
+L["Disband Group"] = "Disolver Grupo"
+L["Discard"] = "Descartar"
+L["Discord"] = true
+L["Do you enjoy the new ElvUI?"] = "¿Disfrutas del nuevo ElvUI?"
+L["Do you swear not to post in technical support about something not working without first disabling the addon/module combination first?"] = "¿Juras no escribir a Soporte Técnico acerca de algo que no funciona sin antes deshabilitar la combinación addon/módulo primero?"
+L["Earned:"] = "Ganada:"
+L["ElvUI Installation"] = "Instalación de ElvUI"
+L["ElvUI Plugin Installation"] = "Instalación del plugin de ElvUI"
+L["ElvUI has a dual spec feature which allows you to load different profiles based on your current spec on the fly. You can enable this from the profiles tab."] = "ElvUI tiene la posibilidad de cargar diferentes perfiles automáticamente al cambiar de especialización de talentos. Puedes activar esta función en la pestaña de perfiles."
+L["ElvUI is five or more revisions out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI está cinco o mas revisiones desactualizado. Puedes descargar la versión más nueva de https://github.com/BanditTech/ElvUI-Ascension"
+L["ElvUI is out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI está desactualizado. Puedes descargar la versión más nueva de https://github.com/BanditTech/ElvUI-Ascension"
+L["ElvUI needs to perform database optimizations please be patient."] = "ElvUI necesita realizar optimizaciones de base de datos por favor se paciente."
+L["ElvUI was updated while the game is still running. Please relaunch the game, as this is required for the files to be properly updated."] = "ElvUI se actualizó mientras el juego aún se está ejecutando. Vuelve a iniciar el juego, ya que es necesario para que los archivos se actualicen correctamente."
+L["Empty Slot"] = "Espacio vacío"
+L["Enable"] = "Habilitar"
+L["Error resetting UnitFrame."] = "Error al restablecer UnitFrame."
+L["Experience Bar"] = "Barra de Experiencia"
+L["Experience"] = "Experiencia"
+L["Export Now"] = true
+L["Farm Mode"] = true
+L["Filter download complete from %s, would you like to apply changes now?"] = "Se completó la descarga de los filtros de %s. ¿Quieres aplicar los cambios ahora?"
+L["Finished"] = "Terminado"
+L["Fishy Loot"] = "Botín Sospechoso"
+L["Focus Castbar"] = "Barra de Lanzamiento del Foco"
+L["Focus Frame"] = "Marco de Foco"
+L["FocusTarget Frame"] = "Marco de Objetivo del Foco"
+L["For technical support visit us at https://github.com/ElvUI-WotLK."] = "Para soporte técnico visítanos en https://github.com/ElvUI-WotLK."
+L["Frame"] = "Marco"
+L["Friends List"] = "Lista de Amigos"
+L["G"] = "H"
+L["GM Ticket Frame"] = "Marco de Consultas para el MJ"
+L["General"] = "General"
+L["Ghost"] = "Fantasma"
+L["Gold"] = "Oro"
+L["Grid Size:"] = "Tamaño de la Rejilla:"
+L["HP"] = "Salud"
+L["HPS"] = "VPS"
+L["Healer"] = "Sanador"
+L["Hit"] = true
+L["Hold Control + Right Click:"] = "Mantén Control y Haz Clic Derecho:"
+L["Hold Shift + Drag:"] = "Mantén Shift y Arrastra:"
+L["Hold Shift + Right Click:"] = "Mantén Shift + Botón Derecho:"
+L["Home Latency:"] = "Latencia Local:"
+L["Hover your mouse over any actionbutton or spellbook button to bind it. Press the ESC key to clear the current actionbutton's keybinding."] = "Pase el mouse sobre cualquier botón de acción o botón del libro de hechizos para vincularlo. Presione la tecla ESC para borrar la combinación de teclas del botón de acción actual."
+L["I Swear"] = "Lo Juro"
+L["INCOMPATIBLE_ADDON"] = "The addon %s is not compatible with ElvUI's %s module. Please select either the addon or the ElvUI module to disable."
+L["Icons Only"] = "Sólo Iconos"
+L["If you accidently remove a chat frame you can always go the in-game configuration menu, press install, go to the chat portion and reset them."] = "Si eliminas un marco de chat accidentalmente, siempre puedes ir a la configuración, pulsar instalar, ir a la parte del chat, y restaurarlo."
+L["If you are experiencing issues with ElvUI try disabling all your addons except ElvUI, remember ElvUI is a full UI replacement addon, you cannot run two addons that do the same thing."] = "Si has experimentado errores con ElvUI prueba a desactivar todos tus addons excepto ElvUI, recuerda que ElvUI remplaza por completo la interfaz, no puede haber addons que hagan lo mismo."
+L["If you have an icon or aurabar that you don't want to display simply hold down shift and right click the icon for it to disapear."] = true
+L["Import Now"] = true
+L["Importance: |cff07D400High|r"] = "Importancia: |cff07D400Alta|r"
+L["Importance: |cffD3CF00Medium|r"] = "Importancia: |cffD3CF00Media|r"
+L["Importance: |cffFF0000Low|r"] = "Importancia: |cffFF0000Baja|r"
+L["In Progress"] = "En Progreso"
+L["Installation Complete"] = "Instalación Completa"
+L["Invalid Target"] = "Objetivo Inválido"
+L["Item Level:"] = "Nivel de Objeto:"
+L["KEY_ALT"] = "A"
+L["KEY_CTRL"] = "C"
+L["KEY_DELETE"] = "Del"
+L["KEY_HOME"] = "Hm"
+L["KEY_INSERT"] = "Ins"
+L["KEY_MOUSEBUTTON"] = "M"
+L["KEY_MOUSEWHEELDOWN"] = "MwD"
+L["KEY_MOUSEWHEELUP"] = "MwU"
+L["KEY_NUMPAD"] = "N"
+L["KEY_PAGEDOWN"] = "PD"
+L["KEY_PAGEUP"] = "PU"
+L["KEY_SHIFT"] = "S"
+L["KEY_SPACE"] = "SpB"
+L["Key"] = "Tecla"
+L["LOGIN_MSG"] = "Welcome to %sElvUI|r version %s%s|r, type /ec to access the in-game configuration menu. If you are in need of technical support you can visit us at https://github.com/BanditTech/ElvUI-Ascension or join our Discord: https://discord.gg/UXSc7nt"
+L["Layout Set"] = "Distribución Establecida"
+L["Layout"] = "Distribución"
+L["Left Chat"] = "Chat Izquierdo"
+L["Left Click:"] = "Clic Izquierdo"
+L["List of installations in queue:"] = "Lista de Instalaciones en cola:"
+L["Lock"] = "Bloquear"
+L["Loot / Alert Frames"] = "Marcos de Botín / Alerta"
+L["Loot Frame"] = "Marco de Botín"
+L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"] = "¡Milagro! ¡La descarga se desvaneció como pedo! Intenta de nuevo"
+L["MA Frames"] = "Marcos de AP"
+L["MT Frames"] = "Marcos de TP"
+L["Micro Bar"] = "Micro Barra"
+L["Minimap"] = "Minimapa"
+L["MirrorTimer"] = "Temporizador"
+L["Miss Chance"] = "Prob. de fallo"
+L["Mitigation By Level: "] = "Mitigación Por Nivel: "
+L["Movers"] = true
+L["Must be in group with the player if he isn't on the same server as you."] = "Debes estar agrupado con el jugador si no está en tu mismo servidor."
+L["No Guild"] = "Sin Hermandad"
+L["No bindings set."] = "No hay teclas establecidas."
+L["No gray items to delete."] = "No hay objetos grises para eliminar."
+L["No, Revert Changes!"] = "¡No, Revierte los Cambios!"
+L["Nudge"] = "Ajuste Fino"
+L["O"] = "O"
+L["Objective Frame"] = "Marco de Objetivo"
+L["Offline"] = "Fuera de Línea"
+L["Oh lord, you have got ElvUI and Tukui both enabled at the same time. Select an addon to disable."] = "Oh cielos, tienes ElvUI y Tukui habilitados al mismo tiempo. Elige un addon a deshabilitar"
+L["On screen positions for different elements."] = true
+L["One or more of the changes you have made require a ReloadUI."] = "Uno o más de los cambios que has hecho requieren una recarga de la interfaz."
+L["One or more of the changes you have made will effect all characters using this addon. You will have to reload the user interface to see the changes you have made."] = "Uno o más de los cambios que has hecho afectaran a todos los personajes que usen este addon. Tendrás que recargar la intefaz de usuario para ver el cambio que has realizado."
+L["P"] = "G"
+L["PL"] = "LG"
+L["Party Frames"] = "Marco de Grupo"
+L["Pending"] = "Pendiente"
+L["Pet Bar"] = "Barra de Mascota"
+L["Pet Castbar"] = "Barra de Lanzamiento de Mascota"
+L["Pet Frame"] = "Marco de Mascota"
+L["PetTarget Frame"] = "Marco de Objetivo de Mascota"
+L["Player Buffs"] = "Ventajas de Jugador"
+L["Player Castbar"] = "Barra de Lanzamiento del Jugador"
+L["Player Debuffs"] = "Perjuicios de Jugador"
+L["Player Frame"] = "Marco de Jugador"
+L["Player Powerbar"] = "Barra de Poder del Jugador"
+L["Please click the button below so you can setup variables and ReloadUI."] = "Haz clic en el botón de abajo para configurar variables y recargar la interfaz."
+L["Please click the button below to setup your CVars."] = "Haz clic en el botón de abajo para configurar las CVars"
+L["Please press the continue button to go onto the next step."] = "Presiona el botón de continuar para ir al siguiente paso"
+L["Preview Changes"] = "Previsualizar cambios"
+L["Preview"] = "Preestreno"
+L["Profile download complete from %s, but the profile %s already exists. Change the name or else it will overwrite the existing profile."] = "Descarga de perfil de %s completa, pero el perfil %s ya existe. Cámbiale el nombre o se reemplazará el perfil existente."
+L["Profile download complete from %s, would you like to load the profile %s now?"] = "Descarga de perfil de %s completa ¿Quieres cargar el perfil %s ahora?"
+L["Profile request sent. Waiting for response from player."] = "Petición de perfil enviada. Esperando respuesta del jugador."
+L["Profit:"] = "Ganancia:"
+L["Purchase Bags"] = "Comprar Bolsas"
+L["PvP"] = true
+L["R"] = "B"
+L["RL"] = "LB"
+L["RW"] = "AB"
+L["Raid Frames"] = "Marcos de Banda"
+L["Raid Menu"] = "Menú de Banda"
+L["Raid Pet Frames"] = "Marcos de Banda con Mascotas"
+L["Raid-40 Frames"] = "Marcos de Banda de 40"
+L["Reload UI"] = true
+L["Remaining:"] = "Restante"
+L["Remove Bar %d Action Page"] = "Quitar Barra %d de la paginación"
+L["Reputation Bar"] = "Barra de Reputación"
+L["Request was denied by user."] = "Petición denegada por el jugador."
+L["Reset Counters: Hold Shift + Left Click"] = "Reiniciar contador: Shift + Click derecho."
+L["Reset Data: Hold Shift + Right Click"] = "Restablecer los Datos: Mantén Shift + Clic Derecho"
+L["Reset Position"] = "Reestablecer Posición"
+L["Rested:"] = "Descansado:"
+L["Right Chat"] = "Chat Derecho"
+L["Right Click:"] = true
+L["SP"] = "PH"
+L["Save"] = "Guardar"
+L["Saved Dungeon(s)"] = "Mazmorra(s) Guardada"
+L["Saved Raid(s)"] = "Banda(s) Guardada(s)"
+L["Select the type of aura system you want to use with ElvUI's unitframes. Set to Aura Bar & Icons to use both aura bars and icons, set to icons only to only see icons."] = "Seleccione el tipo de sistema de aura que desea usar con los cuadros unitarios de ElvUI. Establezca en barras de Aura y Iconos para usar tanto las barras de aura como los íconos, configure los íconos solo para ver solo los íconos."
+L["Server: "] = "Servidor: "
+L["Session:"] = "Sesión:"
+L["Setup CVars"] = "Configurar CVars"
+L["Setup Chat"] = "Configurar Chat"
+L["Show BG Texts"] = true
+L["Skip Process"] = "Saltar Proceso"
+L["Sort Bags"] = "Ordenar Bolsas"
+L["Spell/Heal Power"] = "Hechizo / Poder de Curación"
+L["Spent:"] = "Gastada:"
+L["Stance Bar"] = "Barra de Forma"
+L["Stats For:"] = "Estadísticas para:"
+L["Steps"] = "Pasos"
+L["Sticky Frames"] = "Marcos Adhesivos"
+L["System"] = "Sistema"
+L["Talent Specialization:"] = "Especialización de talentos"
+L["Tank / Physical DPS"] = "Tanque / DPS Físico"
+L["Target Castbar"] = "Barra de Lanzamiento del Objetivo"
+L["Target Frame"] = "Marco de Objetivo"
+L["Target Powerbar"] = "Barra de Poder del Objetivo"
+L["TargetTarget Frame"] = "Marco de Objetivo de Objetivo"
+L["TargetTargetTarget Frame"] = "Marco del Objetivo del Objetivo del Objetivo"
+L["Targeted By:"] = "Objetivo De:"
+L["Temporary Move"] = "Movimiento Temporal"
+L["The UI Scale has been changed, if you would like to preview the change press the preview button. It is recommended that you reload your User Interface for the best appearance."] = "El escalado de interfaz ha sido cambiado, si quieres ver los cambios pulsa el botón de previsualizar. Es recomendable que reinicies la interfaz para una mejor experiencia."
+L["The chat windows function the same as Blizzard standard chat windows, you can right click the tabs and drag them around, rename, etc. Please click the button below to setup your chat windows."] = "Las ventanas de chat funcionan igual que sus contrapartes estándar de Blizzard. Puedes hacer clic derecho en las pestañas y arrastrarlas, cambiarles el nombre, etc. Haz clic en el botón de abajo para configurar las ventanas de chat."
+L["The focus unit can be set by typing /focus when you are targeting the unit you want to focus. It is recommended you make a macro to do this."] = "El foco puede establecerse escribiendo /enfoque cuando tienes seleccionado al objetivo al cual quieres hacer foco. Es recomendable que hagas una macro para esto."
+L["The in-game configuration menu can be accessed by typing the /ec command or by clicking the 'C' button on the minimap. Press the button below if you wish to skip the installation process."] = "El menú de configuración puede ser accedido mediante el comando /ec o haciendo clic en el botón 'C' del minimapa. Presiona el botón de abajo si deseas saltarte la instalación."
+L["The profile you tried to import already exists. Choose a new name or accept to overwrite the existing profile."] = "El perfil que has intentado importar ya existe. Elige un nuevo nombre o acepta sobreescribir el perfil existente."
+L["The spell '%s' has been added to the Blacklist unitframe aura filter."] = "El hechizo '%s' ha sido añadido a la Lista Negra del filtro de auras del marco de unidad."
+L["Theme Set"] = "Establecer Tema"
+L["Theme Setup"] = "Configurar Tema"
+L["This install process will help you learn some of the features in ElvUI has to offer and also prepare your user interface for usage."] = "El proceso de instalación te ayudará a aprender algunas de las características de ElvUI y preparará la interfaz para su uso."
+L["This part of the installation process sets up your World of Warcraft default options it is recommended you should do this step for everything to behave properly."] = "Esta parte de la instalación configura las opciones predeterminadas de World of Warcraft. Se recomienda hacer este paso para que todo funcione apropiadamente."
+L["This part of the installation process sets up your chat windows names, positions and colors."] = "Esta parte de la instalación configura los nombres, posiciones y colores de las ventanas de chat."
+L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."] = "Esta opción causó un punto de fijación en conflicto, donde '%s' estaría adjunto a sí mismo. Por favor comprueba tus puntos de fijación. Opción '%s' a ser fijado a '%s'"
+L["This will change the layout of your unitframes and actionbars."] = "Ésto cambiará el diseño de los marcos de unidades y barras de acción."
+L["To move abilities on the actionbars by default hold shift + drag. You can change the modifier key from the actionbar options menu."] = "Para mover habilidades a las barras de acción mantener shift + arrastrar. Puedes cambiar la tecla de modificación desde el menú de opciones de la barra de acción."
+L["To setup which channels appear in which chat frame, right click the chat tab and go to settings."] = "Para configurar que canales aparecen en el chat, haz clic con el botón derecho en la pestaña del chat y elige opciones."
+L["Toggle Bags"] = "Mostrar/Ocultar Bolsas"
+L["Toggle Chat Frame"] = "Mostrar/Ocultar Marco de Chat"
+L["Toggle Configuration"] = "Mostrar/Ocultar Configuración"
+L["Tooltip"] = "Descripción Emergente"
+L["Total CPU:"] = "CPU Total:"
+L["Total Memory:"] = "Memoria Total:"
+L["Total: "] = "Total: "
+L["Trigger"] = "Disparador"
+L["Type /hellokitty to revert to old settings."] = "Escribe /hellokitty para revertir a las opciones antiguas."
+L["UI Scale"] = "Escalado de interfaz"
+L["Unhittable:"] = "Imbatible:"
+L["Vehicle Seat Frame"] = "Marco del Asiento del Vehículo"
+L["Vendor / Delete Grays"] = "Vender / Eliminar Grises"
+L["Vendored gray items for: %s"] = "Objetos grises vendidos por: %s"
+L["Vendoring Grays"] = "Vendiendo Grises"
+L["Welcome to ElvUI version %s!"] = "Bienvenido(a) a ElvUI versión %s!"
+L["Wintergrasp"] = "Conquista del Invierno"
+L["XP:"] = "XP:"
+L["Yes, Keep Changes!"] = "¡Sí, Mantén los cambios!"
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"] = true
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"] = true
+L["You are now finished with the installation process. If you are in need of technical support please visit us at https://github.com/ElvUI-WotLK."] = "Ya has terminado con el proceso de instalación. Si necesitas ayuda o soporte técnico por favor visítanos en https://github.com/ElvUI-WotLK."
+L["You are using CPU Profiling. This causes decreased performance. Do you want to disable it or continue?"] = "Está utilizando el perfil de CPU CVar. Esto provoca una disminución del rendimiento. ¿Desea deshabilitarlo o continuar?"
+L["You can access copy chat and chat menu functions by mouse over the top right corner of chat panel and left/right click on the button that will appear."] = "Puedes acceder a copiar y a las opciones del chat pasando el ratón sobre la esquina superior derecha del panel del chat y haciendo clic en el botón que aparece."
+L["You can always change fonts and colors of any element of ElvUI from the in-game configuration."] = "Siempre puedes cambiar las fuentes y colores de cualquier elemento de ElvUI desde la configuración."
+L["You can now choose what layout you wish to use based on your combat role."] = "Ahora puedes elegir qué distribución quieres basándote en tu rol de combate."
+L["You can see someones average item level of their gear by holding shift and mousing over them. It should appear inside the tooltip."] = "Puedes ver la media de nivel de objeto de un objetivo manteniendo pulsado shift mientras pasas el ratón por encima de él. El iNvl aparecerá en la descripción emergente."
+L["You can set your keybinds quickly by typing /kb."] = "Puedes establecer tus atajos rapidamente escribiendo /kb."
+L["You can toggle the microbar by using your middle mouse button on the minimap you can also accomplish this by enabling the actual microbar located in the actionbar settings."] = "Puedes acceder a la microbarra usando tu botón central del ratón sobre el minimapa. También puedes activarla desde las opciones de las barras de acción."
+L["You can use the /resetui command to reset all of your movers. You can also use the command to reset a specific mover, /resetui .\nExample: /resetui Player Frame"] = "Puedes usar el commando /resetui para restablecer todos tus fijadores. También puedes usar el comando para restablecer alguno en específico, /resetui . PE: /resetui Player Frame"
+L["You cannot copy settings from the same unit."] = "No puedes copiar la configuración desde la misma unidad"
+L["You don't have enough money to repair all items."] = true
+L["You don't have enough money to repair."] = "No tienes suficiente dinero para reparaciones."
+L["You don't have permission to mark targets."] = "No tienes permiso para marcar objetivos."
+L["You have imported settings which may require a UI reload to take effect. Reload now?"] = "Has importado opciones que pueden requerir una recarga de la interfaz para tomar efecto. ¿Recargar ahora?"
+L["You must purchase a bank slot first!"] = "¡Debes comprar un hueco del banco primero!"
+L["You still have ElvUI_Config installed. ElvUI_Config has been renamed to ElvUI_OptionsUI, please remove it."] = true
+L["Your items have been repaired for: "] = "Tus objetos han sido reparados por:"
+L["Your items have been repaired using guild bank funds for: "] = "Tus objetos han sido reparados con fondos del banco de hermandad por:"
+L["Your profile was successfully recieved by the player."] = "Tu perfil ha sido recibido exitosamente por el jugador."
+L["copperabbrev"] = "|cffeda55fc|r"
+L["goldabbrev"] = "|cffffd700g|r"
+L["lvl"] = "Niv"
+L["says"] = "dice"
+L["silverabbrev"] = "|cffc7c7cfs|r"
+L["whispers"] = "susurra"
+L["yells"] = "grita"
+L["|cFFE30000Lua error recieved. You can view the error message when you exit combat."] = "|cFFE30000Error de Lua recibido. Podrás ver el error cuando salgas de combate."
+
+----------------------------------
+L["RED_ENABLE"] = "|cFFff3333Habilitar|r"
+L["GREEN_ENABLE"] = "|cFF33ff33Habilitar|r"
+L["DESC_MOVERCONFIG"] = [=[Fijadores desbloqueados. Muévelos ahora y haz clic en Bloquear cuando termines.
+Opciones:
+ Clic Izquierdo - Mostrar/Ocultar empujar marco.
+ Clic Derecho - Abrir la sección de configuración.
+ Shift + Clic Derecho - Ocultar los fijadores temporalmente.
+ Ctrl + Clic Derecho - Restablece la posición de los fijadores a los valores por defecto.
+]=]
\ No newline at end of file
diff --git a/ElvUI/Locales/frFR.lua b/ElvUI/Locales/frFR.lua
new file mode 100644
index 0000000..fee99e6
--- /dev/null
+++ b/ElvUI/Locales/frFR.lua
@@ -0,0 +1,331 @@
+-- French localization file for frFR.
+local E = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "frFR")
+
+L[" |cff00ff00bound to |r"] = "|cff00ff00assigné à |r"
+L["%s frame(s) has a conflicting anchor point, please change either the buff or debuff anchor point so they are not attached to each other. Forcing the debuffs to be attached to the main unitframe until fixed."] = "% du (des) cadre(s) à un point d'ancrage contradictoire(s), merci de changer le point d'ancrage des améliorations ou des affaiblissements de sorte qu'ils ne soient pas attachés les uns aux autres. Forcer les affaiblissements à être attachés au cadre d'unité principale jusqu'à ce qu'ils soient fixés."
+L["%s is attempting to share his filters with you. Would you like to accept the request?"] = "%s tente de partager ses filtres avec vous. Voulez-vous accepter la demande ?"
+L["%s is attempting to share the profile %s with you. Would you like to accept the request?"] = "%s tente de partager le profil %s avec vous. Voulez-vous accepter la demande ?"
+L["%s: %s tried to call the protected function '%s'."] = "%s: %s a essayé d'appeler la fonction protégée '%s'."
+L["(Hold Shift) Memory Usage"] = "(Maintenir MAJ) Utilisation de la Mémoire."
+L["(Modifer Click) Collect Garbage"] = true
+L["A raid marker feature is available by pressing Escape -> Keybinds scroll to the bottom under ElvUI and setting a keybind for the raid marker."] = "Une fonction marqueur de raid est disponible en appuyant sur Échap -> Raccourcis, défilez en bas d'ElvUI et paramétrez le raccourcis pour le marqueur de raid."
+L["A setting you have changed will change an option for this character only. This setting that you have changed will be uneffected by changing user profiles. Changing this setting requires that you reload your User Interface."] = "Un réglage que vous avez modifié ne s'appliquera que pour ce personnage. La modification de ce réglage ne sera pas affecté par un changement de profil. Changer ce réglage requiert de relancer l'interface."
+L["ABOVE_THREAT_FORMAT"] = "%s: %.0f%% [%.0f%% excès |cff%02x%02x%02x%s|r]"
+L["AFK"] = "ABS"
+L["Accepting this will reset the UnitFrame settings for %s. Are you sure?"] = true
+L["Accepting this will reset your Filter Priority lists for all auras on NamePlates. Are you sure?"] = "En acceptant, votre liste de priorités des filtres sera réinitialisée pour les auras des barre de noms. Êtes-vous sûr ?"
+L["Accepting this will reset your Filter Priority lists for all auras on UnitFrames. Are you sure?"] = "En acceptant, votre liste de priorités des filtres sera réinitialisée pour les auras des cadres d'unités. Êtes-vous sûr ?"
+L["Adjust the UI Scale to fit your screen, press the autoscale button to set the UI Scale automatically."] = true
+L["All keybindings cleared for |cff00ff00%s|r."] = "Tous les raccourcis ont été effacés pour |cff00ff00%s|r."
+L["Already Running.. Bailing Out!"] = "Déjà en cours d'exécution, arrêt du processus..."
+L["Are you sure you want to apply this font to all ElvUI elements?"] = "Êtes-vous sûr de vouloir appliquer cette police à tous les éléments d'ELvUI ?"
+L["Are you sure you want to disband the group?"] = "Êtes-vous sûr de vouloir dissoudre le groupe ? "
+L["Are you sure you want to reset all the settings on this profile?"] = "Êtes-vous sûr de vouloir réinitialiser tous les réglages sur ce profil ?"
+L["Are you sure you want to reset every mover back to it's default position?"] = "Êtes-vous sûr de vouloir réinitialiser tous les cadres à leur position par défaut ?"
+L["Arena Frames"] = "Cadre d'arène"
+L["Aura Bars & Icons"] = true
+L["Auras Set"] = true
+L["Auras"] = "Auras"
+L["Auto Scale"] = "Échelle automatique"
+L["Avoidance Breakdown"] = "Répartition de l'évitement"
+L["BG"] = true
+L["BGL"] = true
+L["BNet Frame"] = "Cadre BNet"
+L["Bag Mover (Grow Down)"] = "Orientation des sacs (ajouter vers le bas)"
+L["Bag Mover (Grow Up)"] = "Orientation des sacs (ajouter vers le haut)"
+L["Bag Mover"] = "Orientation des sacs"
+L["Bags"] = "Sacs"
+L["Bank Mover (Grow Down)"] = "Orientation de la banque (ajouter vers le bas)"
+L["Bank Mover (Grow Up)"] = "Orientation de la banque (ajouter vers le haut)"
+L["Bank"] = "Banque"
+L["Bar "] = "Barre "
+L["Bars"] = "Barres"
+L["Battleground datatexts temporarily hidden, to show type /bgstats or right click the 'C' icon near the minimap."] = "Textes d'informations du champ de bataille temporairement masqués, pour les afficher tapez /bgstats ou cliquez droit sur le 'C' près de la mini-carte."
+L["Battleground datatexts will now show again if you are inside a battleground."] = "Les textes d'informations du champ de bataille seront à nouveau affichés si vous êtes dans un champ de bataille."
+L["Binding"] = "Raccourcis"
+L["Binds Discarded"] = "Raccourcis annulés"
+L["Binds Saved"] = "Raccourcis sauvegardés"
+L["BoE"] = true
+L["BoU"] = true
+L["Boss Frames"] = "Cadre du Boss"
+L["Buffs"] = "Améliorations"
+L["CVars Set"] = "CVars configurées"
+L["CVars"] = "CVars"
+L["Calendar"] = "Calendrier"
+L["Can't Roll"] = "Ne peut pas jeter les dés"
+L["Can't buy anymore slots!"] = "Impossible d'acheter plus emplacements !"
+L["Caster DPS"] = "DPS distance"
+L["Character: "] = "Personnage : "
+L["Chat Set"] = "Chat configuré"
+L["Chat"] = "Discussion"
+L["Choose a theme layout you wish to use for your initial setup."] = "Choisissez un modèle de thème que vous souhaitez utiliser pour votre configuration initiale."
+L["Classbar"] = "Barre de classe"
+L["Classic"] = "Classique"
+L["Combat Time"] = "Temps Combat"
+L["Combobar"] = "Barre des points de combo"
+L["Config Mode:"] = "Mode Configuration :"
+L["Confused.. Try Again!"] = "Confus... Essayez à nouveau !"
+L["Continue"] = true
+L["Coords"] = "Coordonnées"
+L["Count"] = "Nombre"
+L["DND"] = "OQP"
+L["DPS"] = "DPS"
+L["Dark"] = "Sombre"
+L["Data From: %s"] = "Donnée de : %s"
+L["Data To: %s"] = true
+L["Dead"] = "Mort"
+L["Debuffs"] = "Affaiblissements"
+L["Deficit:"] = "Déficit :"
+L["Delete gray items?"] = true
+L["Detected that your ElvUI OptionsUI addon is out of date. This may be a result of your Tukui Client being out of date. Please visit our download page and update your Tukui Client, then reinstall ElvUI. Not having your ElvUI OptionsUI addon up to date will result in missing options."] = "Nous avons détecté que votre installation d'ElvUI est périmée. Cela peut venir du client Tukui qui est également périmé. Merci de visiter notre page de téléchargement pour mettre à jour le client Tukui, puis réinstallez ElvUI. Ne pas avoir la version à jour ElvUI peut entrainer des erreurs."
+L["Disable Warning"] = "Désactiver l'alerte"
+L["Disable"] = "Désactiver"
+L["Disband Group"] = "Dissoudre le groupe"
+L["Discard"] = "Annuler"
+L["Discord"] = true
+L["Do you enjoy the new ElvUI?"] = "Aimez-vous le nouveau ElvUI ?"
+L["Do you swear not to post in technical support about something not working without first disabling the addon/module combination first?"] = "Jurez-vous de ne pas poster sur le support technique du forum sur quelque chose qui ne fonctionne pas sans avoir désactivé en premier la combinaison Addon/Module?"
+L["Earned:"] = "Gagné :"
+L["ElvUI Installation"] = "Installation d'ElvUI"
+L["ElvUI Plugin Installation"] = "Installation des plugins ElvUI"
+L["ElvUI has a dual spec feature which allows you to load different profiles based on your current spec on the fly. You can enable this from the profiles tab."] = "ElvUI dispose d'une fonction double spécialisation qui vous permet de charger à la volée des profils différents en fonction de votre spécialisation actuelle."
+L["ElvUI is five or more revisions out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI est périmé d'au moins 5 versions. Vous pouvez télécharger la nouvelle version sur https://github.com/BanditTech/ElvUI-Ascension"
+L["ElvUI is out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI est périmé. Vous pouvez télécharger la nouvelle version sur https://github.com/BanditTech/ElvUI-Ascension"
+L["ElvUI needs to perform database optimizations please be patient."] = "ElvUI a besoin d'effectuer des optimisations de la base de données, merci de patienter."
+L["ElvUI was updated while the game is still running. Please relaunch the game, as this is required for the files to be properly updated."] = true
+L["Empty Slot"] = "Emplacement vide"
+L["Enable"] = "Activer"
+L["Error resetting UnitFrame."] = true
+L["Experience Bar"] = "Barre d'expérience"
+L["Experience"] = "Expérience"
+L["Export Now"] = "Exporter maintenant"
+L["Farm Mode"] = "Mode farm"
+L["Filter download complete from %s, would you like to apply changes now?"] = "Téléchargement du filtre de %s complet, voulez-vous appliquer les changements maintenant ?"
+L["Finished"] = "Terminé"
+L["Fishy Loot"] = "Butin de pêche"
+L["Focus Castbar"] = "Barre d'incantation du focus"
+L["Focus Frame"] = "Cadre focus"
+L["FocusTarget Frame"] = "Cadre de la cible de votre focus"
+L["For technical support visit us at https://github.com/ElvUI-WotLK."] = "Pour tout support technique, merci de nous rendre visite sur https://github.com/ElvUI-WotLK."
+L["Frame"] = "Fenêtre"
+L["Friends List"] = "Liste d'amis"
+L["G"] = "G"
+L["GM Ticket Frame"] = "Cadre du ticket MJ"
+L["General"] = "Général"
+L["Ghost"] = "Fantôme"
+L["Gold"] = "Or"
+L["Grid Size:"] = "Taille de la grille :"
+L["HP"] = "PV"
+L["HPS"] = "HPS"
+L["Healer"] = "Soigneur"
+L["Hit"] = true
+L["Hold Control + Right Click:"] = "Contrôle enfoncé + Clic droit"
+L["Hold Shift + Drag:"] = "Majuscule enfoncée + Déplacer"
+L["Hold Shift + Right Click:"] = "Maintenir Majuscule + Clic droit"
+L["Home Latency:"] = "Latence du Domicile :"
+L["Hover your mouse over any actionbutton or spellbook button to bind it. Press the ESC key to clear the current actionbutton's keybinding."] = true
+L["I Swear"] = "Je le jure"
+L["INCOMPATIBLE_ADDON"] = "L'addon %s n'est pas compatible avec le module %s d'ElvUI. Merci de sélectionner soit l'addon, soit le module d'ElvUI, pour le désactiver."
+L["Icons Only"] = "Icônes seulement"
+L["If you accidently remove a chat frame you can always go the in-game configuration menu, press install, go to the chat portion and reset them."] = "Si vous supprimez accidentellement un cadre de discussion, vous pouvez toujours aller dans le menu de configuration d'ElvUI. Cliquez ensuite sur Installation puis passez à l'étape concernant les fenêtres de discussion pour remettre à zéro les paramètres."
+L["If you are experiencing issues with ElvUI try disabling all your addons except ElvUI, remember ElvUI is a full UI replacement addon, you cannot run two addons that do the same thing."] = "Si vous rencontrez des problèmes avec ElvUI, essayez de désactiver tous vos addons sauf ElvUI. Rappelez-vous qu'ElvUi est une interface utilisateur complète et que vous ne pouvez pas exécuter deux addons qui font la même chose."
+L["If you have an icon or aurabar that you don't want to display simply hold down shift and right click the icon for it to disapear."] = true
+L["Import Now"] = "Importer maintenant"
+L["Importance: |cff07D400High|r"] = "Importance : |cff07D400Haute|r"
+L["Importance: |cffD3CF00Medium|r"] = "Importance : |cffD3CF00Moyenne|r"
+L["Importance: |cffFF0000Low|r"] = "Importance : |cffFF0000Faible|r"
+L["In Progress"] = "En cours"
+L["Installation Complete"] = "Installation terminée"
+L["Invalid Target"] = "Cible incorrecte"
+L["Item Level:"] = true
+L["KEY_ALT"] = "A"
+L["KEY_CTRL"] = "C"
+L["KEY_DELETE"] = "Suppr"
+L["KEY_HOME"] = "Hm"
+L["KEY_INSERT"] = "Ins"
+L["KEY_MOUSEBUTTON"] = "M"
+L["KEY_MOUSEWHEELDOWN"] = "MwD"
+L["KEY_MOUSEWHEELUP"] = "MwU"
+L["KEY_NUMPAD"] = "N"
+L["KEY_PAGEDOWN"] = "PD"
+L["KEY_PAGEUP"] = "PU"
+L["KEY_SHIFT"] = "S"
+L["KEY_SPACE"] = "SpB"
+L["Key"] = "Touche"
+L["LOGIN_MSG"] = "Welcome to %sElvUI|r version %s%s|r, type /ec to access the in-game configuration menu. If you are in need of technical support you can visit us at https://github.com/BanditTech/ElvUI-Ascension or join our Discord: https://discord.gg/UXSc7nt"
+L["Layout Set"] = "Disposition configurée"
+L["Layout"] = "Disposition"
+L["Left Chat"] = "Chat gauche"
+L["Left Click:"] = "Clic Gauche:"
+L["List of installations in queue:"] = "Liste des installations en file d'attente"
+L["Lock"] = "Verrouiller"
+L["Loot / Alert Frames"] = "Cadres de butin / Alerte"
+L["Loot Frame"] = "Cadre de butin"
+L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"] = "Seigneur ! C'est un miracle ! Le téléchargement s'est envolé et a disparu comme un pet dans le vent ! Essayez encore !"
+L["MA Frames"] = "Cadres de l'assistant principal"
+L["MT Frames"] = "Cadres du tank principal"
+L["Micro Bar"] = "Micro Barre"
+L["Minimap"] = "Minicarte"
+L["MirrorTimer"] = "Timer mirroir"
+L["Miss Chance"] = true
+L["Mitigation By Level: "] = "Réduction par niveau : "
+L["Movers"] = true
+L["Must be in group with the player if he isn't on the same server as you."] = "Doit être dans le même groupe avec le joueur s'il n'est pas du même serveur."
+L["No Guild"] = "Pas de Guilde"
+L["No bindings set."] = "Aucune assignation"
+L["No gray items to delete."] = "Aucun objet gris à détruire."
+L["No, Revert Changes!"] = "Non, annuler les changements !"
+L["Nudge"] = "Pousser"
+L["O"] = "O"
+L["Objective Frame"] = "Cadre d'objectif"
+L["Offline"] = "Déconnecté"
+L["Oh lord, you have got ElvUI and Tukui both enabled at the same time. Select an addon to disable."] = "Oh seigneur, vous avez ElvUI et Tukui d'activé en même temps. Sélectionnez un addon à désactiver."
+L["On screen positions for different elements."] = true
+L["One or more of the changes you have made require a ReloadUI."] = "Une ou plusieurs modifications que vous avez effectuées nécessitent un rechargement de l'interface."
+L["One or more of the changes you have made will effect all characters using this addon. You will have to reload the user interface to see the changes you have made."] = "Un ou plusieurs changements que vous avez effectués a une incidence sur tous les personnages qui utilisent cet addon. Vous devez recharger l'interface utilisateur pour voir le(s) changement(s) apporté(s)."
+L["P"] = "Gr"
+L["PL"] = "CdG"
+L["Party Frames"] = "Cadres de groupe"
+L["Pending"] = "En attente"
+L["Pet Bar"] = "Barre du familier"
+L["Pet Castbar"] = "Barre d'incantation du familier"
+L["Pet Frame"] = "Cadre du familier"
+L["PetTarget Frame"] = "Cadre de la cible du familier"
+L["Player Buffs"] = "Améliorations du joueur"
+L["Player Castbar"] = "Barre d'incantation du joueur"
+L["Player Debuffs"] = "Affaiblissements du joueur"
+L["Player Frame"] = "Cadre du joueur"
+L["Player Powerbar"] = "Barre de pouvoir du joueur"
+L["Please click the button below so you can setup variables and ReloadUI."] = "Pour configurer les variables et recharger l'interface, cliquez sur le bouton ci-dessous."
+L["Please click the button below to setup your CVars."] = "Pour configurer les CVars, cliquez sur le bouton ci-dessous."
+L["Please press the continue button to go onto the next step."] = "Pour passer à l'étape suivante, cliquez sur le bouton Continuer."
+L["Preview Changes"] = true
+L["Preview"] = true
+L["Profile download complete from %s, but the profile %s already exists. Change the name or else it will overwrite the existing profile."] = "Téléchargement du profil de %s complet, mais le profil de % existe déjà. Changez le nom ou il écrasera le profil existant."
+L["Profile download complete from %s, would you like to load the profile %s now?"] = "Téléchargement du profil de %s complet, voulez-vous charger le profil %s maintenant ?"
+L["Profile request sent. Waiting for response from player."] = "Requête du profil envoyé. En attente de la réponse du joueur."
+L["Profit:"] = "Profit :"
+L["Purchase Bags"] = "Acheter des sacs"
+L["PvP"] = true
+L["R"] = "R"
+L["RL"] = "RL"
+L["RW"] = "RW"
+L["Raid Frames"] = "Cadres de raid"
+L["Raid Menu"] = "Menu Raid"
+L["Raid Pet Frames"] = "Cadres de raid des familiers"
+L["Raid-40 Frames"] = "Cadres de raid 40"
+L["Reload UI"] = true
+L["Remaining:"] = "Restant :"
+L["Remove Bar %d Action Page"] = "Retirer la pagination de la barre d'action"
+L["Reputation Bar"] = "Barre de réputation"
+L["Request was denied by user."] = "La requête a été refusée par l'utilisateur."
+L["Reset Counters: Hold Shift + Left Click"] = true
+L["Reset Data: Hold Shift + Right Click"] = "RAZ des données : MAJ + Clic droit"
+L["Reset Position"] = "Réinitialiser la position"
+L["Rested:"] = "Reposé :"
+L["Right Chat"] = "Chat de droite"
+L["Right Click:"] = "Clic droit:"
+L["SP"] = "PdS"
+L["Save"] = "Sauvegarder"
+L["Saved Dungeon(s)"] = "Donjon(s) sauvegardé(s)"
+L["Saved Raid(s)"] = "Raid(s) sauvegardé(s)"
+L["Select the type of aura system you want to use with ElvUI's unitframes. Set to Aura Bar & Icons to use both aura bars and icons, set to icons only to only see icons."] = true
+L["Server: "] = "Serveur : "
+L["Session:"] = "Session :"
+L["Setup CVars"] = "Configurer les CVars"
+L["Setup Chat"] = "Configurer le chat"
+L["Show BG Texts"] = true
+L["Skip Process"] = "Passer cette étape"
+L["Sort Bags"] = "Trier les sacs"
+L["Spell/Heal Power"] = "Puissance d'attaque / de soin"
+L["Spent:"] = "Dépensé :"
+L["Stance Bar"] = "Barre de posture"
+L["Stats For:"] = "Statistiques pour :"
+L["Steps"] = "Etapes"
+L["Sticky Frames"] = "Cadres aimantés"
+L["System"] = "Système"
+L["Talent Specialization:"] = "Spécialisation des talents:"
+L["Tank / Physical DPS"] = "Tank / DPS physique"
+L["Target Castbar"] = "Barre d'incantation de la cible"
+L["Target Frame"] = "Cadre de la cible"
+L["Target Powerbar"] = "Barre de pouvoir de la cible"
+L["TargetTarget Frame"] = "Cadre de la cible de votre cible"
+L["TargetTargetTarget Frame"] = "Cadre de la cible de la cible de la cible"
+L["Targeted By:"] = "Ciblé par :"
+L["Temporary Move"] = "Déplacer temporairement"
+L["The UI Scale has been changed, if you would like to preview the change press the preview button. It is recommended that you reload your User Interface for the best appearance."] = true
+L["The chat windows function the same as Blizzard standard chat windows, you can right click the tabs and drag them around, rename, etc. Please click the button below to setup your chat windows."] = "La fenêtre de chat ElvUI utilise les même fonctions que celle de Blizzard, vous pouvez faire un clic droit sur un onglet pour le déplacer, le renommer, etc."
+L["The focus unit can be set by typing /focus when you are targeting the unit you want to focus. It is recommended you make a macro to do this."] = "Le cadre de focus peut être défini en tapant /focus quand vous êtes en train de cibler une unité que vous voulez mettre en focus. Il est recommandé de faire une macro pour cela."
+L["The in-game configuration menu can be accessed by typing the /ec command or by clicking the 'C' button on the minimap. Press the button below if you wish to skip the installation process."] = "Le menu de configuration est accessible en tapant la commande /ec ou en cliquant sur le bouton 'C' sur la mini-carte. Cliquez sur le bouton ci-dessous si vous voulez passer le processus d'installation."
+L["The profile you tried to import already exists. Choose a new name or accept to overwrite the existing profile."] = "Le profil que vous essayez d'importer existe déjà. Choisissez un nouveau nom ou acceptez d'écraser le profil existant."
+L["The spell '%s' has been added to the Blacklist unitframe aura filter."] = "Le sort '%s' a bien été ajouté à la liste noire des filtres des cadres d'unités."
+L["Theme Set"] = "Thème configuré"
+L["Theme Setup"] = "Configuration du thème"
+L["This install process will help you learn some of the features in ElvUI has to offer and also prepare your user interface for usage."] = "Ce programme d'installation vous aidera à découvrir quelques fonctionnalités qu'ElvUI offre et préparera également votre interface à son utilisation."
+L["This part of the installation process sets up your World of Warcraft default options it is recommended you should do this step for everything to behave properly."] = "Cette partie du processus d'installation paramètrera vos options par défaut de World of Warcraft. Il est recommandé d'effectuer cette étape afin que tout fonctionne correctement."
+L["This part of the installation process sets up your chat windows names, positions and colors."] = "Cette partie du processus d'installation configure les noms, positions et couleurs de vos fenêtres de chat."
+L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."] = "Cette configuration a causé un conflit avec le point d'ancrage, où '%s' devrait y être rattaché. Veuillez vérifier les points d'ancrages. La configuration de '%s' sera attachée à '%s'."
+L["This will change the layout of your unitframes and actionbars."] = "Ceci changera la disposition des cadres d'unités et des barres d'actions."
+L["To move abilities on the actionbars by default hold shift + drag. You can change the modifier key from the actionbar options menu."] = "Pour déplacer par défaut les capacités des barres d'actions, maintenez MAJ + déplacer. Vous pouvez modifier la touche de modification dans le menu des barres d'actions."
+L["To setup which channels appear in which chat frame, right click the chat tab and go to settings."] = "Pour configurer quels canaux de discussions doivent apparaitre dans les fenêtres de chat, faites un clic droit sur l'onglet de chat et allez dans les paramètres."
+L["Toggle Bags"] = "Afficher les sacs"
+L["Toggle Chat Frame"] = "Activer la fenêtre de discussion"
+L["Toggle Configuration"] = "Afficher la configuration"
+L["Tooltip"] = "Infobulle"
+L["Total CPU:"] = "Charge du CPU :"
+L["Total Memory:"] = "Mémoire totale :"
+L["Total: "] = "Total : "
+L["Trigger"] = "Déclencheur"
+L["Type /hellokitty to revert to old settings."] = "Tapez /hellokitty pour recharger les anciennes configurations"
+L["UI Scale"] = true
+L["Unhittable:"] = "Intouchable :"
+L["Vehicle Seat Frame"] = "Cadre de siège du véhicule"
+L["Vendor / Delete Grays"] = true
+L["Vendored gray items for: %s"] = "Objets gris vendus pour : %s"
+L["Vendoring Grays"] = true
+L["Welcome to ElvUI version %s!"] = "Bienvenue sur la version %s d'ElvUI!"
+L["Wintergrasp"] = true
+L["XP:"] = "XP :"
+L["Yes, Keep Changes!"] = "Oui, garder les changements !"
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"] = true
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"] = true
+L["You are now finished with the installation process. If you are in need of technical support please visit us at https://github.com/ElvUI-WotLK."] = "Vous avez maintenant terminé le processus d'installation. Si vous avez besoin d'un support technique, merci de vous rendre sur https://github.com/ElvUI-WotLK."
+L["You are using CPU Profiling. This causes decreased performance. Do you want to disable it or continue?"] = true
+L["You can access copy chat and chat menu functions by mouse over the top right corner of chat panel and left/right click on the button that will appear."] = "Vous pouvez accéder à une copie du chat et des fonctions du chat en survolant avec votre souris le coin en haut à droite de la fenêtre de discussion. Cliquez ensuite sur le bouton qui apparait."
+L["You can always change fonts and colors of any element of ElvUI from the in-game configuration."] = "Vous pouvez toujours modifier les polices et les couleurs de n'importe quel élément d'Elvui dans la configuration du jeu."
+L["You can now choose what layout you wish to use based on your combat role."] = "Vous pouvez maintenant choisir quelle disposition vous souhaitez utiliser en fonction de votre rôle en combat."
+L["You can see someones average item level of their gear by holding shift and mousing over them. It should appear inside the tooltip."] = "Vous pouvez voir le niveau d'objet moyen de n'importe qui en maintenant la touche MAJ enfoncée puis en passant votre souris sur un joueur. Le score apparaitra dans la bulle d'information."
+L["You can set your keybinds quickly by typing /kb."] = "Vous pouvez assignez rapidement vos raccourcis en tapant /kb."
+L["You can toggle the microbar by using your middle mouse button on the minimap you can also accomplish this by enabling the actual microbar located in the actionbar settings."] = "Vous pouvez afficher la microbarre en utilisant le bouton central de votre souris sur la minicarte. Vous pouvez aussi l'afficher via les réglages des Barres d'actions"
+L["You can use the /resetui command to reset all of your movers. You can also use the command to reset a specific mover, /resetui .\nExample: /resetui Player Frame"] = "Vous pouvez utiliser la commande /resetui pour réinitialiser l'ensemble de vos cadres. Vous pouvez aussi utiliser la commande /resetui pour réinitialiser un cadre spécifique.\nExemple: /resetui Player Frame"
+L["You cannot copy settings from the same unit."] = "Vous ne pouvez pas copier les réglages du même cadre."
+L["You don't have enough money to repair all items."] = true
+L["You don't have enough money to repair."] = "Vous n'avez pas assez d'argent pour réparer votre équipement."
+L["You don't have permission to mark targets."] = "Vous n'avez pas la permission de marquer les cibles."
+L["You have imported settings which may require a UI reload to take effect. Reload now?"] = "Vous avez importé des paramètes qui requièrent un rechargement de l'interface. Recharger maintenant ?"
+L["You must purchase a bank slot first!"] = "Vous devez d'abord acheter un emplacement de banque !"
+L["You still have ElvUI_Config installed. ElvUI_Config has been renamed to ElvUI_OptionsUI, please remove it."] = true
+L["Your items have been repaired for: "] = "Votre équipement a été réparé pour : "
+L["Your items have been repaired using guild bank funds for: "] = "Votre équipement a été réparé avec l'argent de la banque de guilde pour : "
+L["Your profile was successfully recieved by the player."] = "Votre profil a été reçu avec succès par le joueur."
+L["copperabbrev"] = "|cffeda55fc|r"
+L["goldabbrev"] = "|cffffd700g|r"
+L["lvl"] = "niveau"
+L["says"] = "dit"
+L["silverabbrev"] = "|cffc7c7cfs|r"
+L["whispers"] = "chuchote"
+L["yells"] = "crie"
+L["|cFFE30000Lua error recieved. You can view the error message when you exit combat."] = "|cFFE30000Erreur Lua reçue. Vous pouvez voir ce message d'erreur quand vous sortirez de combat."
+
+----------------------------------
+L["RED_ENABLE"] = "|cFFff3333Activer|r"
+L["GREEN_ENABLE"] = "|cFF33ff33Activer|r"
+L["DESC_MOVERCONFIG"] = [=[Cadres déverrouillés. Déplacez-les et cliquez sur Verrouiller une fois terminé.
+
+Options:
+ LeftClick - Toggle Nudge Frame.
+ Clic Droit - Open Config Section.
+ Shift + clic droit - Cacher temporairement.
+ Ctrl + clic droit - Réinitialiser la position par défaut.
+]=]
\ No newline at end of file
diff --git a/ElvUI/Locales/koKR.lua b/ElvUI/Locales/koKR.lua
new file mode 100644
index 0000000..91f1285
--- /dev/null
+++ b/ElvUI/Locales/koKR.lua
@@ -0,0 +1,331 @@
+-- Korean localization file for koKR.
+local E = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "koKR")
+
+L[" |cff00ff00bound to |r"] = " 키로 다음의 행동을 실행합니다: |cff2eb7e4"
+L["%s frame(s) has a conflicting anchor point, please change either the buff or debuff anchor point so they are not attached to each other. Forcing the debuffs to be attached to the main unitframe until fixed."] = "%s 의 위치 기준 프레임이 상충되고 있습니다. 서로가 서로의 위치를 참조하지 않게 버프나 디버프 중 하나의 위치를 바꿔주세요. 수정되기 전까지 강제로 유닛프레임이 기준으로 됩니다. "
+L["%s is attempting to share his filters with you. Would you like to accept the request?"] = "%s 유저가 필터설정을 전송하려 합니다. 받으시겠습니까?"
+L["%s is attempting to share the profile %s with you. Would you like to accept the request?"] = "%s 유저가 ElvUI 설정을 전송하려 합니다. 받으시겠습니까?"
+L["%s: %s tried to call the protected function '%s'."] = "%s: %s 기능이 사용할 수 없는 %s 함수를 사용하려 합니다."
+L["(Hold Shift) Memory Usage"] = "Shift: 메모리 사용량"
+L["(Modifer Click) Collect Garbage"] = true
+L["A raid marker feature is available by pressing Escape -> Keybinds scroll to the bottom under ElvUI and setting a keybind for the raid marker."] = "단축키 설정의 맨 아래에 있는 ElvUI 부분에서 |cff2eb7e4[Raid Marker]|r 기능을 사용하면 대상에게 징표를 간단히 찍을 수 있습니다."
+L["A setting you have changed will change an option for this character only. This setting that you have changed will be uneffected by changing user profiles. Changing this setting requires that you reload your User Interface."] = "이 설정은 캐릭터별로 따로 저장되므로|n프로필에 영향을 주지도, 받지도 않습니다.|n|n설정 적용을 위해 리로드 하시겠습니까?"
+L["ABOVE_THREAT_FORMAT"] = "%s: %.0f%% [%.0f%% 정도 |cff%02x%02x%02x%s|r보다 많음]"
+L["AFK"] = "자리 비움"
+L["Accepting this will reset the UnitFrame settings for %s. Are you sure?"] = "수락하시면 %s의 설정이 초기화됩니다. 정말로 하시겠습니까?"
+L["Accepting this will reset your Filter Priority lists for all auras on NamePlates. Are you sure?"] = "수락하시면 이름표에 적용된 모든 필터 목록이 초기화 됩니다. 정말로 하시겠습니까?"
+L["Accepting this will reset your Filter Priority lists for all auras on UnitFrames. Are you sure?"] = "수락하시면 유닛프레임에 적용된 모든 필터 목록이 초기화 됩니다. 정말로 하시겠습니까?"
+L["Adjust the UI Scale to fit your screen, press the autoscale button to set the UI Scale automatically."] = true
+L["All keybindings cleared for |cff00ff00%s|r."] = "|cff00ff00%s|r 버튼에 설정된 모든 단축키 설정이 해제되었습니다."
+L["Already Running.. Bailing Out!"] = "이미 실행중입니다. 잠시만 기다려 주세요."
+L["Are you sure you want to apply this font to all ElvUI elements?"] = "정말로 이 글씨체를 ElvUI의 모든 구성요소에 적용하시겠습니까?"
+L["Are you sure you want to disband the group?"] = "현재 그룹을 해산하시겠습니까?"
+L["Are you sure you want to reset all the settings on this profile?"] = "현재 사용중인 프로필을 초기화 하시겠습니까?"
+L["Are you sure you want to reset every mover back to it's default position?"] = "모든 프레임을 기본 위치로 초기화 하시겠습니까?"
+L["Arena Frames"] = "투기장 프레임"
+L["Aura Bars & Icons"] = true
+L["Auras Set"] = true
+L["Auras"] = "오라 설정"
+L["Auto Scale"] = "UI크기 자동조절"
+L["Avoidance Breakdown"] = "방어율 목록"
+L["BG"] = true
+L["BGL"] = true
+L["BNet Frame"] = "배틀넷 알림"
+L["Bag Mover (Grow Down)"] = "가방 조정자(아래로 성장)"
+L["Bag Mover (Grow Up)"] = "가방 조정자(위로 성장)"
+L["Bag Mover"] = "가방 조정자"
+L["Bags"] = "가방"
+L["Bank Mover (Grow Down)"] = "은행 조정자(아래로 성장)"
+L["Bank Mover (Grow Up)"] = "은행 조정자(위로 성장)'"
+L["Bank"] = "은행"
+L["Bar "] = "바 "
+L["Bars"] = "바"
+L["Battleground datatexts temporarily hidden, to show type /bgstats or right click the 'C' icon near the minimap."] = "전장전용 정보문자를 일시적으로 표시하지 않습니다. 다시 보고 싶으면 |cffceff00/bgstats|r 나 미니맵에 있는 C 버튼을 우클릭하세요."
+L["Battleground datatexts will now show again if you are inside a battleground."] = "전장전용 정보문자를 다시 표시합니다."
+L["Binding"] = " "
+L["Binds Discarded"] = "방금 한 단축키 지정 작업을 저장하지 않고 취소했습니다."
+L["Binds Saved"] = "단축키가 저장되었습니다."
+L["BoE"] = true
+L["BoU"] = true
+L["Boss Frames"] = "보스 프레임"
+L["Buffs"] = "강화효과"
+L["CVars Set"] = "CVars 설정"
+L["CVars"] = "게임 인터페이스 설정(CVars)"
+L["Calendar"] = "달력"
+L["Can't Roll"] = "주사위를 굴릴 수 없습니다."
+L["Can't buy anymore slots!"] = "더 이상 가방 칸을 늘릴 수 없습니다."
+L["Caster DPS"] = "원거리 딜러"
+L["Character: "] = "캐릭터:"
+L["Chat Set"] = "대화창 설정"
+L["Chat"] = "대화창"
+L["Choose a theme layout you wish to use for your initial setup."] = "UI의 전체적인 분위기를 선택하세요."
+L["Classbar"] = "직업바"
+L["Classic"] = "클래식"
+L["Combat Time"] = "전투 시간"
+L["Combobar"] = "연계점수 바"
+L["Config Mode:"] = "표시할 프레임 계열:"
+L["Confused.. Try Again!"] = "작업에 혼선이 있었습니다. 다시 시도해 주세요."
+L["Continue"] = true
+L["Coords"] = "좌표"
+L["Count"] = "갯수"
+L["DND"] = "다른 용무 중"
+L["DPS"] = "DPS"
+L["Dark"] = "어두운 느낌"
+L["Data From: %s"] = "%s 유저에게서 데이터 받는중..."
+L["Data To: %s"] = true
+L["Dead"] = "죽음"
+L["Debuffs"] = "약화효과"
+L["Deficit:"] = "손해:"
+L["Delete gray items?"] = "잡템을 삭제하시겠습니까?"
+L["Detected that your ElvUI OptionsUI addon is out of date. This may be a result of your Tukui Client being out of date. Please visit our download page and update your Tukui Client, then reinstall ElvUI. Not having your ElvUI OptionsUI addon up to date will result in missing options."] = "ElvUI_OptionsUI 가 오래된 버전입니다. Tukui Client 프로그램을 쓰고 있으면 클라이언트를 업데이트하고 ElvUI를 재설치하세요."
+L["Disable Warning"] = "비활성화 경고"
+L["Disable"] = "비활성화"
+L["Disband Group"] = "그룹 해산"
+L["Discard"] = "작업 취소"
+L["Discord"] = true
+L["Do you enjoy the new ElvUI?"] = "만우절 기능이었습니다! 이대로 쓰실래요?"
+L["Do you swear not to post in technical support about something not working without first disabling the addon/module combination first?"] = "두 애드온을 병행하여 생기는 문제를 스스로 감수하며 관련 질문글을 올리지 마세요."
+L["Earned:"] = "수입:"
+L["ElvUI Installation"] = "ElvUI 설치"
+L["ElvUI Plugin Installation"] = "ElvUI 플러그인 설치"
+L["ElvUI has a dual spec feature which allows you to load different profiles based on your current spec on the fly. You can enable this from the profiles tab."] = "각 전문화별로 ElvUI 설정을 따로 지정할 수 있습니다. 설정의 프로필 항목에 |cff2eb7e4[이중 프로필 사용]|r 기능을 확인하세요."
+L["ElvUI is five or more revisions out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "현재 사용하는 ElvUI가 5버전 이상 뒤쳐진 버전입니다. https://github.com/BanditTech/ElvUI-Ascension 에서 새 버전을 다운로드 받으세요"
+L["ElvUI is out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI가 오래된 버전입니다. https://github.com/BanditTech/ElvUI-Ascension 에서 새 버전을 다운로드 받으세요."
+L["ElvUI needs to perform database optimizations please be patient."] = "ElvUI의 데이터베이스를 조정할 필요가 있습니다. 잠시 기다려주세요."
+L["ElvUI was updated while the game is still running. Please relaunch the game, as this is required for the files to be properly updated."] = true
+L["Empty Slot"] = "빈 칸"
+L["Enable"] = "사용"
+L["Error resetting UnitFrame."] = "유닛프레임 초기화 오류"
+L["Experience Bar"] = "경험치 바"
+L["Experience"] = "경험치"
+L["Export Now"] = "지금 내보내기"
+L["Farm Mode"] = true
+L["Filter download complete from %s, would you like to apply changes now?"] = "%s 유저에게서 필터 설정 다운로드가 완료되었습니다. 변경사항을 적용할까요?"
+L["Finished"] = "마침"
+L["Fishy Loot"] = "낚시 전리품"
+L["Focus Castbar"] = "주시대상 시전바"
+L["Focus Frame"] = "주시대상 프레임"
+L["FocusTarget Frame"] = "주시대상의 대상 프레임"
+L["For technical support visit us at https://github.com/ElvUI-WotLK."] = "궁금한 사항이나 기술지원은 |cff2eb7e4github.com/ElvUI-WotLK|r에서 해결하세요."
+L["Frame"] = "유닛프레임"
+L["Friends List"] = "친구 목록"
+L["G"] = "길드"
+L["GM Ticket Frame"] = "GM요청 번호표"
+L["General"] = "일반"
+L["Ghost"] = "유령"
+L["Gold"] = "골드"
+L["Grid Size:"] = "격자 크기 :"
+L["HP"] = "주문력"
+L["HPS"] = "HPS"
+L["Healer"] = "힐러"
+L["Hit"] = true
+L["Hold Control + Right Click:"] = "Shift 우클릭:"
+L["Hold Shift + Drag:"] = "Shift 드래그:"
+L["Hold Shift + Right Click:"] = "쉬프트+우클릭"
+L["Home Latency:"] = "지연 시간:"
+L["Hover your mouse over any actionbutton or spellbook button to bind it. Press the ESC key to clear the current actionbutton's keybinding."] = true
+L["I Swear"] = "알겠습니다."
+L["INCOMPATIBLE_ADDON"] = "%s 애드온의 기능이 ElvUI의 %s 모듈과 상충됩니다. 그 애드온을 쓰지 않거나 ElvUI의 기능을 사용해제하세요."
+L["Icons Only"] = "아이콘만 표시"
+L["If you accidently remove a chat frame you can always go the in-game configuration menu, press install, go to the chat portion and reset them."] = "ElvUI 에서 지원하는 대부분의 기능은 |cff2eb7e4/ec|r 에서 조정이 가능합니다. 하고 싶은 조절 기능이 없다면 직접 lua수정으로 고쳐야 합니다."
+L["If you are experiencing issues with ElvUI try disabling all your addons except ElvUI, remember ElvUI is a full UI replacement addon, you cannot run two addons that do the same thing."] = "ElvUI에서 지원하는 기능과 겹치는 다른 애드온을 쓰고 싶으면 ElvUI 설정에서 해당 기능을 사용 체크해제 해야합니다. (예: Bartender, Dominos)"
+L["If you have an icon or aurabar that you don't want to display simply hold down shift and right click the icon for it to disapear."] = true
+L["Import Now"] = "지금 가져오기"
+L["Importance: |cff07D400High|r"] = "중요도: |cff07D400높음|r"
+L["Importance: |cffD3CF00Medium|r"] = "중요도: |cffD3CF00보통|r"
+L["Importance: |cffFF0000Low|r"] = "중요도 : |cffFF0000낮음|r"
+L["In Progress"] = "진행 중"
+L["Installation Complete"] = "설치 완료"
+L["Invalid Target"] = "잘못된 대상"
+L["Item Level:"] = true
+L["KEY_ALT"] = "A"
+L["KEY_CTRL"] = "C"
+L["KEY_DELETE"] = "Del"
+L["KEY_HOME"] = "Hm"
+L["KEY_INSERT"] = "Ins"
+L["KEY_MOUSEBUTTON"] = "M"
+L["KEY_MOUSEWHEELDOWN"] = "W▼"
+L["KEY_MOUSEWHEELUP"] = "W▲"
+L["KEY_NUMPAD"] = "N"
+L["KEY_PAGEDOWN"] = "P▼"
+L["KEY_PAGEUP"] = "P▲"
+L["KEY_SHIFT"] = "S"
+L["KEY_SPACE"] = "Spc"
+L["Key"] = "단축키"
+L["LOGIN_MSG"] = "Welcome to %sElvUI|r version %s%s|r, type /ec to access the in-game configuration menu. If you are in need of technical support you can visit us at https://github.com/BanditTech/ElvUI-Ascension or join our Discord: https://discord.gg/UXSc7nt"
+L["Layout Set"] = "레이아웃 설정"
+L["Layout"] = "레이아웃"
+L["Left Chat"] = "좌측 패널"
+L["Left Click:"] = "왼 클릭 :"
+L["List of installations in queue:"] = "설치 대기열 목록"
+L["Lock"] = "잠금"
+L["Loot / Alert Frames"] = "획득/알림 창"
+L["Loot Frame"] = "전리품 프레임"
+L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"] = "데이터를 받는 중 혼선이 생겼습니다. 다시 시도해주세요."
+L["MA Frames"] = "지원공격 전담 프레임"
+L["MT Frames"] = "방어전담 프레임"
+L["Micro Bar"] = "메뉴모음 바"
+L["Minimap"] = "미니맵"
+L["MirrorTimer"] = "미러 타이머"
+L["Miss Chance"] = true
+L["Mitigation By Level: "] = "레벨별 데미지 경감률"
+L["Movers"] = true
+L["Must be in group with the player if he isn't on the same server as you."] = "대상으로 잡은 유저가 타 서버 유저라면 반드시 그 유저와 파티를 맻고 있어야 합니다."
+L["No Guild"] = "길드 없음"
+L["No bindings set."] = "설정한 단축키가 없습니다."
+L["No gray items to delete."] = "잡동사니가 없습니다."
+L["No, Revert Changes!"] = "예전으로 돌려주세요"
+L["Nudge"] = "미세조정"
+L["O"] = "관리자"
+L["Objective Frame"] = "퀘스트 프레임"
+L["Offline"] = "오프라인"
+L["Oh lord, you have got ElvUI and Tukui both enabled at the same time. Select an addon to disable."] = "ElvUI 와 TukUI 를 동시에 사용하려 하고 있습니다. 하나만 선택해 주세요."
+L["On screen positions for different elements."] = true
+L["One or more of the changes you have made require a ReloadUI."] = "변경 사항을 적용하려면 애드온을 리로드 해야합니다."
+L["One or more of the changes you have made will effect all characters using this addon. You will have to reload the user interface to see the changes you have made."] = "이 설정은 모든 캐릭터에게 동일하게 적용됩니다.|n|n설정 적용을 위해 리로드 하시겠습니까?"
+L["P"] = "파티"
+L["PL"] = "파장"
+L["Party Frames"] = "파티 프레임"
+L["Pending"] = "미결"
+L["Pet Bar"] = "소환수 바"
+L["Pet Castbar"] = "소환수 시전바"
+L["Pet Frame"] = "소환수 프레임"
+L["PetTarget Frame"] = "소환수 대상 프레임"
+L["Player Buffs"] = "플레이어 버프"
+L["Player Castbar"] = "플레이어 시전바"
+L["Player Debuffs"] = "플레이어 디버프"
+L["Player Frame"] = "플레이어 프레임"
+L["Player Powerbar"] = "플레이어 자원바"
+L["Please click the button below so you can setup variables and ReloadUI."] = "아래 버튼을 누르면 설치를 마무리하고 UI를 재시작합니다."
+L["Please click the button below to setup your CVars."] = "ElvUI의 게임 인터페이스 설정을 적용하려면 아래 버튼을 클릭하세요."
+L["Please press the continue button to go onto the next step."] = "|cff2eb7e4[계속]|r 버튼으로 설치를 진행하세요."
+L["Preview Changes"] = true
+L["Preview"] = true
+L["Profile download complete from %s, but the profile %s already exists. Change the name or else it will overwrite the existing profile."] = "%s 유저에게서 ElvUI 설정 다운로드가 완료되었습니다. 하지만 건네받은 프로필 이름이 이미 존재합니다. 프로필이름을 바꾸지 않으면 기존의 것에 덮어씌웁니다."
+L["Profile download complete from %s, would you like to load the profile %s now?"] = "%s 유저에게서 ElvUI 설정 다운로드가 완료되었습니다. 건네받은 설정을 지금 불러올까요?"
+L["Profile request sent. Waiting for response from player."] = "상대에게서 전송여부를 확인받고 있습니다."
+L["Profit:"] = "이익:"
+L["Purchase Bags"] = "가방 슬롯 구입"
+L["PvP"] = true
+L["R"] = "공대"
+L["RL"] = "공장"
+L["RW"] = "경보"
+L["Raid Frames"] = "레이드 프레임"
+L["Raid Menu"] = "공대 도구"
+L["Raid Pet Frames"] = "레이드 소환수 프레임"
+L["Raid-40 Frames"] = "레이드 프레임(40인)"
+L["Reload UI"] = true
+L["Remaining:"] = "다음 레벨까지: "
+L["Remove Bar %d Action Page"] = "Blizzard %d번 행동단축바 숨기기"
+L["Reputation Bar"] = "평판 바"
+L["Request was denied by user."] = "상대방이 전송을 거절했습니다."
+L["Reset Counters: Hold Shift + Left Click"] = "통계 초기화: 쉬프트+우클릭"
+L["Reset Data: Hold Shift + Right Click"] = "자료 초기화: 쉬프트+우클릭"
+L["Reset Position"] = "위치 초기화"
+L["Rested:"] = "휴식 경험치:"
+L["Right Chat"] = "우측 패널"
+L["Right Click:"] = true
+L["SP"] = "주문력"
+L["Save"] = "저장"
+L["Saved Dungeon(s)"] = "귀속된 던전"
+L["Saved Raid(s)"] = "귀속된 던전"
+L["Select the type of aura system you want to use with ElvUI's unitframes. Set to Aura Bar & Icons to use both aura bars and icons, set to icons only to only see icons."] = true
+L["Server: "] = "서버:"
+L["Session:"] = "현재 접속:"
+L["Setup CVars"] = "인터페이스 설정 적용"
+L["Setup Chat"] = "대화창 설치"
+L["Show BG Texts"] = true
+L["Skip Process"] = "건너뛰기"
+L["Sort Bags"] = "가방 정렬"
+L["Spell/Heal Power"] = "주문력"
+L["Spent:"] = "지출:"
+L["Stance Bar"] = "태세 바"
+L["Stats For:"] = "점수:"
+L["Steps"] = "단계"
+L["Sticky Frames"] = "자석"
+L["System"] = "시스템"
+L["Talent Specialization:"] = "전문화 획득 전문화 변경:"
+L["Tank / Physical DPS"] = true
+L["Target Castbar"] = "대상 시전바"
+L["Target Frame"] = "대상 프레임"
+L["Target Powerbar"] = "대상 자원바"
+L["TargetTarget Frame"] = "대상의대상 프레임"
+L["TargetTargetTarget Frame"] = "대상의대상의대상 프레임"
+L["Targeted By:"] = "선택됨:"
+L["Temporary Move"] = "임시 이동"
+L["The UI Scale has been changed, if you would like to preview the change press the preview button. It is recommended that you reload your User Interface for the best appearance."] = true
+L["The chat windows function the same as Blizzard standard chat windows, you can right click the tabs and drag them around, rename, etc. Please click the button below to setup your chat windows."] = "보편적인 설정을 적용할 뿐이므로, 마음대로 채널표시나 색상을 변경할 수 있습니다.|n아래 버튼을 클릭하면 채팅창 설정을 적용합니다."
+L["The focus unit can be set by typing /focus when you are targeting the unit you want to focus. It is recommended you make a macro to do this."] = "ElvUI의 특정 기능만 따로 독립애드온으로 분리하는 것은 불가능합니다."
+L["The in-game configuration menu can be accessed by typing the /ec command or by clicking the 'C' button on the minimap. Press the button below if you wish to skip the installation process."] = "게임 내 설정창은 채팅창에 /ec를 입력하시거나 미니맵 옆의 C버튼을 클릭하면 열립니다. 그냥 사용하고자 한다면 아래의 |cff2eb7e4[건너뛰기]|r 버튼을 누르세요."
+L["The profile you tried to import already exists. Choose a new name or accept to overwrite the existing profile."] = "불러오려는 프로필이 이미 존재합니다. 새로운 이름을 지정하시거나 기존 프로필에 덮어쓸지를 선택하십시오."
+L["The spell '%s' has been added to the Blacklist unitframe aura filter."] = "%s 주문이 차단 목록에 등록되었습니다."
+L["Theme Set"] = "테마 적용"
+L["Theme Setup"] = "테마 설정"
+L["This install process will help you learn some of the features in ElvUI has to offer and also prepare your user interface for usage."] = "이 설치과정을 통해 ElvUI를 좀 더 자신에게 맞게 설정하고|n몇가지 기능에 대해 알 수 있습니다."
+L["This part of the installation process sets up your World of Warcraft default options it is recommended you should do this step for everything to behave properly."] = "WoW의 기본 인터페이스 설정을 ElvUI에 적합하게 변경합니다. 애드온 사용에 있어 유용하니 적용할 것을 추천합니다."
+L["This part of the installation process sets up your chat windows names, positions and colors."] = "채팅창 설정을 변경합니다. 간단한 채널설정, 색상설정 등이 포함되어 있습니다.|n자신만의 채널 설정, 색상 등을 유지하고 싶으면 설치하지 마세요."
+L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."] = true
+L["This will change the layout of your unitframes and actionbars."] = "역할에 따라서 유닛프레임과 행동단축바의 레이아웃이 알맞게 바뀝니다."
+L["To move abilities on the actionbars by default hold shift + drag. You can change the modifier key from the actionbar options menu."] = "기본적으로 단축바에서 스킬을 뺄려면 |cff2eb7e4Shift 키를 누른 상태에서 드래그|r해야 합니다. 수정키는 /ec -> 행동단축바 항목에서 바꿀 수 있습니다."
+L["To setup which channels appear in which chat frame, right click the chat tab and go to settings."] = "채팅창에 표시할 채널은 채팅탭을 우클릭하면 뜨는 메뉴의 설정에서 변경할 수 있습니다."
+L["Toggle Bags"] = "가방슬롯 보기"
+L["Toggle Chat Frame"] = "패널 표시 전환"
+L["Toggle Configuration"] = "ElvUI 설정창 열기"
+L["Tooltip"] = "툴팁"
+L["Total CPU:"] = "전체 CPU 사용량:"
+L["Total Memory:"] = "전체 메모리:"
+L["Total: "] = "합계:"
+L["Trigger"] = "묶음을 펼치고 각 주문에 지정하세요."
+L["Type /hellokitty to revert to old settings."] = "/hellokitty 를 입력해서 예전 세팅으로 돌릴 수 있습니다."
+L["UI Scale"] = true
+L["Unhittable:"] = "100% 방어행동까지"
+L["Vehicle Seat Frame"] = "차량 좌석 프레임"
+L["Vendor / Delete Grays"] = "잡템 자동판매/삭제"
+L["Vendored gray items for: %s"] = "모든 잡동사니를 팔았습니다: %s"
+L["Vendoring Grays"] = true
+L["Welcome to ElvUI version %s!"] = "ElvUI 버전 %s에 오신 것을 환영합니다!"
+L["Wintergrasp"] = true
+L["XP:"] = "경험치:"
+L["Yes, Keep Changes!"] = "네! 이대로 할래요!"
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"] = true
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"] = true
+L["You are now finished with the installation process. If you are in need of technical support please visit us at https://github.com/ElvUI-WotLK."] = "설치 과정이 끝났습니다.|n궁금한 점 해결이나 기술지원이 필요하면 https://github.com/ElvUI-WotLK 를 방문하세요."
+L["You are using CPU Profiling. This causes decreased performance. Do you want to disable it or continue?"] = true
+L["You can access copy chat and chat menu functions by mouse over the top right corner of chat panel and left/right click on the button that will appear."] = "채팅창 우측상단의 문서 아이콘을 클릭하면 대화 내역을 복사할 수 있습니다. 우클릭하면 채팅에 관련된 메뉴가 나옵니다."
+L["You can always change fonts and colors of any element of ElvUI from the in-game configuration."] = "ElvUI에서 표시하는 폰트나 색상은 설정에서 언제든지 바꿀 수 있습니다."
+L["You can now choose what layout you wish to use based on your combat role."] = "게임 안에서 주로 플레이하는 전문화 역할을 선택하세요."
+L["You can see someones average item level of their gear by holding shift and mousing over them. It should appear inside the tooltip."] = "/ec -> 툴팁 항목에서 |cff2eb7e4[특성/아이템레벨 표시]|r 기능을 체크하고 Shift를 누른 상태로 마우스를 대면 그 유저의 템렙과 특성을 툴팁에 표시합니다."
+L["You can set your keybinds quickly by typing /kb."] = "|cff2eb7e4/kb|r 를 입력하면 간편하게 단축키를 설정할 수 있는 기능이 실행됩니다."
+L["You can toggle the microbar by using your middle mouse button on the minimap you can also accomplish this by enabling the actual microbar located in the actionbar settings."] = "미니맵을 휠버튼클릭 하거나 행동단축바 설정으로 각종 메뉴버튼을 볼 수 있습니다."
+L["You can use the /resetui command to reset all of your movers. You can also use the command to reset a specific mover, /resetui .\nExample: /resetui Player Frame"] = "|cff2eb7e4/resetui|r 입력으로 움직였던 모든 프레임의 위치를 초기화할 수 있습니다. |cff2eb7e4 /resetui 프레임이름|r 으로 특정 프레임만 초기화도 가능합니다."
+L["You cannot copy settings from the same unit."] = "같은 유닛은 복사할 수 없습니다."
+L["You don't have enough money to repair all items."] = true
+L["You don't have enough money to repair."] = "수리 비용이 부족합니다."
+L["You don't have permission to mark targets."] = "레이드 아이콘을 지정할 권한이 없습니다."
+L["You have imported settings which may require a UI reload to take effect. Reload now?"] = "적용을 위해 UI 다시불러오기가 필요할 수 있는 설정을 가져왔습니다. 지금 UI를 재시작하시겠습니까?"
+L["You must purchase a bank slot first!"] = "우선 은행가방 칸을 구입해야됩니다!"
+L["You still have ElvUI_Config installed. ElvUI_Config has been renamed to ElvUI_OptionsUI, please remove it."] = true
+L["Your items have been repaired for: "] = "자동으로 수리하고 비용을 지불했습니다: "
+L["Your items have been repaired using guild bank funds for: "] = "길드자금으로 수리하고 비용을 지불했습니다: "
+L["Your profile was successfully recieved by the player."] = "상대에게 데이터를 성공적으로 전송했습니다."
+L["copperabbrev"] = "|TInterface\\MoneyFrame\\UI-MoneyIcons:0:0:1:0:64:16:33:48:1:16|t"
+L["goldabbrev"] = "|TInterface\\MoneyFrame\\UI-MoneyIcons:0:0:1:0:64:16:1:16:1:16|t"
+L["lvl"] = "레벨"
+L["says"] = "일반"
+L["silverabbrev"] = "|TInterface\\MoneyFrame\\UI-MoneyIcons:0:0:1:0:64:16:17:32:1:16|t"
+L["whispers"] = "귓"
+L["yells"] = "외침"
+L["|cFFE30000Lua error recieved. You can view the error message when you exit combat."] = "Lua 에러가 발생하였습니다. 전투가 끝난 후에 내역을 표시하겠습니다."
+
+----------------------------------
+L["RED_ENABLE"] = "|cFFff3333사용|r"
+L["GREEN_ENABLE"] = "|cFF33ff33사용|r"
+L["DESC_MOVERCONFIG"] = [=[프레임을 드래그로 원하는 위치로 이동시키세요.|n[잠금] 버튼을 누르면 이동모드가 종료됩니다.
+
+선택사항:
+ LeftClick - Toggle Nudge Frame.
+ 우클릭 - Open Config Section.
+ Shift + 우클릭 - 조정자를 일시적으로 숨깁니다.
+ Ctrl + 우클릭 - 조정자의 위치를 기본값으로 초기화합니다.
+]=]
\ No newline at end of file
diff --git a/ElvUI/Locales/ptBR.lua b/ElvUI/Locales/ptBR.lua
new file mode 100644
index 0000000..bb12487
--- /dev/null
+++ b/ElvUI/Locales/ptBR.lua
@@ -0,0 +1,331 @@
+-- Portuguese localization file for ptBR.
+local E = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "ptBR")
+
+L[" |cff00ff00bound to |r"] = " |cff00ff00Ligado a |r"
+L["%s frame(s) has a conflicting anchor point, please change either the buff or debuff anchor point so they are not attached to each other. Forcing the debuffs to be attached to the main unitframe until fixed."] = "%s quadro(s) tem um ponto de fixação em conflito, por favor mude o ponto de fixação do quadro de bônus ou de penalidades para que eles não fiquem ligados uns aos outros. Forçando as penalidades a ficarem anexadas ao quadro principal até que sejam consertados."
+L["%s is attempting to share his filters with you. Would you like to accept the request?"] = "%s está tentando compartilhar os filtros dele com você. Gostaria de aceitar o pedido?"
+L["%s is attempting to share the profile %s with you. Would you like to accept the request?"] = "%s está tentando compartilhar o perfil %s com você. Gostaria de aceitar o pedido?"
+L["%s: %s tried to call the protected function '%s'."] = "%s: %s tentou chamar a função protegida '%s'."
+L["(Hold Shift) Memory Usage"] = "(Segurar Shift) Memória em Uso"
+L["(Modifer Click) Collect Garbage"] = true
+L["A raid marker feature is available by pressing Escape -> Keybinds scroll to the bottom under ElvUI and setting a keybind for the raid marker."] = "A opção Marcas de Raide está disponivel pressionando Escape -> Teclas de Atalho, rolando tudo para o fundo debaixo de ElvUI e definindo uma tecla de atalho para o Raid Marker."
+L["A setting you have changed will change an option for this character only. This setting that you have changed will be uneffected by changing user profiles. Changing this setting requires that you reload your User Interface."] = "A definição que você alterou afetará apenas este personagem. Esta definição que você alterou não será afetada por mudanças de perfil. Alterar esta difinição requer que você recarregue a sua interface."
+L["ABOVE_THREAT_FORMAT"] = "%s: %.0f%% [%.0f%% above |cff%02x%02x%02x%s|r]"
+L["AFK"] = "LDT"
+L["Accepting this will reset the UnitFrame settings for %s. Are you sure?"] = true
+L["Accepting this will reset your Filter Priority lists for all auras on NamePlates. Are you sure?"] = true
+L["Accepting this will reset your Filter Priority lists for all auras on UnitFrames. Are you sure?"] = true
+L["Adjust the UI Scale to fit your screen, press the autoscale button to set the UI Scale automatically."] = true
+L["All keybindings cleared for |cff00ff00%s|r."] = "Todos os atalhos livres para"
+L["Already Running.. Bailing Out!"] = "Já está executando... Cancelando a ordenação!"
+L["Are you sure you want to apply this font to all ElvUI elements?"] = true
+L["Are you sure you want to disband the group?"] = "Tem a certeza de que quer dissolver o grupo?"
+L["Are you sure you want to reset all the settings on this profile?"] = "Tem certeza que quer redefinir todas as configurações desse perfil?"
+L["Are you sure you want to reset every mover back to it's default position?"] = "Tem a certeza de que deseja restaurar todos os movedores de volta para a sua posição padrão?"
+L["Arena Frames"] = "Quadros de Arenas"
+L["Aura Bars & Icons"] = true
+L["Auras Set"] = true
+L["Auras"] = true
+L["Auto Scale"] = "Dimensionar automaticamente"
+L["Avoidance Breakdown"] = "Separação de Anulação"
+L["BG"] = true
+L["BGL"] = true
+L["BNet Frame"] = "Quadro do Bnet"
+L["Bag Mover (Grow Down)"] = true
+L["Bag Mover (Grow Up)"] = true
+L["Bag Mover"] = true
+L["Bags"] = "Bolsas"
+L["Bank Mover (Grow Down)"] = true
+L["Bank Mover (Grow Up)"] = true
+L["Bank"] = true
+L["Bar "] = "Barra "
+L["Bars"] = "Barras"
+L["Battleground datatexts temporarily hidden, to show type /bgstats or right click the 'C' icon near the minimap."] = "Os textos Informativos dos Campos de Batalha estão temporáriamente ocultos, para serem mostrados digite /bgstats ou clique direito no ícone 'C' perto do minimapa."
+L["Battleground datatexts will now show again if you are inside a battleground."] = "Os textos Informativos irão agora ser mostrados se estiver dentro de um Campo de Batalha."
+L["Binding"] = "Ligações"
+L["Binds Discarded"] = "Ligações Descartadas"
+L["Binds Saved"] = "Ligações Salvas"
+L["BoE"] = true
+L["BoU"] = true
+L["Boss Frames"] = "Quadros dos Chefes"
+L["Buffs"] = "Bônus"
+L["CVars Set"] = "CVars configuradas"
+L["CVars"] = "CVars"
+L["Calendar"] = "Calendário"
+L["Can't Roll"] = "Não pode rolar"
+L["Can't buy anymore slots!"] = "Não é possível comprar mais espaços!"
+L["Caster DPS"] = "DPS Lançador"
+L["Character: "] = "Personagem: "
+L["Chat Set"] = "Bate-Papo configurado"
+L["Chat"] = "Bate-papo"
+L["Choose a theme layout you wish to use for your initial setup."] = "Escolha o tema de layout que deseje usar inicialmente."
+L["Classbar"] = "Barra da Classe"
+L["Classic"] = "Clássico"
+L["Combat Time"] = true
+L["Combobar"] = true
+L["Config Mode:"] = "Modo de configuração"
+L["Confused.. Try Again!"] = "Confuso... Tente novamente!"
+L["Continue"] = true
+L["Coords"] = true
+L["Count"] = "Contar"
+L["DND"] = "NP"
+L["DPS"] = "DPS"
+L["Dark"] = "Escuro"
+L["Data From: %s"] = "Dados De: %s"
+L["Data To: %s"] = true
+L["Dead"] = true
+L["Debuffs"] = "Penalidades"
+L["Deficit:"] = "Défice:"
+L["Delete gray items?"] = true
+L["Detected that your ElvUI OptionsUI addon is out of date. This may be a result of your Tukui Client being out of date. Please visit our download page and update your Tukui Client, then reinstall ElvUI. Not having your ElvUI OptionsUI addon up to date will result in missing options."] = true
+L["Disable Warning"] = "Desativar Aviso"
+L["Disable"] = "Desativar"
+L["Disband Group"] = "Dissolver Grupo"
+L["Discard"] = "Descartar"
+L["Discord"] = true
+L["Do you enjoy the new ElvUI?"] = true
+L["Do you swear not to post in technical support about something not working without first disabling the addon/module combination first?"] = "Você jura não postar no suporte técnico sobre alguma coisa não funcionando sem antes desabilitar a combinação addon/módulo?"
+L["Earned:"] = "Ganho:"
+L["ElvUI Installation"] = "Instalação do ElvUI"
+L["ElvUI Plugin Installation"] = true
+L["ElvUI has a dual spec feature which allows you to load different profiles based on your current spec on the fly. You can enable this from the profiles tab."] = "A ElvUI contém o modo de duas especializações, que permite que carregue perfis diferentes baseado na sua especialização atual rapidamente. Você pode ativar esta opção na guia Perfis."
+L["ElvUI is five or more revisions out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = true
+L["ElvUI is out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = true
+L["ElvUI needs to perform database optimizations please be patient."] = true
+L["ElvUI was updated while the game is still running. Please relaunch the game, as this is required for the files to be properly updated."] = true
+L["Empty Slot"] = true
+L["Enable"] = "Ativar"
+L["Error resetting UnitFrame."] = true
+L["Experience Bar"] = "Barra de Experiência"
+L["Experience"] = "Experiência"
+L["Export Now"] = true
+L["Farm Mode"] = true
+L["Filter download complete from %s, would you like to apply changes now?"] = "Baixa de filtros de %s completada, gostaria de aplicar as alterações agora?"
+L["Finished"] = "Terminado"
+L["Fishy Loot"] = "Saque de Peixes"
+L["Focus Castbar"] = "Barra de Lançamento do Foco"
+L["Focus Frame"] = "Quadro do Foco"
+L["FocusTarget Frame"] = "Quadro do Alvo do Foco"
+L["For technical support visit us at https://github.com/ElvUI-WotLK."] = "Para suporte técnico visite-nos no site https://github.com/ElvUI-WotLK."
+L["For technical support visit us at https://github.com/ElvUI-WotLK."] = true
+L["Frame"] = "Quadro"
+L["Friends List"] = "Lista de Amigos"
+L["G"] = "G"
+L["GM Ticket Frame"] = "Quadro de Consulta com GM"
+L["General"] = "Geral"
+L["Ghost"] = "Fantasma"
+L["Gold"] = true
+L["Grid Size:"] = "Tamanho da Grade"
+L["HP"] = "PV"
+L["HPS"] = "PVS"
+L["Healer"] = "Curandeiro"
+L["Hit"] = true
+L["Hold Control + Right Click:"] = "Segurar Control + Clique Direito:"
+L["Hold Shift + Drag:"] = "Segurar Shift + Arrastar:"
+L["Hold Shift + Right Click:"] = true
+L["Home Latency:"] = "Latência de Casa:"
+L["Hover your mouse over any actionbutton or spellbook button to bind it. Press the ESC key to clear the current actionbutton's keybinding."] = true
+L["I Swear"] = "Eu Juro"
+L["INCOMPATIBLE_ADDON"] = "The addon %s is not compatible with ElvUI's %s module. Please select either the addon or the ElvUI module to disable."
+L["Icons Only"] = "Apenas Ícones"
+L["If you accidently remove a chat frame you can always go the in-game configuration menu, press install, go to the chat portion and reset them."] = "Se acidentalmente remover um quadro de conversação você pode sempre ir ao menu de configuração em jogo, pressionar instalar, ir até a etapa de bate-papo e os restaurar."
+L["If you are experiencing issues with ElvUI try disabling all your addons except ElvUI, remember ElvUI is a full UI replacement addon, you cannot run two addons that do the same thing."] = "Se estiver a ter problemas com a ElvUI tente desativar todos os addons exceto a ElvUI, lembre-se que a ElvUI é um addon de substituição de interface completo, e não se consegue executar dois addons que fazem a mesma coisa."
+L["If you have an icon or aurabar that you don't want to display simply hold down shift and right click the icon for it to disapear."] = true
+L["Import Now"] = true
+L["Importance: |cff07D400High|r"] = "Importância: |cff07D400Alta|r"
+L["Importance: |cffD3CF00Medium|r"] = "Importância: |cffD3CF00Média|r"
+L["Importance: |cffFF0000Low|r"] = "Importância: |cffFF0000Baixa|r"
+L["In Progress"] = true
+L["Installation Complete"] = "Instalação Completa"
+L["Invalid Target"] = "Alvo inválido"
+L["Item Level:"] = true
+L["KEY_ALT"] = "A"
+L["KEY_CTRL"] = "C"
+L["KEY_DELETE"] = "Del"
+L["KEY_HOME"] = "Hm"
+L["KEY_INSERT"] = "Ins"
+L["KEY_MOUSEBUTTON"] = "M"
+L["KEY_MOUSEWHEELDOWN"] = "MwD"
+L["KEY_MOUSEWHEELUP"] = "MwU"
+L["KEY_NUMPAD"] = "N"
+L["KEY_PAGEDOWN"] = "PD"
+L["KEY_PAGEUP"] = "PU"
+L["KEY_SHIFT"] = "S"
+L["KEY_SPACE"] = "SpB"
+L["Key"] = "Tecla"
+L["LOGIN_MSG"] = "Welcome to %sElvUI|r version %s%s|r, type /ec to access the in-game configuration menu. If you are in need of technical support you can visit us at https://github.com/BanditTech/ElvUI-Ascension or join our Discord: https://discord.gg/UXSc7nt"
+L["Layout Set"] = "Definições do Layout"
+L["Layout"] = "Layout"
+L["Left Chat"] = "Bate-papo esquerdo"
+L["Left Click:"] = "Clique Esquerdo:"
+L["List of installations in queue:"] = true
+L["Lock"] = "Travar"
+L["Loot / Alert Frames"] = "Quadro de Saque / Alerta"
+L["Loot Frame"] = true
+L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"] = "Senhor! É um milagre! O Download sumiu como um peido no vento! Tente novamente!"
+L["MA Frames"] = "Quadro do Assistente Principal"
+L["MT Frames"] = "Quadro do Tank Principal"
+L["Micro Bar"] = "Micro Barra"
+L["Minimap"] = "Minimapa"
+L["MirrorTimer"] = true
+L["Miss Chance"] = true
+L["Mitigation By Level: "] = "Mitigação por nível"
+L["Movers"] = true
+L["Must be in group with the player if he isn't on the same server as you."] = "É necessário estar em grupo com o jogador se ele não é do mesmo reino que você."
+L["No Guild"] = "Sem Guilda"
+L["No bindings set."] = "Sem atalhos definidos"
+L["No gray items to delete."] = "Nenhum item cinzento para destruir."
+L["No, Revert Changes!"] = true
+L["Nudge"] = "Ajuste fino"
+L["O"] = "O"
+L["Objective Frame"] = true
+L["Offline"] = "Desconectado"
+L["Oh lord, you have got ElvUI and Tukui both enabled at the same time. Select an addon to disable."] = "Oh senhor, você está com os addons ElvUI e Tuki ativos ao mesmo tempo. Selecione um para desativar."
+L["On screen positions for different elements."] = true
+L["One or more of the changes you have made require a ReloadUI."] = "Uma ou mais das alterações que fez requerem que recarregue a IU."
+L["One or more of the changes you have made will effect all characters using this addon. You will have to reload the user interface to see the changes you have made."] = "Uma ou mais das alterações que fez afetará todos os personagens que usam este addon. Você terá que recarregar a interface para ver as alterações que fez."
+L["P"] = "P"
+L["PL"] = "PL"
+L["Party Frames"] = "Quadros de Grupo"
+L["Pending"] = true
+L["Pet Bar"] = "Barra do Ajudante"
+L["Pet Castbar"] = true
+L["Pet Frame"] = "Quadro do Ajudante"
+L["PetTarget Frame"] = "Quadro do Alvo do Ajudante"
+L["Player Buffs"] = true
+L["Player Castbar"] = "Barra de lançamento do Jogador"
+L["Player Debuffs"] = true
+L["Player Frame"] = "Quadro do Jogador"
+L["Player Powerbar"] = true
+L["Please click the button below so you can setup variables and ReloadUI."] = "Por favor, clique no botão abaixo para que possa configurar as variáveis e Recarregar a IU."
+L["Please click the button below to setup your CVars."] = "Por favor, clique no botão abaixo para configurar as suas Cvars."
+L["Please press the continue button to go onto the next step."] = "Por favor, pressione o botão Continuar para passar à próxima etapa."
+L["Preview Changes"] = true
+L["Preview"] = true
+L["Profile download complete from %s, but the profile %s already exists. Change the name or else it will overwrite the existing profile."] = "Baixa de perfil completada de %s, mas o perfil %s já existe. Altere o nome ou ele irá sobrescrever o perfil existente."
+L["Profile download complete from %s, would you like to load the profile %s now?"] = "Baixa de perfil completada de %s, gostaria de carregar o perfil %s agora?"
+L["Profile request sent. Waiting for response from player."] = "Pedido de perfil enviado. Aguardando a resposta do jogador."
+L["Profit:"] = "Lucro:"
+L["Purchase Bags"] = true
+L["PvP"] = true
+L["R"] = "R"
+L["RL"] = "RL"
+L["RW"] = "AR"
+L["Raid Frames"] = true
+L["Raid Menu"] = "Menu de Raide"
+L["Raid Pet Frames"] = true
+L["Raid-40 Frames"] = true
+L["Reload UI"] = true
+L["Remaining:"] = "Restante:"
+L["Remove Bar %d Action Page"] = "Remover paginação de ação da barra %d."
+L["Reputation Bar"] = "Barra de Reputação"
+L["Request was denied by user."] = "Pedido negado pelo usuário."
+L["Reset Counters: Hold Shift + Left Click"] = true
+L["Reset Data: Hold Shift + Right Click"] = "Redefinir Dados: Segurar Shifr + Clique Direito"
+L["Reset Position"] = "Redefinir Posição"
+L["Rested:"] = "Descansado:"
+L["Right Chat"] = "Bate-papo direito"
+L["Right Click:"] = true
+L["SP"] = "PM"
+L["Save"] = "Salvar"
+L["Saved Dungeon(s)"] = true
+L["Saved Raid(s)"] = "Raide(s) Salva(s)"
+L["Select the type of aura system you want to use with ElvUI's unitframes. Set to Aura Bar & Icons to use both aura bars and icons, set to icons only to only see icons."] = true
+L["Server: "] = "Servidor: "
+L["Session:"] = "Sessão:"
+L["Setup CVars"] = "Configurar CVars"
+L["Setup Chat"] = "Configurar Bate-papo"
+L["Show BG Texts"] = true
+L["Skip Process"] = "Pular Processo"
+L["Sort Bags"] = "Organizar Bolsas"
+L["Spell/Heal Power"] = true
+L["Spent:"] = "Gasto:"
+L["Stance Bar"] = "Barra de Postura"
+L["Stats For:"] = "Estatísticas para:"
+L["Steps"] = true
+L["Sticky Frames"] = "Quadros Pegadiços"
+L["System"] = true
+L["Talent Specialization:"] = true
+L["Tank / Physical DPS"] = "Tank / DPS Físico"
+L["Target Castbar"] = "Barra de lançamento do Alvo"
+L["Target Frame"] = "Quadro do Alvo"
+L["Target Powerbar"] = true
+L["TargetTarget Frame"] = "Quadro do Alvo do Alvo"
+L["TargetTargetTarget Frame"] = true
+L["Targeted By:"] = "Sendo Alvo de:"
+L["Temporary Move"] = "Mover Temporariamente"
+L["The UI Scale has been changed, if you would like to preview the change press the preview button. It is recommended that you reload your User Interface for the best appearance."] = true
+L["The chat windows function the same as Blizzard standard chat windows, you can right click the tabs and drag them around, rename, etc. Please click the button below to setup your chat windows."] = "As janelas de bate-papo funcionam da mesma forma das da Blizzard, você pode usar o botão direito nas guias para os arrastar, mudar o nome, etc. Por favor clique no botão abaixo para configurar as suas janelas de bate-papo"
+L["The focus unit can be set by typing /focus when you are targeting the unit you want to focus. It is recommended you make a macro to do this."] = "A unidade de Foco pode ser definida escrevendo /focus quando voce tem no alvo a unidade que quer tal. É recomendado que faça uma macro para este efeito."
+L["The in-game configuration menu can be accessed by typing the /ec command or by clicking the 'C' button on the minimap. Press the button below if you wish to skip the installation process."] = "O modo configuração em jogo pode ser acessado escrevendo o comando /ec ou clicando no botão 'C' no minimapa. Pressione o botão abaixo se desejar pular o processo de instalação"
+L["The profile you tried to import already exists. Choose a new name or accept to overwrite the existing profile."] = true
+L["The spell '%s' has been added to the Blacklist unitframe aura filter."] = "O feitiço \"%s\" foi adicionado à Lista Negra dos filtros das auras de unidades."
+L["Theme Set"] = "Tema configurado"
+L["Theme Setup"] = "Configuração do Tema"
+L["This install process will help you learn some of the features in ElvUI has to offer and also prepare your user interface for usage."] = "Este processo de instalação vai mostrar-lhe algumas das opções que a ElvUI tem para oferecer e também vai preparar a sua interface para ser usada."
+L["This part of the installation process sets up your World of Warcraft default options it is recommended you should do this step for everything to behave properly."] = "Esta parte da instalação serve para definir as suas opcões padrão do WoW, é recomendado fazer isto para que tudo funcione corretamente."
+L["This part of the installation process sets up your chat windows names, positions and colors."] = "Esta parte da instalação é para definir os nomes, posições e cores das suas janelas de bate-papo."
+L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."] = true
+L["This will change the layout of your unitframes and actionbars."] = true
+L["To move abilities on the actionbars by default hold shift + drag. You can change the modifier key from the actionbar options menu."] = "Para mover habilidades nas barras de ação (modo padrão) mantenha pressionado Shift enquanto arrasta. Você pode mudar a tecla no menu de opções das barras de ações."
+L["To setup which channels appear in which chat frame, right click the chat tab and go to settings."] = "Para configurar que canais aparecem em cada quadro de conversação, clique com o botão direito no guia do bate-papo e vá a configurações."
+L["Toggle Bags"] = "Mostrar/Ocultar Bolsas"
+L["Toggle Chat Frame"] = "Mostrar/Ocultar Bat-papo"
+L["Toggle Configuration"] = "Mostrar/Ocultar Modo de Configuração"
+L["Tooltip"] = "Tooltip"
+L["Total CPU:"] = "CPU Total:"
+L["Total Memory:"] = "Memória Total:"
+L["Total: "] = "Total: "
+L["Trigger"] = "Gatilho"
+L["Type /hellokitty to revert to old settings."] = true
+L["UI Scale"] = true
+L["Unhittable:"] = "Inacertável"
+L["Vehicle Seat Frame"] = "Quadro de Assento de Veículo"
+L["Vendor / Delete Grays"] = true
+L["Vendored gray items for: %s"] = "Vendeu os itens cinzentos por: %s"
+L["Vendoring Grays"] = true
+L["Welcome to ElvUI version %s!"] = "Bem-vindo à versão %s da ElvUI!"
+L["Wintergrasp"] = true
+L["XP:"] = "XP:"
+L["Yes, Keep Changes!"] = true
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"] = true
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"] = true
+L["You are now finished with the installation process. If you are in need of technical support please visit us at https://github.com/ElvUI-WotLK."] = "O processo de instalação está agora terminado. Se precisar de suporte técnico por favor visite-nos no site https://github.com/ElvUI-WotLK."
+L["You are using CPU Profiling. This causes decreased performance. Do you want to disable it or continue?"] = true
+L["You can access copy chat and chat menu functions by mouse over the top right corner of chat panel and left/right click on the button that will appear."] = "Você pode acessar ao 'copiar bate-papo' e ao menu de funções do bate-papo passando com o rato (mouse) no canto superior direito do painel e clicando botão esquerdo/direito no botão que irá aparecer."
+L["You can always change fonts and colors of any element of ElvUI from the in-game configuration."] = "As cores e fontes da ElvUI podem ser mudadas em qualquer momento no modo de configuração demtro do jogo."
+L["You can now choose what layout you wish to use based on your combat role."] = "Pode agora escolher o layout que pretende usar baseado no seu papel."
+L["You can see someones average item level of their gear by holding shift and mousing over them. It should appear inside the tooltip."] = "Você pode ver o nivel médio de itens que outra pessoa tem mantendo shift pressionado e passando com o rato (mouse) por cima deles. Deverá aparecer na tooltip."
+L["You can set your keybinds quickly by typing /kb."] = "Você pode definir os seus atalhos rapidamente escrevendo /kb."
+L["You can toggle the microbar by using your middle mouse button on the minimap you can also accomplish this by enabling the actual microbar located in the actionbar settings."] = "Você pode ativar a micro barra clicando no minimapa com o seu botão do meio do rato (mouse), pode também conseguir isto ativando a verdadeira micro barra nas definições das barras de ações."
+L["You can use the /resetui command to reset all of your movers. You can also use the command to reset a specific mover, /resetui .\nExample: /resetui Player Frame"] = "Você pode usar o comando /resetui para restaurar todos os movedores. Pode usar este comando também para restaurar um movedor especifico escrevendo /resetui \nExemplo: /resetui Player Frame"
+L["You cannot copy settings from the same unit."] = "Você não pode copiar as configurações da mesma unidade."
+L["You don't have enough money to repair all items."] = true
+L["You don't have enough money to repair."] = "Você não tem dinheiro suficiente para reparar."
+L["You don't have permission to mark targets."] = "Você não tem permissão para marcar alvos."
+L["You have imported settings which may require a UI reload to take effect. Reload now?"] = true
+L["You must purchase a bank slot first!"] = "Você deve comprar um espaço no banco primeiro!"
+L["You still have ElvUI_Config installed. ElvUI_Config has been renamed to ElvUI_OptionsUI, please remove it."] = true
+L["Your items have been repaired for: "] = "Seus itens foram reparadas por: "
+L["Your items have been repaired using guild bank funds for: "] = "Seus itens foram reparados usando fundos do banco da guilda por: "
+L["Your profile was successfully recieved by the player."] = "Seu perfil foi recebido com sucesso pelo jogador."
+L["copperabbrev"] = "|cffeda55fc|r"
+L["goldabbrev"] = "|cffffd700g|r"
+L["lvl"] = "nível"
+L["says"] = "diz"
+L["silverabbrev"] = "|cffc7c7cfs|r"
+L["whispers"] = "sussurra"
+L["yells"] = "grita"
+L["|cFFE30000Lua error recieved. You can view the error message when you exit combat."] = "|cFFE30000Erro Lua recebido. Pode ver a mensagem de erro quando sair de combate"
+
+----------------------------------
+L["RED_ENABLE"] = "|cFFff3333Ativar|r"
+L["GREEN_ENABLE"] = "|cFF33ff33Ativar|r"
+L["DESC_MOVERCONFIG"] = [=[Movedores destravados. Mova-os agora e clique Travar quando acabar.
+Options:
+ LeftClick - Toggle Nudge Frame.
+ RightClick - Open Config Section.
+ Shift + RightClick - Hides mover temporarily.
+ Ctrl + RightClick - Resets mover position to default.
+]=]
\ No newline at end of file
diff --git a/ElvUI/Locales/ruRU.lua b/ElvUI/Locales/ruRU.lua
new file mode 100644
index 0000000..3fb8877
--- /dev/null
+++ b/ElvUI/Locales/ruRU.lua
@@ -0,0 +1,330 @@
+-- Russian localization file for ruRU.
+local E = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "ruRU")
+
+L[" |cff00ff00bound to |r"] = " |cff00ff00назначено для |r"
+L["%s frame(s) has a conflicting anchor point, please change either the buff or debuff anchor point so they are not attached to each other. Forcing the debuffs to be attached to the main unitframe until fixed."] = "Обнаружен конфликт точек фиксирования во фрейме(ах) %s. Пожалуйста, переназначьте фиксирование баффов и дебаффов так, чтобы они не крепились друг к другу. Установлено принудительное крепление дебаффов к фрейму."
+L["%s is attempting to share his filters with you. Would you like to accept the request?"] = "%s хочет передать Вам свои фильтры. Желаете ли Вы принять их?"
+L["%s is attempting to share the profile %s with you. Would you like to accept the request?"] = "%s хочет передать Вам профиль %s. Желаете ли Вы принять его?"
+L["%s: %s tried to call the protected function '%s'."] = "%s: %s tried to call the protected function '%s'."
+L["(Hold Shift) Memory Usage"] = "(Зажать Shift) Использование памяти"
+L["(Modifer Click) Collect Garbage"] = "(Клик с модификатором) Очистка мусора"
+L["A raid marker feature is available by pressing Escape -> Keybinds scroll to the bottom under ElvUI and setting a keybind for the raid marker."] = "Функция рейдовых меток доступна в Escape -> Назначение клавиш. Прокрутите вниз до раздела ElvUI и назначьте клавишу для рейдовых меток."
+L["A setting you have changed will change an option for this character only. This setting that you have changed will be uneffected by changing user profiles. Changing this setting requires that you reload your User Interface."] = "Настройка, которую Вы только что изменили, будет влиять только на этого персонажа. Она не будет изменяться при смене профиля. Также это изменение требует перезагрузки интерфейса для вступления в силу."
+L["ABOVE_THREAT_FORMAT"] = "%s: %.0f%% [на %.0f%% опережаем |cff%02x%02x%02x%s|r]"
+L["AFK"] = "АФК"
+L["Accepting this will reset the UnitFrame settings for %s. Are you sure?"] = "Приняв это вы сбросите настройки для %s. Вы уверены?"
+L["Accepting this will reset your Filter Priority lists for all auras on NamePlates. Are you sure?"] = "Приняв это вы сбросите ваши списки приоритетов для всех аур на индикаторах здоровья. Вы уверены?"
+L["Accepting this will reset your Filter Priority lists for all auras on UnitFrames. Are you sure?"] = "Приняв это вы сбросите ваши списки приоритетов для всех аур на рамках юнитов. Вы уверены?"
+L["Adjust the UI Scale to fit your screen, press the autoscale button to set the UI Scale automatically."] = "Измените масштаб интерфейса для вашего экрана. Нажмите автомасштаб, чтобы мы установили его сами."
+L["All keybindings cleared for |cff00ff00%s|r."] = "Сброшены все назначения для |cff00ff00%s|r."
+L["Already Running.. Bailing Out!"] = "Уже выполняется.. Бобер, выдыхай!"
+L["Are you sure you want to apply this font to all ElvUI elements?"] = "Вы уверены, что хотите применить этот шрифт ко всем элементам ElvUI?"
+L["Are you sure you want to disband the group?"] = "Вы уверены, что хотите распустить группу?"
+L["Are you sure you want to reset all the settings on this profile?"] = "Вы уверены, что хотите сбросить все настройки для этого профиля?"
+L["Are you sure you want to reset every mover back to it's default position?"] = "Вы уверены, что хотите сбросить все фиксаторы на позиции по умолчанию?"
+L["Arena Frames"] = "Арена"
+L["Aura Bars & Icons"] = "Полосы и иконки"
+L["Auras Set"] = "Ауры установлены"
+L["Auras"] = "Ауры"
+L["Auto Scale"] = "Автоматический масштаб"
+L["Avoidance Breakdown"] = "Распределение защиты"
+L["BG"] = "ПБ"
+L["BGL"] = "Лидер ПБ"
+L["BNet Frame"] = "Оповещения BNet"
+L["Bag Mover (Grow Down)"] = "Сумки (Рост вниз)"
+L["Bag Mover (Grow Up)"] = "Сумки (Рост вверх)"
+L["Bag Mover"] = "Фиксатор сумок"
+L["Bags"] = "Сумки"
+L["Bank Mover (Grow Down)"] = "Банк (Рост вниз)"
+L["Bank Mover (Grow Up)"] = "Банк (Рост вверх)"
+L["Bank"] = "Банк"
+L["Bar "] = "Панель "
+L["Bars"] = "Полосы"
+L["Battleground datatexts temporarily hidden, to show type /bgstats or right click the 'C' icon near the minimap."] = "Информация поля боя временно скрыта. Для отображения введите /bgstat или ПКМ на иконке 'С' у миникарты."
+L["Battleground datatexts will now show again if you are inside a battleground."] = "Информация поля боя снова будет отображаться, если Вы находитесь на них."
+L["Binding"] = "Назначение"
+L["Binds Discarded"] = "Назначения отменены"
+L["Binds Saved"] = "Назначения сохранены"
+L["BoE"] = true
+L["BoU"] = "ПпИ"
+L["Boss Frames"] = "Боссы"
+L["Buffs"] = "Баффы"
+L["CVars Set"] = "Настройки сброшены"
+L["CVars"] = "Настройки игры"
+L["Calendar"] = "Календарь"
+L["Can't Roll"] = "Не могу бросить кости"
+L["Can't buy anymore slots!"] = "Невозможно приобрести больше слотов!"
+L["Caster DPS"] = "Заклинатель"
+L["Character: "] = "Персонаж: "
+L["Chat Set"] = "Чат настроен"
+L["Chat"] = "Чат"
+L["Choose a theme layout you wish to use for your initial setup."] = "Выберите тему, которую Вы хотите использовать."
+L["Classbar"] = "Полоса класса"
+L["Classic"] = "Классическая"
+L["Combat Time"] = "Время боя"
+L["Combobar"] = "Полоса серии"
+L["Config Mode:"] = "Режим настройки:"
+L["Confused.. Try Again!"] = "Что за?.. Попробуйте еще раз!"
+L["Continue"] = "Продолжить"
+L["Coords"] = "Коорд."
+L["Count"] = "Кол-во"
+L["DND"] = "ДНД"
+L["DPS"] = "УВС"
+L["Dark"] = "Темная"
+L["Data From: %s"] = "Данные от: %s"
+L["Data To: %s"] = true
+L["Dead"] = "Труп"
+L["Debuffs"] = "Дебаффы"
+L["Deficit:"] = "Убыток:"
+L["Delete gray items?"] = "Удалить серый предметы?"
+L["Detected that your ElvUI OptionsUI addon is out of date. This may be a result of your Tukui Client being out of date. Please visit our download page and update your Tukui Client, then reinstall ElvUI. Not having your ElvUI OptionsUI addon up to date will result in missing options."] = "Мы обнаружили, что ElvUI OptionsUI устарел. Это может быть результатом устаревшей версии Tukui Client. Пожалуйста, посетите нашу страницу загрузок и обновите Tukui Client, а затем переустановите ElvUI. Устаревший ElvUI OptionsUI может привести к отсутствию некоторых опций."
+L["Disable Warning"] = "Отключить предупреждение"
+L["Disable"] = "Выключить"
+L["Disband Group"] = "Распустить группу"
+L["Discard"] = "Отменить"
+L["Discord"] = true --Doesn't need translating
+L["Do you enjoy the new ElvUI?"] = "Вам нравится ElvUI?"
+L["Do you swear not to post in technical support about something not working without first disabling the addon/module combination first?"] = "Клянетесь ли Вы не постить на форуме технической поддержки, что что-то не работает, до того, как отключите другие аддоны/модули?"
+L["Earned:"] = "Заработано"
+L["ElvUI Installation"] = "Установка ElvUI"
+L["ElvUI Plugin Installation"] = "Установка плагина ElvUI"
+L["ElvUI has a dual spec feature which allows you to load different profiles based on your current spec on the fly. You can enable this from the profiles tab."] = "В ElvUI присутствует функция двойной специализации, которая позволит Вам использовать разные профили для разных наборов талантов. Вы можете включить эту функцию в разделе профилей."
+L["ElvUI is five or more revisions out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "Ваш ElvUI устарел более, чем на 5 версий. Обновите его на https://github.com/BanditTech/ElvUI-Ascension"
+L["ElvUI is out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI устарел. Вы можете скачать последнюю версию с https://github.com/BanditTech/ElvUI-Ascension"
+L["ElvUI needs to perform database optimizations please be patient."] = "ElvUI нужно провести оптимизацию базы данных. Подождите, пожалуйста."
+L["ElvUI was updated while the game is still running. Please relaunch the game, as this is required for the files to be properly updated."] = "ElvUI обновился, пока игра была запущена. Перезапустите игру, чтобы обновления могли по человечески примениться."
+L["Empty Slot"] = "Пустой слот"
+L["Enable"] = "Включить"
+L["Error resetting UnitFrame."] = "Ошибка сброса рамки юнита."
+L["Experience Bar"] = "Полоса опыта"
+L["Experience"] = "Опыт"
+L["Export Now"] = "Экспортировать"
+L["Farm Mode"] = "Режим фарма"
+L["Filter download complete from %s, would you like to apply changes now?"] = "Завершена загрузка фильтров от %s. Желаете применить изменения сейчас?"
+L["Finished"] = "Завершить"
+L["Fishy Loot"] = "Улов"
+L["Focus Castbar"] = "Полоса заклинаний фокуса"
+L["Focus Frame"] = "Фокус"
+L["FocusTarget Frame"] = "Цель фокуса"
+L["For technical support visit us at https://github.com/ElvUI-WotLK."] = "За технической поддержкой обращайтесь на https://github.com/ElvUI-WotLK."
+L["Frame"] = "Рамка"
+L["Friends List"] = "Список друзей"
+L["G"] = "Г"
+L["GM Ticket Frame"] = "Запрос ГМу"
+L["General"] = "Общие"
+L["Ghost"] = "Призрак"
+L["Gold"] = "Золото"
+L["Grid Size:"] = "Размер сетки"
+L["HP"] = "+ Исцел."
+L["HPS"] = "ИВС"
+L["Healer"] = "Лекарь"
+L["Hit"] = true
+L["Hold Control + Right Click:"] = "Зажать Control + ПКМ:"
+L["Hold Shift + Drag:"] = "Зажать shift и перетаскивать:"
+L["Hold Shift + Right Click:"] = "Shift + ПКМ:"
+L["Home Latency:"] = "Локальная задержка: "
+L["Hover your mouse over any actionbutton or spellbook button to bind it. Press the ESC key to clear the current actionbutton's keybinding."] = "Наведите мышку на любую кнопку панели команд или книги заклинаний, чтобы создать назначение. Нажатие ESC убирает текущее назначение."
+L["I Swear"] = "Я клянусь!"
+L["INCOMPATIBLE_ADDON"] = "Аддон %s не совместим с модулем %s ElvUI. Пожалуйста, выберите отключить ли несовместимый аддон или модуль."
+L["Icons Only"] = "Только иконки"
+L["If you accidently remove a chat frame you can always go the in-game configuration menu, press install, go to the chat portion and reset them."] = "Если Вы случайно удалили вкладку чата, всегда можно сделать следующее: зайти в конфигурацию, запустить установку, дойти до шага настроек чата и сбросить их."
+L["If you are experiencing issues with ElvUI try disabling all your addons except ElvUI, remember ElvUI is a full UI replacement addon, you cannot run two addons that do the same thing."] = "Если Вы испытываете проблемы с ElvUI, попробуйте отключить все аддоны, кроме самого ElvUI. Помните, ElvUI это аддон, полностью заменяющий интерфейс, Вы не можете одновременно использовать два аддона, выполняющих одинаковые функции."
+L["If you have an icon or aurabar that you don't want to display simply hold down shift and right click the icon for it to disapear."] = "Если у вас есть иконка или полоса аур, которую вы не хотите отображать, просто shift+ПКМ на ней для занесения в черный список (она пропадет)."
+L["Import Now"] = "Импортировать"
+L["Importance: |cff07D400High|r"] = "Важность: |cff07D400Высокая|r"
+L["Importance: |cffD3CF00Medium|r"] = "Важность: |cffD3CF00Средняя|r"
+L["Importance: |cffFF0000Low|r"] = "Важность: |cffFF0000Низкая|r"
+L["In Progress"] = "В процессе"
+L["Installation Complete"] = "Установка завершена"
+L["Invalid Target"] = "Неверная цель"
+L["Item Level:"] = "Уровень предмета:"
+L["KEY_ALT"] = "A"
+L["KEY_CTRL"] = "C"
+L["KEY_DELETE"] = "Del"
+L["KEY_HOME"] = "Hm"
+L["KEY_INSERT"] = "Ins"
+L["KEY_MOUSEBUTTON"] = "M"
+L["KEY_MOUSEWHEELDOWN"] = "MwD"
+L["KEY_MOUSEWHEELUP"] = "MwU"
+L["KEY_NUMPAD"] = "N"
+L["KEY_PAGEDOWN"] = "PD"
+L["KEY_PAGEUP"] = "PU"
+L["KEY_SHIFT"] = "S"
+L["KEY_SPACE"] = "SpB"
+L["Key"] = "Клавиша"
+L["LOGIN_MSG"] = "Добро пожаловать в %sElvUI|r версии %s%s|r, наберите /ec для доступа в меню настроек. Если Вам нужна техническая поддержка, посетите наш форум на https://github.com/BanditTech/ElvUI-Ascension или присоединяйтесь к серверу Discord: https://discord.gg/UXSc7nt"
+L["Layout Set"] = "Расположение установлено"
+L["Layout"] = "Расположение"
+L["Left Chat"] = "Левый чат"
+L["Left Click:"] = "ЛКМ:"
+L["List of installations in queue:"] = "Очередь установки:"
+L["Lock"] = "Закрепить"
+L["Loot / Alert Frames"] = "Розыгрыш/оповещения"
+L["Loot Frame"] = "Окно добычи"
+L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"] = "Чтоб его! Загрузка была... да всплыла. Попробуйте еще раз!"
+L["MA Frames"] = "Помощники"
+L["MT Frames"] = "Танки"
+L["Micro Bar"] = "Микроменю"
+L["Minimap"] = "Миникарта"
+L["MirrorTimer"] = "Таймер"
+L["Miss Chance"] = "Вероятность промаха"
+L["Mitigation By Level: "] = "Снижение на уровне: "
+L["Movers"] = "Фиксаторы"
+L["Must be in group with the player if he isn't on the same server as you."] = "Вы должны быть в группе в данным игроком, если он не с Вашего сервера."
+L["No Guild"] = "Нет гильдии"
+L["No bindings set."] = "Нет назначений"
+L["No gray items to delete."] = "Нет предметов серого качества для удаления."
+L["No, Revert Changes!"] = "Нет, обратить изменения!"
+L["Nudge"] = "Сдвиг"
+L["O"] = "Оф"
+L["Objective Frame"] = "Задачи"
+L["Offline"] = "Не в сети"
+L["Oh lord, you have got ElvUI and Tukui both enabled at the same time. Select an addon to disable."] = "Японский городовой... у Вас одновременно включены ElvUi и Tukui. Выберите аддон для отключения."
+L["On screen positions for different elements."] = "Положение разлицных элементов на экране"
+L["One or more of the changes you have made require a ReloadUI."] = "Одно или несколько изменений требуют перезагрузки интерфейса"
+L["One or more of the changes you have made will effect all characters using this addon. You will have to reload the user interface to see the changes you have made."] = "Одно или несколько изменений повлияют на всех персонажей, использующих этот аддон. Вы должны перезагрузить интерфейс для отображения этих изменений."
+L["P"] = "Гр"
+L["PL"] = "Лидер гр."
+L["Party Frames"] = "Группа"
+L["Pending"] = "Ожидает"
+L["Pet Bar"] = "Панель питомца"
+L["Pet Castbar"] = "Полоса заклинаний питомца"
+L["Pet Frame"] = "Питомец"
+L["PetTarget Frame"] = "Цель питомца"
+L["Player Buffs"] = "Баффы игрока"
+L["Player Castbar"] = "Полоса заклинаний игрока"
+L["Player Debuffs"] = "Дебаффы игрока"
+L["Player Frame"] = "Игрок"
+L["Player Powerbar"] = "Полоса ресурса игрока"
+L["Please click the button below so you can setup variables and ReloadUI."] = "Пожалуйста, нажмите кнопку ниже для установки переменных и перезагрузки интерфейса."
+L["Please click the button below to setup your CVars."] = "Пожалуйста, нажмите кнопку ниже для сброса настроек."
+L["Please press the continue button to go onto the next step."] = "Пожалуйста, нажмите кнопку 'Продолжить' для перехода к следующему шагу"
+L["Preview Changes"] = "Посмотреть изменения"
+L["Preview"] = "Предпросмотр"
+L["Profile download complete from %s, but the profile %s already exists. Change the name or else it will overwrite the existing profile."] = "Загрузка профиля от %s завершена, но профиль %s уже существует. Измените его название или он перезапишет уже существующий профиль."
+L["Profile download complete from %s, would you like to load the profile %s now?"] = "Загрузка профиля от %s завершена, хотите загрузить профиль %s сейчас?"
+L["Profile request sent. Waiting for response from player."] = "Запрос на передачу профиля отправлен. Ждите, пожалуйста, ответа."
+L["Profit:"] = "Прибыль:"
+L["Purchase Bags"] = "Приобрести слот"
+L["PvP"] = true
+L["R"] = "Р"
+L["RL"] = "РЛ"
+L["RW"] = "Объявление"
+L["Raid Frames"] = "Рейд"
+L["Raid Menu"] = "Рейдовое меню"
+L["Raid Pet Frames"] = "Питомцы рейда"
+L["Raid-40 Frames"] = "Рейд 40"
+L["Reload UI"] = true
+L["Remaining:"] = "Осталось:"
+L["Remove Bar %d Action Page"] = "Удалить панель %d из списка переключаемых"
+L["Reputation Bar"] = "Полоса репутации"
+L["Request was denied by user."] = "Запрос отклонен пользователем."
+L["Reset Counters: Hold Shift + Left Click"] = "Сбросить счётчики: Shift + ЛКМ"
+L["Reset Data: Hold Shift + Right Click"] = "Сбросить данные: Shift + ПКМ"
+L["Reset Position"] = "Сбросить позицию"
+L["Rested:"] = "Бодрость:"
+L["Right Chat"] = "Правый чат"
+L["Right Click:"] = "ПКМ:"
+L["SP"] = "+ Закл."
+L["Save"] = "Сохранить"
+L["Saved Dungeon(s)"] = "Сохраненнные подземелья"
+L["Saved Raid(s)"] = "Сохраненные рейды"
+L["Select the type of aura system you want to use with ElvUI's unitframes. Set to Aura Bar & Icons to use both aura bars and icons, set to icons only to only see icons."] = "Выберите тип си стемы аур, который будет применен к рамкам юнитов. Выберите \"Полосы и иконки\" для показа полос аур и иконок, выберите \"Только иконки\" для показа исключительно иконок."
+L["Server: "] = "На сервере:"
+L["Session:"] = "За сеанс:"
+L["Setup CVars"] = "Сбросить настройки"
+L["Setup Chat"] = "Настроить чат"
+L["Show BG Texts"] = true
+L["Skip Process"] = "Пропустить установку"
+L["Sort Bags"] = "Сортировать"
+L["Spell/Heal Power"] = "Сила заклинаний"
+L["Spent:"] = "Потрачено:"
+L["Stance Bar"] = "Панель стоек"
+L["Stats For:"] = "Статистика для:"
+L["Steps"] = "Шаги"
+L["Sticky Frames"] = "Клейкие фреймы"
+L["System"] = "Система"
+L["Talent Specialization:"] = "Таланты:"
+L["Tank / Physical DPS"] = "Танк / Физ. урон"
+L["Target Castbar"] = "Полоса заклинаний цели"
+L["Target Frame"] = "Цель"
+L["Target Powerbar"] = "Полоса ресурса цели"
+L["TargetTarget Frame"] = "Цель цели"
+L["TargetTargetTarget Frame"] = "Цель цели цели"
+L["Targeted By:"] = "Является целью:"
+L["Temporary Move"] = "Временное перемещение"
+L["The UI Scale has been changed, if you would like to preview the change press the preview button. It is recommended that you reload your User Interface for the best appearance."] = "Масштаб интерфейса изменен. Если вы хотите посмотреть на результат, нажмите кнопку предпросмотра. Для лучшего результата рекомендуется перезагрузить интерфейс."
+L["The chat windows function the same as Blizzard standard chat windows, you can right click the tabs and drag them around, rename, etc. Please click the button below to setup your chat windows."] = "Окна чата работают так же, как и в стандартном чате Blizzard. Вы можете нажать правую кнопку мыши на вкладках для перемещения, переименования и тд. Пожалуйста, нажмите кнопку ниже для настройки чата."
+L["The focus unit can be set by typing /focus when you are targeting the unit you want to focus. It is recommended you make a macro to do this."] = "Запомненную цель (фокус) можно установить командой /focus при взятии нужного врага в цель. Для этого рекомендуется сделать макрос."
+L["The in-game configuration menu can be accessed by typing the /ec command or by clicking the 'C' button on the minimap. Press the button below if you wish to skip the installation process."] = "Меню настроек можно вызвать командой /ес или кнопкой 'С' на миникарте. Нажмите кнопку ниже, если Вы хотите прервать процесс установки."
+L["The profile you tried to import already exists. Choose a new name or accept to overwrite the existing profile."] = "Профиль, который вы хотите импортировать, уже существует. Задайте новой имя или примите для перезаписи существующего профиля."
+L["The spell '%s' has been added to the Blacklist unitframe aura filter."] = "Заклинание \"%s\" было добавлено в фильтр \"Blacklist\" аур рамок юнитов."
+L["Theme Set"] = "Тема установлена"
+L["Theme Setup"] = "Тема"
+L["This install process will help you learn some of the features in ElvUI has to offer and also prepare your user interface for usage."] = "Этот процесс установки поможет Вам узнать о некоторых функциях ElvUI и подготовить Ваш интерфейс к использованию."
+L["This part of the installation process sets up your World of Warcraft default options it is recommended you should do this step for everything to behave properly."] = "Эта часть установки сбросит настройки World of Warcraft на конфигурацию по умолчанию. Рекомендуется выполнить этот шаг для надлежащей работы интерфейса."
+L["This part of the installation process sets up your chat windows names, positions and colors."] = "Эта часть установки настроит названия, позиции и цвета вкладок чата."
+L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."] = "Эта опция вызвала конфликт точек фиксации, в результате которого \"%s\" крепится к самому себе. Пожалуйста, проверьте настройки точек фиксации. \"%s\" будет прикреплено к \"%s\"."
+L["This will change the layout of your unitframes and actionbars."] = "Это изменит расположение ваших рамок юнитов, рейда и панелей команд."
+L["To move abilities on the actionbars by default hold shift + drag. You can change the modifier key from the actionbar options menu."] = "Для перемещения способностей по панелям команд нужно перемещать их с зажатой клавишей shift. Вы можете поменять модификатор в опциях панелей команд."
+L["To setup which channels appear in which chat frame, right click the chat tab and go to settings."] = "Для настройки отображения каналов в чате кликните правой кнопкой мыши на закладке нужного чата и выберите пункт \"параметры\"."
+L["Toggle Bags"] = "Показать сумки"
+L["Toggle Chat Frame"] = "Показать/скрыть чат"
+L["Toggle Configuration"] = "Конфигурация"
+L["Tooltip"] = "Подсказка"
+L["Total CPU:"] = "Использование процессора:"
+L["Total Memory:"] = "Всего памяти:"
+L["Total: "] = "Всего: "
+L["Trigger"] = "Триггер"
+L["Type /hellokitty to revert to old settings."] = "Напишите /hellokitty для возврата к предыдущим настройкам."
+L["UI Scale"] = true
+L["Unhittable:"] = "Полная защита от ударов"
+L["Vehicle Seat Frame"] = "Техника"
+L["Vendor / Delete Grays"] = "Продать/удалить серые предметы"
+L["Vendored gray items for: %s"] = "Проданы серые предметы на сумму: %s"
+L["Vendoring Grays"] = "Продаю хлам"
+L["Welcome to ElvUI version %s!"] = "Добро пожаловать в ElvUI версии %s!"
+L["Wintergrasp"] = "Озеро Ледяных Оков"
+L["XP:"] = "Опыт:"
+L["Yes, Keep Changes!"] = "Да, сохранить изменения!"
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"] = "Вы собираетесь скопировать настройки для модуля |cffD3CF00\"%s\"|r из вашего текущего профиля |cff4beb2c\"%s\"|r в профиль |cff4beb2c\"%s\"|r. Вы уверены?"
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"] = "Вы собираетесь скопировать настройки для модуля |cffD3CF00\"%s\"|r из вашего профиля |cff4beb2c\"%s\"|r в текущий профиль |cff4beb2c\"%s\"|r. Вы уверены?"
+L["You are now finished with the installation process. If you are in need of technical support please visit us at https://github.com/ElvUI-WotLK."] = "Вы завершили процесс установки. Если Вам требуется техническая поддержка, посетите сайт https://github.com/ElvUI-WotLK."
+L["You are using CPU Profiling. This causes decreased performance. Do you want to disable it or continue?"] = "Вы используете профайлинг ЦПУ. Это бьет по производительности. Вы точно уверены, что это нужно?"
+L["You can access copy chat and chat menu functions by mouse over the top right corner of chat panel and left/right click on the button that will appear."] = "Вы можете получить доступ к функциям копирования чата и меню чата, наведя курсор на верхний правый угол панели чата и кликнув левой/правой кнопкой мыши на появившейся кнопке."
+L["You can always change fonts and colors of any element of ElvUI from the in-game configuration."] = "Вы всегда можете изменить шрифты и цвета любого элемента ElvUI из меню конфигурации. Классическая и пиксельная темы не отличаются для русского клиента."
+L["You can now choose what layout you wish to use based on your combat role."] = "Вы можете выбрать используемое расположение, основываясь на Вашей роли."
+L["You can see someones average item level of their gear by holding shift and mousing over them. It should appear inside the tooltip."] = "Вы можете узнать средний уровень предметов игрока, зажав shift и наведя на них курсор. Информация будет отражена в подсказке."
+L["You can set your keybinds quickly by typing /kb."] = "Вы можете быстро назначать клавиши, введя команду /kb."
+L["You can toggle the microbar by using your middle mouse button on the minimap you can also accomplish this by enabling the actual microbar located in the actionbar settings."] = "Вы можете получить доступ к микроменю, кликнув средней кнопкой мыши на миникарте. Также Вы можете включить обычное микроменю в настройках панелей команд"
+L["You can use the /resetui command to reset all of your movers. You can also use the command to reset a specific mover, /resetui .\nExample: /resetui Player Frame"] = "Вы можете использовать команду /resetui чтобы сбросить положения всех фиксаторов. Вы также можете использовать команду /resetui <имя фиксатора> для сброса определенного фиксатора.\nПример: /resetui Player Frame"
+L["You cannot copy settings from the same unit."] = "Вы не можете копировать установки из того же юнита."
+L["You don't have enough money to repair all items."] = true
+L["You don't have enough money to repair."] = "У вас недостаточно денег для ремонта."
+L["You don't have permission to mark targets."] = "У вас нет разрешения на установку меток"
+L["You have imported settings which may require a UI reload to take effect. Reload now?"] = "Вы импортировали настройки, которые могут потребовать перезагрузки для вступления в силу. Перезагрузить?"
+L["You must purchase a bank slot first!"] = "Сперва Вы должны приобрести дополнительный слот в банке!"
+L["You still have ElvUI_Config installed. ElvUI_Config has been renamed to ElvUI_OptionsUI, please remove it."] = true
+L["Your items have been repaired for: "] = "Ремонт обошелся в "
+L["Your items have been repaired using guild bank funds for: "] = "Ремонт обошелся гильдии в "
+L["Your profile was successfully recieved by the player."] = "Ваш профиль успешно получен целью. Ура, товарищи!"
+L["copperabbrev"] = "|cffeda55fм|r"
+L["goldabbrev"] = "|cffffd700з|r"
+L["lvl"] = "ур."
+L["says"] = "говорит"
+L["silverabbrev"] = "|cffc7c7cfс|r"
+L["whispers"] = "шепчет"
+L["yells"] = "кричит"
+L["|cFFE30000Lua error recieved. You can view the error message when you exit combat."] = "|cFFE30000Обнаружена ошибка lua. Вы получите отчет о ней после завершения боя."
+
+----------------------------------
+L["RED_ENABLE"] = "|cFFff3333Включить|r"
+L["GREEN_ENABLE"] = "|cFF33ff33Включить|r"
+L["DESC_MOVERCONFIG"] = [=[Блокировка отключена. Передвиньте фреймы и нажмите "Закрепить", когда закончите.
+Options:
+ LeftClick - Toggle Nudge Frame.
+ RightClick - Open Config Section.
+ Shift + RightClick - Hides mover temporarily.
+ Ctrl + RightClick - Resets mover position to default.
+]=]
\ No newline at end of file
diff --git a/ElvUI/Locales/zhCN.lua b/ElvUI/Locales/zhCN.lua
new file mode 100644
index 0000000..20f5b3b
--- /dev/null
+++ b/ElvUI/Locales/zhCN.lua
@@ -0,0 +1,331 @@
+-- Simplified Chinese localization file for zhCN.
+local E = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "zhCN")
+
+L[" |cff00ff00bound to |r"] = " |cff00ff00绑定到 |r"
+L["%s frame(s) has a conflicting anchor point, please change either the buff or debuff anchor point so they are not attached to each other. Forcing the debuffs to be attached to the main unitframe until fixed."] = "%s 个框架锚点冲突,请移动buff或者debuff锚点让他们彼此不依附。暂时强制debuff依附到主框架。"
+L["%s is attempting to share his filters with you. Would you like to accept the request?"] = "%s 试图与你分享过滤器配置. 你是否接受?"
+L["%s is attempting to share the profile %s with you. Would you like to accept the request?"] = "%s 试图与你分享配置文件 %s. 你是否接受?"
+L["%s: %s tried to call the protected function '%s'."] = "%s: %s 尝试调用保护函数 '%s'."
+L["(Hold Shift) Memory Usage"] = "(按住Shift) 内存占用"
+L["(Modifer Click) Collect Garbage"] = "(按住修饰键并点击) 垃圾回收"
+L["A raid marker feature is available by pressing Escape -> Keybinds scroll to the bottom under ElvUI and setting a keybind for the raid marker."] = "你可以通过按ESC键 -> 按键设置, 滚动到ElvUI设置下方设置一个快速标记的快捷键."
+L["A setting you have changed will change an option for this character only. This setting that you have changed will be uneffected by changing user profiles. Changing this setting requires that you reload your User Interface."] = "你所做的改动只会影响到使用这个插件的本角色, 你需要重新加载界面才能使改动生效."
+L["ABOVE_THREAT_FORMAT"] = "%s: %.0f%% [%.0f%% 以上 |cff%02x%02x%02x%s|r]"
+L["AFK"] = "离开"
+L["Accepting this will reset the UnitFrame settings for %s. Are you sure?"] = "接受这个将重置关于%s的单位单位框架. 你确定吗?"
+L["Accepting this will reset your Filter Priority lists for all auras on NamePlates. Are you sure?"] = "接受这个将重置姓名板中所有光环的过滤器优先级. 你确定吗?"
+L["Accepting this will reset your Filter Priority lists for all auras on UnitFrames. Are you sure?"] = "接受这个将重置单位框架中所有光环的过滤器优先级. 你确定吗?"
+L["Adjust the UI Scale to fit your screen, press the autoscale button to set the UI Scale automatically."] = "调整UI缩放来适应你的屏幕, 点击自动缩放按钮来自动设置UI缩放."
+L["All keybindings cleared for |cff00ff00%s|r."] = "取消 |cff00ff00%s|r 所有绑定的快捷键."
+L["Already Running.. Bailing Out!"] = "正在运行!"
+L["Are you sure you want to apply this font to all ElvUI elements?"] = "确定要对所有ElvUI元素使用这个字体?"
+L["Are you sure you want to disband the group?"] = "确定要解散队伍?"
+L["Are you sure you want to reset all the settings on this profile?"] = "确定需要重置这个配置文件中的所有设置?"
+L["Are you sure you want to reset every mover back to it's default position?"] = "确定需要重置所有框架至默认位置?"
+L["Arena Frames"] = "竞技场框架"
+L["Aura Bars & Icons"] = "光环条及图标"
+L["Auras Set"] = "光环设定"
+L["Auras"] = "光环"
+L["Auto Scale"] = "自动缩放"
+L["Avoidance Breakdown"] = "免伤统计"
+L["BG"] = "战场"
+L["BGL"] = "战场领袖"
+L["BNet Frame"] = "战网提示信息"
+L["Bag Mover (Grow Down)"] = "背包框架(向下)"
+L["Bag Mover (Grow Up)"] = "背包框架(向上)"
+L["Bag Mover"] = "背包框架"
+L["Bags"] = "背包"
+L["Bank Mover (Grow Down)"] = "银行框架(向下)"
+L["Bank Mover (Grow Up)"] = "银行框架(向上)"
+L["Bank"] = "银行"
+L["Bar "] = "动作条 "
+L["Bars"] = "条"
+L["Battleground datatexts temporarily hidden, to show type /bgstats or right click the 'C' icon near the minimap."] = "战场信息暂时隐藏, 你可以通过输入/bgstats 或右键点击小地图旁「C」按钮显示."
+L["Battleground datatexts will now show again if you are inside a battleground."] = "当你处于战场时战场信息将再次显示."
+L["Binding"] = "绑定"
+L["Binds Discarded"] = "取消绑定"
+L["Binds Saved"] = "保存绑定"
+L["BoE"] = true
+L["BoU"] = "使用后绑定"
+L["Boss Frames"] = "首领框架"
+L["Buffs"] = "增益光环"
+L["CVars Set"] = "参数设定"
+L["CVars"] = "参数"
+L["Calendar"] = "日历"
+L["Can't Roll"] = "无法需求此装备"
+L["Can't buy anymore slots!"] = "银行背包栏位已达最大值"
+L["Caster DPS"] = "法系输出"
+L["Character: "] = "角色: "
+L["Chat Set"] = "聊天设定"
+L["Chat"] = "聊天框"
+L["Choose a theme layout you wish to use for your initial setup."] = "为你的个人设置选择一个你喜欢的皮肤主题."
+L["Classbar"] = "职业特有条"
+L["Classic"] = "经典"
+L["Combat Time"] = "战斗时间"
+L["Combobar"] = "连击点"
+L["Config Mode:"] = "设置模式:"
+L["Confused.. Try Again!"] = "请再试一次!"
+L["Continue"] = "下一步"
+L["Coords"] = "坐标"
+L["Count"] = "计数"
+L["DND"] = "忙碌"
+L["DPS"] = "伤害输出"
+L["Dark"] = "黑暗"
+L["Data From: %s"] = "数据来源: %s"
+L["Data To: %s"] = "数据发往: %s"
+L["Dead"] = "死亡"
+L["Debuffs"] = "减益光环"
+L["Deficit:"] = "亏损:"
+L["Delete gray items?"] = "删除灰色物品?"
+L["Detected that your ElvUI OptionsUI addon is out of date. This may be a result of your Tukui Client being out of date. Please visit our download page and update your Tukui Client, then reinstall ElvUI. Not having your ElvUI OptionsUI addon up to date will result in missing options."] = "检测到您的ElvUI设置插件已过期.这可能是因为您的 Tukui 客户端已过期.请访问我们的下载页面并更新 Tukui 客户端,然后重新安装ElvUI.ElvUI设置插件过期会造成某些选项丢失"
+L["Disable Warning"] = "禁用警告"
+L["Disable"] = "禁用"
+L["Disband Group"] = "解散队伍"
+L["Discard"] = "取消"
+L["Discord"] = "Discord"
+L["Do you enjoy the new ElvUI?"] = "你喜欢新的ElvUI么?"
+L["Do you swear not to post in technical support about something not working without first disabling the addon/module combination first?"] = "你发誓在你没停用其他插件前不会到技术支持询问某些功能失效吗?"
+L["Earned:"] = "赚取:"
+L["ElvUI Installation"] = "安装 ElvUI"
+L["ElvUI Plugin Installation"] = "ElvUI插件安装"
+L["ElvUI has a dual spec feature which allows you to load different profiles based on your current spec on the fly. You can enable this from the profiles tab."] = "ElvUI可以根据你所使用的天赋自动套用不同的设置档. 你可以在配置文件中使用此功能."
+L["ElvUI is five or more revisions out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI已过期5个或者更多的版本。你可以在https://github.com/BanditTech/ElvUI-Ascension下载到最新的版本。"
+L["ElvUI is out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI已过期。你可以在www.tukui.org下载到最新的版本。"
+L["ElvUI needs to perform database optimizations please be patient."] = "ElvUI需要进行数据库优化,请耐性等待。"
+L["ElvUI was updated while the game is still running. Please relaunch the game, as this is required for the files to be properly updated."] = "ElvUI已更新,然而游戏仍在运行. 请重启游戏,以保证文件正确更新."
+L["Empty Slot"] = "空拾取位"
+L["Enable"] = "启用"
+L["Error resetting UnitFrame."] = "重置单位框架出现错误."
+L["Experience Bar"] = "经验条"
+L["Experience"] = "经验/声望条"
+L["Export Now"] = "现在导出"
+L["Farm Mode"] = "farm模式"
+L["Filter download complete from %s, would you like to apply changes now?"] = "过滤器配置下载于 %s, 你是否现在变更?"
+L["Finished"] = "完成"
+L["Fishy Loot"] = "贪婪"
+L["Focus Castbar"] = "焦点施法条"
+L["Focus Frame"] = "焦点框架"
+L["FocusTarget Frame"] = "焦点目标框架"
+L["For technical support visit us at https://github.com/ElvUI-WotLK."] = "如需技术支援请至 https://github.com/ElvUI-WotLK."
+L["Frame"] = "框架"
+L["Friends List"] = "好友列表"
+L["G"] = "公会"
+L["GM Ticket Frame"] = "GM对话框"
+L["General"] = "一般"
+L["Ghost"] = "鬼魂"
+L["Gold"] = "金"
+L["Grid Size:"] = "网格尺寸:"
+L["HP"] = "生命值"
+L["HPS"] = "治疗输出"
+L["Healer"] = "治疗"
+L["Hit"] = true
+L["Hold Control + Right Click:"] = "按住 Ctrl 并按鼠标右键:"
+L["Hold Shift + Drag:"] = "按住 Shift 并拖动:"
+L["Hold Shift + Right Click:"] = "按住Shift + 右键点击"
+L["Home Latency:"] = "本机延迟:"
+L["Hover your mouse over any actionbutton or spellbook button to bind it. Press the ESC key to clear the current actionbutton's keybinding."] = "鼠标指向任何动作条或者技能书快捷键来绑定它. 按Esc键来清除当前动作条按钮的按键绑定."
+L["I Swear"] = "我承诺"
+L["INCOMPATIBLE_ADDON"] = "插件 %s 不相容于 ElvUI 的 %s 模组, 请停用不相容的插件, 或停用模组."
+L["Icons Only"] = "图标"
+L["If you accidently remove a chat frame you can always go the in-game configuration menu, press install, go to the chat portion and reset them."] = "如果你不慎移除了对话框, 你可以重新安装一次重置他们."
+L["If you are experiencing issues with ElvUI try disabling all your addons except ElvUI, remember ElvUI is a full UI replacement addon, you cannot run two addons that do the same thing."] = "如果你遇到问题, ElvUI会尝试禁用你除了ElvUI之外的插件. 请记住你不能用不同的插件实现同一功能."
+L["If you have an icon or aurabar that you don't want to display simply hold down shift and right click the icon for it to disapear."] = "如果你不希望显示某个光环图标或者光环条,只需要按住shift并右键点击它."
+L["Import Now"] = "现在导入"
+L["Importance: |cff07D400High|r"] = "重要度: |cff07D400高|r"
+L["Importance: |cffD3CF00Medium|r"] = "重要性: |cffD3CF00中|r"
+L["Importance: |cffFF0000Low|r"] = "重要性:|cffFF0000低|r"
+L["In Progress"] = "正在进行中"
+L["Installation Complete"] = "安装完成"
+L["Invalid Target"] = "无效的目标"
+L["Item Level:"] = "物品等级:"
+L["KEY_ALT"] = "A"
+L["KEY_CTRL"] = "C"
+L["KEY_DELETE"] = "Del"
+L["KEY_HOME"] = "Hm"
+L["KEY_INSERT"] = "Ins"
+L["KEY_MOUSEBUTTON"] = "M"
+L["KEY_MOUSEWHEELDOWN"] = "MwD"
+L["KEY_MOUSEWHEELUP"] = "MwU"
+L["KEY_NUMPAD"] = "N"
+L["KEY_PAGEDOWN"] = "PD"
+L["KEY_PAGEUP"] = "PU"
+L["KEY_SHIFT"] = "S"
+L["KEY_SPACE"] = "SpB"
+L["Key"] = "键"
+L["LOGIN_MSG"] = "Welcome to %sElvUI|r version %s%s|r, type /ec to access the in-game configuration menu. If you are in need of technical support you can visit us at https://github.com/BanditTech/ElvUI-Ascension or join our Discord: https://discord.gg/UXSc7nt"
+L["Layout Set"] = "界面布局设置"
+L["Layout"] = "界面布局"
+L["Left Chat"] = "左侧对话框"
+L["Left Click:"] = "左键:"
+L["List of installations in queue:"] = "即将安装的列表:"
+L["Lock"] = "锁定"
+L["Loot / Alert Frames"] = "拾取/提醒框"
+L["Loot Frame"] = "拾取框架"
+L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"] = "天啊! 太奇葩了! 下载消失了! 就像在风中放了一个屁... 再试一次吧!"
+L["MA Frames"] = "主助理框"
+L["MT Frames"] = "主坦克框"
+L["Micro Bar"] = "微型系统菜单"
+L["Minimap"] = "小地图"
+L["MirrorTimer"] = "镜像计时器"
+L["Miss Chance"] = true
+L["Mitigation By Level: "] = "等级减伤: "
+L["Movers"] = "框架位置"
+L["Must be in group with the player if he isn't on the same server as you."] = "如果不是同一服务器, 那他必须和你在同一队伍中"
+L["No Guild"] = "没有公会"
+L["No bindings set."] = "无绑定设定"
+L["No gray items to delete."] = "没有要删除的灰色物品"
+L["No, Revert Changes!"] = "不,撤销修改!"
+L["Nudge"] = "微调"
+L["O"] = "官员"
+L["Objective Frame"] = "任务框架"
+L["Offline"] = "离线"
+L["Oh lord, you have got ElvUI and Tukui both enabled at the same time. Select an addon to disable."] = "你不能同时使用Elvui和Tukui,请选择一个禁用."
+L["On screen positions for different elements."] = "屏幕上各元素的位置"
+L["One or more of the changes you have made require a ReloadUI."] = "已变更一或多个设定,需重载界面."
+L["One or more of the changes you have made will effect all characters using this addon. You will have to reload the user interface to see the changes you have made."] = "你所做的改动可能会影响到使用这个插件的所有角色,你需要重新加载界面才能使改动生效。"
+L["P"] = "队伍"
+L["PL"] = "队长"
+L["Party Frames"] = "小队框架"
+L["Pending"] = "等待中"
+L["Pet Bar"] = "宠物动作条"
+L["Pet Castbar"] = "宠物施法条"
+L["Pet Frame"] = "宠物框架"
+L["PetTarget Frame"] = "宠物目标框架"
+L["Player Buffs"] = "玩家增益"
+L["Player Castbar"] = "玩家施法条"
+L["Player Debuffs"] = "玩家减益"
+L["Player Frame"] = "玩家框架"
+L["Player Powerbar"] = "玩家能量条"
+L["Please click the button below so you can setup variables and ReloadUI."] = "请按下方按钮设定变数并重载介面。"
+L["Please click the button below to setup your CVars."] = "请按下方按钮设定参数."
+L["Please press the continue button to go onto the next step."] = "请按继续按钮到下一步"
+L["Preview Changes"] = "预览改动"
+L["Preview"] = "预览"
+L["Profile download complete from %s, but the profile %s already exists. Change the name or else it will overwrite the existing profile."] = "配置文件从 %s 下载完成, 但是配置文件 %s 已存在. 请更改名称, 否则它会覆盖你的现有配置文件."
+L["Profile download complete from %s, would you like to load the profile %s now?"] = "配置文件从 %s 下载完成, 你是否加载配置文件 %s?"
+L["Profile request sent. Waiting for response from player."] = "已发送文件请求. 等待对方响应."
+L["Profit:"] = "利润:"
+L["Purchase Bags"] = "购买背包"
+L["PvP"] = true
+L["R"] = "团队"
+L["RL"] = "团队领袖"
+L["RW"] = "团队警告"
+L["Raid Frames"] = "团队框体"
+L["Raid Menu"] = "团队菜单"
+L["Raid Pet Frames"] = "团队宠物框体"
+L["Raid-40 Frames"] = "40人团队框体"
+L["Reload UI"] = "重载界面"
+L["Remaining:"] = "剩余:"
+L["Remove Bar %d Action Page"] = "移除第%d动作条"
+L["Reputation Bar"] = "声望条"
+L["Request was denied by user."] = "请求被对方拒绝."
+L["Reset Counters: Hold Shift + Left Click"] = "重置计数器: 按住Shift + 左键点击"
+L["Reset Data: Hold Shift + Right Click"] = "重置数据: 按住 Shift + 右键点击"
+L["Reset Position"] = "重设位置"
+L["Rested:"] = "休息:"
+L["Right Chat"] = "右侧对话框"
+L["Right Click:"] = "右键点击"
+L["SP"] = "法术强度"
+L["Save"] = "储存"
+L["Saved Dungeon(s)"] = "已有进度的地下城"
+L["Saved Raid(s)"] = "已有进度的副本"
+L["Select the type of aura system you want to use with ElvUI's unitframes. Set to Aura Bar & Icons to use both aura bars and icons, set to icons only to only see icons."] = "选择你想使用的光环系统类型. 选择光环条及图标将会同时显示光环条及图标,选择图标将只会显示图标."
+L["Server: "] = "服务器: "
+L["Session:"] = "本次登陆:"
+L["Setup CVars"] = "设定参数"
+L["Setup Chat"] = "设定聊天框"
+L["Show BG Texts"] = "显示战场文本"
+L["Skip Process"] = "跳过"
+L["Sort Bags"] = "背包整理"
+L["Spell/Heal Power"] = "法术/治疗强度"
+L["Spent:"] = "花费:"
+L["Stance Bar"] = "姿态条"
+L["Stats For:"] = "统计:"
+L["Steps"] = "步骤"
+L["Sticky Frames"] = "框架依附"
+L["System"] = "系统信息"
+L["Talent Specialization:"] = "天赋专精"
+L["Tank / Physical DPS"] = "坦克/物理输出"
+L["Target Castbar"] = "目标施法条"
+L["Target Frame"] = "目标框架"
+L["Target Powerbar"] = "目标能量条"
+L["TargetTarget Frame"] = "目标的目标框架"
+L["TargetTargetTarget Frame"] = "目标的目标的目标框架"
+L["Targeted By:"] = "同目标的有:"
+L["Temporary Move"] = "移动背包"
+L["The UI Scale has been changed, if you would like to preview the change press the preview button. It is recommended that you reload your User Interface for the best appearance."] = "UI缩放已经改变, 点击'预览'按钮来预览改动. 建议你重载界面以获得最好的界面."
+L["The chat windows function the same as Blizzard standard chat windows, you can right click the tabs and drag them around, rename, etc. Please click the button below to setup your chat windows."] = "对话窗口与 WOW 原始对话窗口的操作方式相同,你可以拖拉、移动分页或重新命名分页。请按下方按钮以设定对话窗口。"
+L["The focus unit can be set by typing /focus when you are targeting the unit you want to focus. It is recommended you make a macro to do this."] = "你可以通过 /focus 命令设置焦点目标."
+L["The in-game configuration menu can be accessed by typing the /ec command or by clicking the 'C' button on the minimap. Press the button below if you wish to skip the installation process."] = "若要进入内建设定选单,请输入 /ec,或者按一下小地图旁的 C 按钮。若要略过安装程序,请按下方按钮。"
+L["The profile you tried to import already exists. Choose a new name or accept to overwrite the existing profile."] = "你尝试导入的配置文件已经存在。请选择一个新的名字或者确认覆盖存在的配置文件。"
+L["The spell '%s' has been added to the Blacklist unitframe aura filter."] = "法术\"%s\"已经被添加到单位框架的光环过滤器中."
+L["Theme Set"] = "主题设置"
+L["Theme Setup"] = "主题安装"
+L["This install process will help you learn some of the features in ElvUI has to offer and also prepare your user interface for usage."] = "此安装程序有助你了解 ElvUI 部份功能,并可协助你预先设定 UI。"
+L["This part of the installation process sets up your World of Warcraft default options it is recommended you should do this step for everything to behave properly."] = "此安装步骤将会设定 WOW 预设选项,建议你执行此步骤,以确保功能均可正常运作。"
+L["This part of the installation process sets up your chat windows names, positions and colors."] = "此安装步骤将会设定聊天框的名称、位置和颜色。"
+L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."] = "这个设置引起一个互相矛盾的锚点, '%s' 被依附于他自身. 请检查你的锚点设置. 设置 '%s' 依附到 '%s'."
+L["This will change the layout of your unitframes and actionbars."] = "这将会改变你单位框架和动作条的构架。"
+L["To move abilities on the actionbars by default hold shift + drag. You can change the modifier key from the actionbar options menu."] = "你可以通过按住Shift拖动技能条中的按键. 你可以在 Blizzard 的动作条设置中更改按键."
+L["To setup which channels appear in which chat frame, right click the chat tab and go to settings."] = "你可以通过右键点击对话框标签栏设置你需要在对话框内显示的频道."
+L["Toggle Bags"] = "背包开关"
+L["Toggle Chat Frame"] = "开关聊天框架"
+L["Toggle Configuration"] = "设置开关"
+L["Tooltip"] = "鼠标提示"
+L["Total CPU:"] = "CPU占用"
+L["Total Memory:"] = "总内存:"
+L["Total: "] = "合计: "
+L["Trigger"] = "触发器"
+L["Type /hellokitty to revert to old settings."] = "输入/hellokitty以撤销到原来的设定"
+L["UI Scale"] = "界面缩放"
+L["Unhittable:"] = "未命中:"
+L["Vehicle Seat Frame"] = "载具座位框"
+L["Vendor / Delete Grays"] = "出售/删除灰色物品"
+L["Vendored gray items for: %s"] = "已出售灰色物品: %s"
+L["Vendoring Grays"] = "正在出售灰色物品"
+L["Welcome to ElvUI version %s!"] = "欢迎使用 ElvUI 版本 %s!"
+L["Wintergrasp"] = "冬拥湖"
+L["XP:"] = "经验:"
+L["Yes, Keep Changes!"] = "是的,保存修改!"
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"] = "|cffD3CF00\"%s\"|r 设置将从你当前配置文件 |cff4beb2c\"%s\"|r 导出到 |cff4beb2c\"%s\"|r 配置文件中. 你确定吗?"
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"] = "|cffD3CF00\"%s\"|r 设置将从 |cff4beb2c\"%s\"|r 配置文件导入到你当前配置文件 |cff4beb2c\"%s\"|r 中. 你确定吗?"
+L["You are now finished with the installation process. If you are in need of technical support please visit us at https://github.com/ElvUI-WotLK."] = "你已经完成安装过程. 如果你需要技术支持请访问https://github.com/ElvUI-WotLK"
+L["You are using CPU Profiling. This causes decreased performance. Do you want to disable it or continue?"] = "你正在追踪CPU使用记录. 这将导致性能低下. 你想禁用它还是继续?"
+L["You can access copy chat and chat menu functions by mouse over the top right corner of chat panel and left/right click on the button that will appear."] = "你可以通过鼠标滑过对话框右上角点击复制图标打开对话复制窗口."
+L["You can always change fonts and colors of any element of ElvUI from the in-game configuration."] = "你可以在游戏内的设定选项内更改ElvUI的字体、颜色等设定."
+L["You can now choose what layout you wish to use based on your combat role."] = "你现在可以根据你的战斗角色选择合适的布局。"
+L["You can see someones average item level of their gear by holding shift and mousing over them. It should appear inside the tooltip."] = "你可以通过按住Shift并将鼠标滑过目标看到目标的装备等级, 这将显示在你的鼠标提示框内."
+L["You can set your keybinds quickly by typing /kb."] = "你可以通过输入 /kb 快速绑定按键."
+L["You can toggle the microbar by using your middle mouse button on the minimap you can also accomplish this by enabling the actual microbar located in the actionbar settings."] = "你可以通过鼠标中键点击小地图或在动作条设置内选择打开微型系统栏."
+L["You can use the /resetui command to reset all of your movers. You can also use the command to reset a specific mover, /resetui .\nExample: /resetui Player Frame"] = "使用 /resetui 命令可以重置你的所有框架位置. 你也可以通过命令 /resetui <框架名称> 单独重置某个框架.\n例如: /resetui Player Frame"
+L["You cannot copy settings from the same unit."] = "你不能从相同的单位复制设定"
+L["You don't have enough money to repair all items."] = "你没有足够的金币修理所有物品。"
+L["You don't have enough money to repair."] = "你没有足够的金币修理。"
+L["You don't have permission to mark targets."] = "你没有标记目标的权限"
+L["You have imported settings which may require a UI reload to take effect. Reload now?"] = "你导入的设置可能需要重载界面才能生效。确认重载?"
+L["You must purchase a bank slot first!"] = "你必需购买一个银行背包栏位"
+L["You still have ElvUI_Config installed. ElvUI_Config has been renamed to ElvUI_OptionsUI, please remove it."] = "你插件里依然有ElvUI_Config,不过它已经重命名为ElvUI_OptionsUI,请删除它。"
+L["Your items have been repaired for: "] = "装备已修复: "
+L["Your items have been repaired using guild bank funds for: "] = "物品已使用公会银行资金修复: "
+L["Your profile was successfully recieved by the player."] = "你的配置文件已被其他玩家成功接收."
+L["copperabbrev"] = "|cffeda55f铜|r"
+L["goldabbrev"] = "|cffffd700金|r"
+L["lvl"] = "等级"
+L["says"] = "说"
+L["silverabbrev"] = "|cffc7c7cf银|r"
+L["whispers"] = "密语"
+L["yells"] = "大喊"
+L["|cFFE30000Lua error recieved. You can view the error message when you exit combat."] = "|cFFE30000LUA错误已接收, 你可以在脱离战斗后检查.|r"
+
+----------------------------------
+L["RED_ENABLE"] = "|cFFff3333启用|r"
+L["GREEN_ENABLE"] = "|cFF33ff33启用|r"
+L["DESC_MOVERCONFIG"] = [=[解除框架移动锁定. 现在可以移动它们, 移好后请点击「锁定」.
+
+选项:
+ 左键 - 打开微调窗口.
+ 右键 - 打开配置窗口.
+ Shift + 右键 - 暂时隐藏定位开关
+ Ctrl + 右键 - 重置定位开关位置
+]=]
\ No newline at end of file
diff --git a/ElvUI/Locales/zhTW.lua b/ElvUI/Locales/zhTW.lua
new file mode 100644
index 0000000..d7d41d8
--- /dev/null
+++ b/ElvUI/Locales/zhTW.lua
@@ -0,0 +1,330 @@
+-- Traditional Chinese localization file for zhTW.
+local E = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local L = E.Libs.ACL:NewLocale("ElvUI", "zhTW")
+
+L[" |cff00ff00bound to |r"] = " |cff00ff00綁定到 |r"
+L["%s frame(s) has a conflicting anchor point, please change either the buff or debuff anchor point so they are not attached to each other. Forcing the debuffs to be attached to the main unitframe until fixed."] = " %s 個框架錨點衝突, 請移動buff或者debuff錨點讓他們彼此不依附. 暫時強制debuff依附到主框架."
+L["%s is attempting to share his filters with you. Would you like to accept the request?"] = "%s 試圖與你分享過濾器設定. 你是否接受?"
+L["%s is attempting to share the profile %s with you. Would you like to accept the request?"] = "%s 試圖與你分享設定檔 %s. 你是否接受?"
+L["%s: %s tried to call the protected function '%s'."] = "%s: %s 嘗試調用保護函數'%s'."
+L["(Hold Shift) Memory Usage"] = "(按住 Shift) 記憶體使用量"
+L["(Modifer Click) Collect Garbage"] = "(按住修飾鍵) 垃圾收集"
+L["A raid marker feature is available by pressing Escape -> Keybinds scroll to the bottom under ElvUI and setting a keybind for the raid marker."] = "你可以通過按ESC鍵-> 按鍵設定, 滾動到ElvUI設定下方設定一個快速標記的快捷鍵."
+L["A setting you have changed will change an option for this character only. This setting that you have changed will be uneffected by changing user profiles. Changing this setting requires that you reload your User Interface."] = "你所做的改動只會影響到使用這個插件的本角色, 你需要重新加載介面才能使改動生效."
+L["ABOVE_THREAT_FORMAT"] = "%s: %.0f%% [%.0f%% 以上 |cff%02x%02x%02x%s|r]"
+L["AFK"] = "離開"
+L["Accepting this will reset the UnitFrame settings for %s. Are you sure?"] = "接受將會重置 %s 的單位框架設定. 你確定嗎?"
+L["Accepting this will reset your Filter Priority lists for all auras on NamePlates. Are you sure?"] = "接受將會重置所有姓名板(血條)的過濾器優先度列表. 你確定嗎?"
+L["Accepting this will reset your Filter Priority lists for all auras on UnitFrames. Are you sure?"] = "接受將會重置所有單位框架的過濾器優先度列表. 你確定嗎?"
+L["Adjust the UI Scale to fit your screen, press the autoscale button to set the UI Scale automatically."] = "調節適合你螢幕的介面縮放比例, 按下自動調節按鍵可自動設置介面縮放比例。"
+L["All keybindings cleared for |cff00ff00%s|r."] = "取消|cff00ff00%s|r 所有綁定的快捷鍵."
+L["Already Running.. Bailing Out!"] = "正在運行"
+L["Are you sure you want to apply this font to all ElvUI elements?"] = "你確定要將此字型應用到所有 ElvUI 部件嗎?"
+L["Are you sure you want to disband the group?"] = "確定要解散隊伍?"
+L["Are you sure you want to reset all the settings on this profile?"] = "確定需要重置這個設定檔中的所有設定?"
+L["Are you sure you want to reset every mover back to it's default position?"] = "確定需要重置所有框架至預設位置?"
+L["Arena Frames"] = "競技場框架"
+L["Aura Bars & Icons"] = "光環條及圖標"
+L["Auras Set"] = "光環設定"
+L["Auras"] = "光環"
+L["Auto Scale"] = "自動縮放"
+L["Avoidance Breakdown"] = "免傷統計"
+L["BG"] = true
+L["BGL"] = true
+L["BNet Frame"] = "戰網提示資訊"
+L["Bag Mover (Grow Down)"] = "背包錨點 (向下增長)"
+L["Bag Mover (Grow Up)"] = "背包錨點 (向上增長)"
+L["Bag Mover"] = "背包錨點"
+L["Bags"] = "背包"
+L["Bank Mover (Grow Down)"] = "銀行錨點 (向下增長)"
+L["Bank Mover (Grow Up)"] = "銀行錨點 (向上增長)"
+L["Bank"] = "銀行"
+L["Bar "] = "快捷列 "
+L["Bars"] = "條"
+L["Battleground datatexts temporarily hidden, to show type /bgstats or right click the 'C' icon near the minimap."] = "戰場資訊暫時隱藏, 你可以通過輸入/bgstats 或右鍵點擊小地圖旁「C」按鈕顯示."
+L["Battleground datatexts will now show again if you are inside a battleground."] = "當你處於戰場時戰場資訊將再次顯示."
+L["Binding"] = "綁定"
+L["Binds Discarded"] = "取消綁定"
+L["Binds Saved"] = "儲存綁定"
+L["BoE"] = true
+L["BoU"] = true
+L["Boss Frames"] = "首領框架"
+L["Buffs"] = "增益光環"
+L["CVars Set"] = "參數設定"
+L["CVars"] = "參數"
+L["Calendar"] = "行事曆"
+L["Can't Roll"] = "無法需求此裝備"
+L["Can't buy anymore slots!"] = "無法再購買更多銀行欄位!"
+L["Caster DPS"] = "法系輸出"
+L["Character: "] = "角色: "
+L["Chat Set"] = "對話设置"
+L["Chat"] = "對話"
+L["Choose a theme layout you wish to use for your initial setup."] = "為你的個人設定選擇一個你喜歡的皮膚主題."
+L["Classbar"] = "職業特有條"
+L["Classic"] = "經典"
+L["Combat Time"] = "戰鬥時間"
+L["Combobar"] = "集星條"
+L["Config Mode:"] = "設定模式:"
+L["Confused.. Try Again!"] = "請再試一次!"
+L["Continue"] = "下一步"
+L["Coords"] = "坐標"
+L["Count"] = "計數"
+L["DND"] = "忙碌"
+L["DPS"] = "傷害輸出"
+L["Dark"] = "黑暗"
+L["Data From: %s"] = "數據來源: %s"
+L["Data To: %s"] = true
+L["Dead"] = "死亡"
+L["Debuffs"] = "減益光環"
+L["Deficit:"] = "赤字:"
+L["Delete gray items?"] = "刪除灰色物品?"
+L["Detected that your ElvUI OptionsUI addon is out of date. This may be a result of your Tukui Client being out of date. Please visit our download page and update your Tukui Client, then reinstall ElvUI. Not having your ElvUI OptionsUI addon up to date will result in missing options."] = "偵測到你的 ElvUI 設定插件已過期. 這可能是因為你的 Tukui 客戶端已過期. 請拜訪我們的下載頁面並更新 Tukui 客戶端然後再重新安裝 ElvUI. ElvUI 設定插件過期會造成某些選項遺失"
+L["Disable Warning"] = "停用警告"
+L["Disable"] = "停用"
+L["Disband Group"] = "解散隊伍"
+L["Discard"] = "取消"
+L["Discord"] = true
+L["Do you enjoy the new ElvUI?"] = "你享受新版的ElvUI嗎?"
+L["Do you swear not to post in technical support about something not working without first disabling the addon/module combination first?"] = "你發誓在你沒停用其他插件或是模組前不會到技術支援發文詢問某些功能失效嗎?"
+L["Earned:"] = "賺取:"
+L["ElvUI Installation"] = "安裝 ElvUI"
+L["ElvUI Plugin Installation"] = "ElvUI 插件安裝"
+L["ElvUI has a dual spec feature which allows you to load different profiles based on your current spec on the fly. You can enable this from the profiles tab."] = "ElvUI 可以根據你所使用的天賦自動套用不同的裝備組. 你可以在設定檔中啟用此功能."
+L["ElvUI is five or more revisions out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI 已過期超過5個版本. 你可以在 https://github.com/BanditTech/ElvUI-Ascension 下載到最新的版本."
+L["ElvUI is out of date. You can download the newest version from https://github.com/BanditTech/ElvUI-Ascension"] = "ElvUI 已過期. 你可以在 https://github.com/BanditTech/ElvUI-Ascension 下載到最新的版本."
+L["ElvUI needs to perform database optimizations please be patient."] = "ElvUI 需要進行資料庫優化, 請稍待."
+L["ElvUI was updated while the game is still running. Please relaunch the game, as this is required for the files to be properly updated."] = "ElvUI 在遊戲運行時被更新了. 請重開遊戲以確保文件的完整更新."
+L["Empty Slot"] = "空格"
+L["Enable"] = "啟用"
+L["Error resetting UnitFrame."] = "重置單位框架錯誤"
+L["Experience Bar"] = "經驗條"
+L["Experience"] = "經驗/聲望條"
+L["Export Now"] = "現在導出"
+L["Farm Mode"] = true
+L["Filter download complete from %s, would you like to apply changes now?"] = "過濾器設定下載於 %s, 你是否現在變更?"
+L["Finished"] = "設定完畢"
+L["Fishy Loot"] = "貪婪"
+L["Focus Castbar"] = "焦點目標施法條"
+L["Focus Frame"] = "焦點目標框架"
+L["FocusTarget Frame"] = "焦點目標的目標框架"
+L["For technical support visit us at https://github.com/ElvUI-WotLK."] = "如需技術支援請至 https://github.com/ElvUI-WotLK."
+L["Frame"] = "框架"
+L["Friends List"] = "好友列表"
+L["G"] = "公會"
+L["GM Ticket Frame"] = "GM 對話框"
+L["General"] = "一般設定"
+L["Ghost"] = "鬼魂"
+L["Gold"] = "金錢"
+L["Grid Size:"] = "網格尺寸:"
+L["HP"] = "生命值"
+L["HPS"] = "治療輸出"
+L["Healer"] = "補師"
+L["Hit"] = true
+L["Hold Control + Right Click:"] = "按住 Ctrl 並按滑鼠右鍵:"
+L["Hold Shift + Drag:"] = "按住 Shift 並拖曳:"
+L["Hold Shift + Right Click:"] = "按住 Shift + 滑鼠右鍵"
+L["Home Latency:"] = "本機延遲:"
+L["Hover your mouse over any actionbutton or spellbook button to bind it. Press the ESC key to clear the current actionbutton's keybinding."] = "將你的滑鼠游標放在任意快捷鍵或是法術書上來完成綁定。按下 ESC 可以清除當前快捷鍵的綁定."
+L["I Swear"] = "我承諾"
+L["INCOMPATIBLE_ADDON"] = "插件 %s 與 ElvUI 的 %s 模組不相容。請停用不相容的插件, 或停用相關的模組."
+L["Icons Only"] = "圖示"
+L["If you accidently remove a chat frame you can always go the in-game configuration menu, press install, go to the chat portion and reset them."] = "如果你不慎移除了對話框, 你可以重新安裝一次重置他們."
+L["If you are experiencing issues with ElvUI try disabling all your addons except ElvUI, remember ElvUI is a full UI replacement addon, you cannot run two addons that do the same thing."] = "如果你使用 ElvUI 時遇到問題, 請嘗試停用除了ElvUI之外的插件. 請記住ElvUI是一套全套的UI替換插件, 你不能同時使用不同的插件來完成同一件事."
+L["If you have an icon or aurabar that you don't want to display simply hold down shift and right click the icon for it to disapear."] = "如果你不想讓某一個光環或是光環條顯示出來, 只需按住Shift的同時滑鼠右鍵點擊圖標就可以讓其消失."
+L["Import Now"] = "現在導入"
+L["Importance: |cff07D400High|r"] = "重要性: |cff07D400高|r"
+L["Importance: |cffD3CF00Medium|r"] = "重要性: |cffD3CF00中|r"
+L["Importance: |cffFF0000Low|r"] = "重要性: |cffFF0000低|r"
+L["In Progress"] = "進行中"
+L["Installation Complete"] = "安裝完畢"
+L["Invalid Target"] = "無效的目標"
+L["Item Level:"] = "物品等級:"
+L["KEY_ALT"] = "A"
+L["KEY_CTRL"] = "C"
+L["KEY_DELETE"] = "Del"
+L["KEY_HOME"] = "Hm"
+L["KEY_INSERT"] = "Ins"
+L["KEY_MOUSEBUTTON"] = "M"
+L["KEY_MOUSEWHEELDOWN"] = "MwD"
+L["KEY_MOUSEWHEELUP"] = "MwU"
+L["KEY_NUMPAD"] = "N"
+L["KEY_PAGEDOWN"] = "PD"
+L["KEY_PAGEUP"] = "PU"
+L["KEY_SHIFT"] = "S"
+L["KEY_SPACE"] = "SpB"
+L["Key"] = "鍵"
+L["LOGIN_MSG"] = "歡迎使用 %sElvUI|r %s%s 版本|r, 輸入 /ec 可打開遊戲內設置介面. 如果你需要技術協助, 可訪問我們的網址 https://github.com/BanditTech/ElvUI-Ascension 或是加入我們的 Discord 伺服器: https://discord.gg/UXSc7nt"
+L["Layout Set"] = "版面配置設定"
+L["Layout"] = "介面佈局"
+L["Left Chat"] = "左側對話框"
+L["Left Click:"] = "滑鼠左鍵:"
+L["List of installations in queue:"] = "即將安裝的列表"
+L["Lock"] = "鎖定"
+L["Loot / Alert Frames"] = "拾取 / 提醒框架"
+L["Loot Frame"] = "拾取框架"
+L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"] = "天啊! 太奇葩啦! 下載消失了! 就像是在風中放了個屁... 再試一次吧!"
+L["MA Frames"] = "主助理框架"
+L["MT Frames"] = "主坦克框架"
+L["Micro Bar"] = "微型系統菜單"
+L["Minimap"] = "小地圖"
+L["MirrorTimer"] = "鏡像計時器"
+L["Miss Chance"] = true
+L["Mitigation By Level: "] = "等級減傷: "
+L["Movers"] = "移動器"
+L["Must be in group with the player if he isn't on the same server as you."] = "如果不是同一服務器, 那他必需和你在同一隊伍中."
+L["No Guild"] = "沒有公會"
+L["No bindings set."] = "未設定快捷綁定."
+L["No gray items to delete."] = "沒有可刪除的灰色物品."
+L["No, Revert Changes!"] = "不, 回復修改!"
+L["Nudge"] = "微調"
+L["O"] = "幹部"
+L["Objective Frame"] = "任務框架"
+L["Offline"] = "離線"
+L["Oh lord, you have got ElvUI and Tukui both enabled at the same time. Select an addon to disable."] = "喔 拜託,你不能同時使用 Elvui 和 Tukui, 請選擇一個停用."
+L["On screen positions for different elements."] = "不同的元件在螢幕上的位置"
+L["One or more of the changes you have made require a ReloadUI."] = "已變更一或多個設定, 需重載介面."
+L["One or more of the changes you have made will effect all characters using this addon. You will have to reload the user interface to see the changes you have made."] = "你所做的改動可能會影響到使用這個插件的所有角色, 你需要重新加載介面才能使改動生效."
+L["P"] = "隊伍"
+L["PL"] = "隊長"
+L["Party Frames"] = "隊伍框架"
+L["Pending"] = "等待中"
+L["Pet Bar"] = "寵物快捷列"
+L["Pet Castbar"] = "寵物施法條"
+L["Pet Frame"] = "寵物框架"
+L["PetTarget Frame"] = "寵物目標框架"
+L["Player Buffs"] = "玩家增益"
+L["Player Castbar"] = "玩家施法條"
+L["Player Debuffs"] = "玩家減益"
+L["Player Frame"] = "玩家框架"
+L["Player Powerbar"] = "玩家能量條"
+L["Please click the button below so you can setup variables and ReloadUI."] = "請按下方按鈕設定變數並重載介面."
+L["Please click the button below to setup your CVars."] = "請按下方按鈕設定參數."
+L["Please press the continue button to go onto the next step."] = "請按「繼續」按鈕, 執行下一個步驟."
+L["Preview Changes"] = "預覽修改"
+L["Preview"] = "預覽"
+L["Profile download complete from %s, but the profile %s already exists. Change the name or else it will overwrite the existing profile."] = "設定文件從 %s 下載完成, 但是設定文件 %s 已存在. 請更改名稱, 否則它會覆蓋你的現有設定檔."
+L["Profile download complete from %s, would you like to load the profile %s now?"] = "設定檔從 %s 下載完成, 你是否要加載設定檔 %s?"
+L["Profile request sent. Waiting for response from player."] = "已發送設定檔請求. 等待對方回應"
+L["Profit:"] = "利潤: "
+L["Purchase Bags"] = "購買背包"
+L["PvP"] = true
+L["R"] = "團隊"
+L["RL"] = "團長"
+L["RW"] = "團隊警告"
+L["Raid Frames"] = "團隊框架"
+L["Raid Menu"] = "團隊選單"
+L["Raid Pet Frames"] = "團隊寵物框架"
+L["Raid-40 Frames"] = "40人團隊框架"
+L["Reload UI"] = true
+L["Remaining:"] = "剩餘:"
+L["Remove Bar %d Action Page"] = "移除第 %d 快捷列"
+L["Reputation Bar"] = "聲望條"
+L["Request was denied by user."] = "請求被對方拒絕."
+L["Reset Counters: Hold Shift + Left Click"] = "重置計數器: 按住 Shift + 左鍵點擊"
+L["Reset Data: Hold Shift + Right Click"] = "重置數據: 按住 Shift + 右鍵點擊"
+L["Reset Position"] = "重設位置"
+L["Rested:"] = "休息:"
+L["Right Chat"] = "右側對話框"
+L["Right Click:"] = true
+L["SP"] = "法術能量"
+L["Save"] = "儲存"
+L["Saved Dungeon(s)"] = "已有進度地城"
+L["Saved Raid(s)"] = "已有進度的副本"
+L["Select the type of aura system you want to use with ElvUI's unitframes. Set to Aura Bar & Icons to use both aura bars and icons, set to icons only to only see icons."] = "選擇你想用在 ElvUI 單位框架上的光環系統類型. 選擇光環條及圖標將會同時顯示光環條及光環圖標, 如果選擇圖標就只會顯示光環圖標."
+L["Server: "] = "伺服器: "
+L["Session:"] = "本次登入:"
+L["Setup CVars"] = "設定參數"
+L["Setup Chat"] = "設定對話視窗"
+L["Show BG Texts"] = true
+L["Skip Process"] = "略過"
+L["Sort Bags"] = "整理背包"
+L["Spell/Heal Power"] = "法術/治療強度"
+L["Spent:"] = "花費:"
+L["Stance Bar"] = "姿態列"
+L["Stats For:"] = "統計:"
+L["Steps"] = "步驟"
+L["Sticky Frames"] = "框架依附"
+L["System"] = "系統信息"
+L["Talent Specialization:"] = true
+L["Tank / Physical DPS"] = "坦克/物理輸出"
+L["Target Castbar"] = "目標施法條"
+L["Target Frame"] = "目標框架"
+L["Target Powerbar"] = "目標能量條"
+L["TargetTarget Frame"] = "目標的目標框架"
+L["TargetTargetTarget Frame"] = "目標的目標的目標框架"
+L["Targeted By:"] = "同目標的有:"
+L["Temporary Move"] = "移動背包"
+L["The UI Scale has been changed, if you would like to preview the change press the preview button. It is recommended that you reload your User Interface for the best appearance."] = "介面縮放比例已被更改, 如果您想預覽這個更改, 請按預覽按鈕. 同時建議您為了最好的顯示效果重載用戶介面."
+L["The chat windows function the same as Blizzard standard chat windows, you can right click the tabs and drag them around, rename, etc. Please click the button below to setup your chat windows."] = "對話視窗與魔獸世界原生對話視窗的操作方式相同, 你可以拖拉、移動分頁或重新命名分頁. 請按下方按鈕以設定對話視窗."
+L["The focus unit can be set by typing /focus when you are targeting the unit you want to focus. It is recommended you make a macro to do this."] = "你可以使用 /focus 指令設定目前目標為焦點目標. 建議你可以寫一個聚集來做這件事"
+L["The in-game configuration menu can be accessed by typing the /ec command or by clicking the 'C' button on the minimap. Press the button below if you wish to skip the installation process."] = "若要進入內建設定選單, 請輸入/ec, 或者按一下小地圖旁的「C」按鈕.若要略過安裝程序, 請按下方按鈕."
+L["The profile you tried to import already exists. Choose a new name or accept to overwrite the existing profile."] = "你嘗試導入的設定檔已存在. 選擇一個新名稱或是允許覆蓋原有設定檔"
+L["The spell '%s' has been added to the Blacklist unitframe aura filter."] = "法術'%s'已經被添加到單位框架的光環過濾器中."
+L["Theme Set"] = "主題設定"
+L["Theme Setup"] = "主題安裝"
+L["This install process will help you learn some of the features in ElvUI has to offer and also prepare your user interface for usage."] = "此安裝程序有助你瞭解ElvUI 部份功能, 並可協助你預先設定UI."
+L["This part of the installation process sets up your World of Warcraft default options it is recommended you should do this step for everything to behave properly."] = "此安裝步驟將會設定魔獸世界的預設選項, 建議你執行此步驟, 以確保功能均可正常運作."
+L["This part of the installation process sets up your chat windows names, positions and colors."] = "此安裝步驟將會設定對話視窗的名稱、位置和顏色."
+L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."] = "此設定造成了錨點衝突, '%s' 框架會依附於自己, 請檢查你的錨點. 將 '%s' 依附於 '%s'."
+L["This will change the layout of your unitframes and actionbars."] = "這將會改變你的單位框架和動作條的佈局"
+L["To move abilities on the actionbars by default hold shift + drag. You can change the modifier key from the actionbar options menu."] = "你可以通過按住Shift拖動技能條中的按鍵. 你可以在Blizzard的快捷列設定中更改按鍵."
+L["To setup which channels appear in which chat frame, right click the chat tab and go to settings."] = "你可以通過右鍵點擊對話框標籤欄設定你需要在對話框內顯示的頻道."
+L["Toggle Bags"] = "開啟/關閉背包"
+L["Toggle Chat Frame"] = "開關對話框架"
+L["Toggle Configuration"] = "開啟/關閉設定"
+L["Tooltip"] = "浮動提示"
+L["Total CPU:"] = "CPU佔用"
+L["Total Memory:"] = "總記憶體:"
+L["Total: "] = "合計: "
+L["Trigger"] = "觸發器"
+L["Type /hellokitty to revert to old settings."] = "輸入 /hellokitty 來回復舊設定"
+L["UI Scale"] = true
+L["Unhittable:"] = "未命中:"
+L["Vehicle Seat Frame"] = "載具座位框"
+L["Vendor / Delete Grays"] = "出售/摧毁灰色物品"
+L["Vendored gray items for: %s"] = "已售出灰色物品, 共得: %s"
+L["Vendoring Grays"] = "正在出售灰色物品"
+L["Welcome to ElvUI version %s!"] = "歡迎使用 ElvUI %s 版!"
+L["Wintergrasp"] = true
+L["XP:"] = "經驗:"
+L["Yes, Keep Changes!"] = "是的, 保留變更!"
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"] = "你將進行 |cffD3CF00\"%s\"|r 的設定拷貝, 從當前配置文件 |cff4beb2c\"%s\"|r 到配置文件 |cff4beb2c\"%s\"|r. 你確定麼?"
+L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"] = "你將進行 |cffD3CF00\"%s\"|r 的設定拷貝, 從配置文件 |cff4beb2c\"%s\"|r 到你當前配置文件 |cff4beb2c\"%s\"|r. 你確定麼?"
+L["You are now finished with the installation process. If you are in need of technical support please visit us at https://github.com/ElvUI-WotLK."] = "已完成安裝程序. 小提示: 若想開啟微型選單, 請在小地圖按滑鼠中鍵. 如果沒有中鍵按鈕, 請按住Shift鍵, 並在小地圖按滑鼠右鍵. 如需技術支援請至https://github.com/ElvUI-WotLK"
+L["You are using CPU Profiling. This causes decreased performance. Do you want to disable it or continue?"] = "你正在使用 CPU 使用記錄. 這將導致性能低下. 你想要關閉它還是繼續?"
+L["You can access copy chat and chat menu functions by mouse over the top right corner of chat panel and left/right click on the button that will appear."] = "你可以將滑鼠滑到對話框右上角並且點擊左鍵或右鍵來開啟對話複製或是對話指令視窗"
+L["You can always change fonts and colors of any element of ElvUI from the in-game configuration."] = "你可以在遊戲內的設定選項內更改ElvUI的字體、顏色等設定."
+L["You can now choose what layout you wish to use based on your combat role."] = "你現在可以根據你的戰鬥角色選擇合適的佈局."
+L["You can see someones average item level of their gear by holding shift and mousing over them. It should appear inside the tooltip."] = "你可以透過按住Shift並將滑鼠滑過目標來看到目標的平均裝等, 結果將顯示在你的滑鼠提示框內."
+L["You can set your keybinds quickly by typing /kb."] = "你可以通過輸入/kb 快速綁定按鍵."
+L["You can toggle the microbar by using your middle mouse button on the minimap you can also accomplish this by enabling the actual microbar located in the actionbar settings."] = "你可以通過滑鼠中鍵點擊小地圖或在快捷列設定內選擇打開微型系統欄."
+L["You can use the /resetui command to reset all of your movers. You can also use the command to reset a specific mover, /resetui .\nExample: /resetui Player Frame"] = "你可以使用 /resetui 命令來重置所有框架的位置. 你也可以通過命令 /resetui <框架名稱> 單獨重置某個框架.\n例如: /resetui Player Frame"
+L["You cannot copy settings from the same unit."] = "你不能從相同的單位複制設定"
+L["You don't have enough money to repair all items."] = true
+L["You don't have enough money to repair."] = "沒有足夠的資金來修理."
+L["You don't have permission to mark targets."] = "你沒有標記目標的權限."
+L["You have imported settings which may require a UI reload to take effect. Reload now?"] = "你導入的設定可能需要重新載入UI才能生效. 現在重新載入嗎?"
+L["You must purchase a bank slot first!"] = "你必需先購買一個銀行背包欄位!"
+L["You still have ElvUI_Config installed. ElvUI_Config has been renamed to ElvUI_OptionsUI, please remove it."] = true
+L["Your items have been repaired for: "] = "裝備已修理, 共支出:"
+L["Your items have been repaired using guild bank funds for: "] = "已使用公會資金修理裝備, 共支出:"
+L["Your profile was successfully recieved by the player."] = "你的設定檔已被其他玩家成功接收."
+L["copperabbrev"] = "|cffeda55f銅|r"
+L["goldabbrev"] = "|cffffd700金|r"
+L["lvl"] = "等級"
+L["says"] = "說"
+L["silverabbrev"] = "|cffc7c7cf銀|r"
+L["whispers"] = "密語"
+L["yells"] = "大喊"
+L["|cFFE30000Lua error recieved. You can view the error message when you exit combat."] = "|cFFE30000接收到了Lua錯誤, 你可以在脫離戰鬥後檢查.|r"
+
+----------------------------------
+L["RED_ENABLE"] = "|cFFff3333啟用|r"
+L["GREEN_ENABLE"] = "|cFF33ff33啟用|r"
+L["DESC_MOVERCONFIG"] = [=[解除框架移動鎖定. 現在可以移動它們, 移好後請點擊「鎖定」.
+選項:
+ 左鍵 - 開啟微調窗口.
+ 右鍵 - 開啟對應設定.
+ Shift + 右鍵 - 暫時隱藏定位器.
+ Ctrl + 右鍵 - 重置定位器位置到預設值.
+]=]
\ No newline at end of file
diff --git a/ElvUI/Media/Arrows/Arrow0.tga b/ElvUI/Media/Arrows/Arrow0.tga
new file mode 100644
index 0000000..9b590b0
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow0.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow1.tga b/ElvUI/Media/Arrows/Arrow1.tga
new file mode 100644
index 0000000..967ee7a
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow1.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow10.tga b/ElvUI/Media/Arrows/Arrow10.tga
new file mode 100644
index 0000000..fc21912
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow10.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow11.tga b/ElvUI/Media/Arrows/Arrow11.tga
new file mode 100644
index 0000000..32bab0e
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow11.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow12.tga b/ElvUI/Media/Arrows/Arrow12.tga
new file mode 100644
index 0000000..662b66b
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow12.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow13.tga b/ElvUI/Media/Arrows/Arrow13.tga
new file mode 100644
index 0000000..fd6f897
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow13.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow14.tga b/ElvUI/Media/Arrows/Arrow14.tga
new file mode 100644
index 0000000..cb0d84e
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow14.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow15.tga b/ElvUI/Media/Arrows/Arrow15.tga
new file mode 100644
index 0000000..342d4e2
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow15.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow16.tga b/ElvUI/Media/Arrows/Arrow16.tga
new file mode 100644
index 0000000..643df8f
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow16.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow17.tga b/ElvUI/Media/Arrows/Arrow17.tga
new file mode 100644
index 0000000..3954bc6
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow17.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow18.tga b/ElvUI/Media/Arrows/Arrow18.tga
new file mode 100644
index 0000000..3023e2c
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow18.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow19.tga b/ElvUI/Media/Arrows/Arrow19.tga
new file mode 100644
index 0000000..5857a52
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow19.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow2.tga b/ElvUI/Media/Arrows/Arrow2.tga
new file mode 100644
index 0000000..309be5d
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow2.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow20.tga b/ElvUI/Media/Arrows/Arrow20.tga
new file mode 100644
index 0000000..d3f4c79
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow20.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow21.tga b/ElvUI/Media/Arrows/Arrow21.tga
new file mode 100644
index 0000000..9e5fd64
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow21.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow22.tga b/ElvUI/Media/Arrows/Arrow22.tga
new file mode 100644
index 0000000..29e6165
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow22.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow23.tga b/ElvUI/Media/Arrows/Arrow23.tga
new file mode 100644
index 0000000..907bf4d
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow23.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow24.tga b/ElvUI/Media/Arrows/Arrow24.tga
new file mode 100644
index 0000000..1f9526c
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow24.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow25.tga b/ElvUI/Media/Arrows/Arrow25.tga
new file mode 100644
index 0000000..010dcbe
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow25.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow26.tga b/ElvUI/Media/Arrows/Arrow26.tga
new file mode 100644
index 0000000..0fff509
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow26.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow27.tga b/ElvUI/Media/Arrows/Arrow27.tga
new file mode 100644
index 0000000..0919c83
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow27.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow28.tga b/ElvUI/Media/Arrows/Arrow28.tga
new file mode 100644
index 0000000..7e3d2bd
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow28.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow29.tga b/ElvUI/Media/Arrows/Arrow29.tga
new file mode 100644
index 0000000..5607b4f
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow29.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow3.tga b/ElvUI/Media/Arrows/Arrow3.tga
new file mode 100644
index 0000000..f7d47dc
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow3.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow30.tga b/ElvUI/Media/Arrows/Arrow30.tga
new file mode 100644
index 0000000..0470030
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow30.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow31.tga b/ElvUI/Media/Arrows/Arrow31.tga
new file mode 100644
index 0000000..652e9c8
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow31.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow32.tga b/ElvUI/Media/Arrows/Arrow32.tga
new file mode 100644
index 0000000..7d88bda
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow32.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow33.tga b/ElvUI/Media/Arrows/Arrow33.tga
new file mode 100644
index 0000000..3e59bfc
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow33.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow34.tga b/ElvUI/Media/Arrows/Arrow34.tga
new file mode 100644
index 0000000..4245528
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow34.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow35.tga b/ElvUI/Media/Arrows/Arrow35.tga
new file mode 100644
index 0000000..8dcc5ed
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow35.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow36.tga b/ElvUI/Media/Arrows/Arrow36.tga
new file mode 100644
index 0000000..d932d07
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow36.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow37.tga b/ElvUI/Media/Arrows/Arrow37.tga
new file mode 100644
index 0000000..13d01b3
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow37.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow38.tga b/ElvUI/Media/Arrows/Arrow38.tga
new file mode 100644
index 0000000..8225b0b
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow38.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow39.tga b/ElvUI/Media/Arrows/Arrow39.tga
new file mode 100644
index 0000000..681ea05
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow39.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow4.tga b/ElvUI/Media/Arrows/Arrow4.tga
new file mode 100644
index 0000000..19c4b3c
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow4.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow40.tga b/ElvUI/Media/Arrows/Arrow40.tga
new file mode 100644
index 0000000..ac22b49
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow40.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow41.tga b/ElvUI/Media/Arrows/Arrow41.tga
new file mode 100644
index 0000000..5420b2a
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow41.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow42.tga b/ElvUI/Media/Arrows/Arrow42.tga
new file mode 100644
index 0000000..d6cc247
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow42.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow43.tga b/ElvUI/Media/Arrows/Arrow43.tga
new file mode 100644
index 0000000..49311cd
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow43.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow44.tga b/ElvUI/Media/Arrows/Arrow44.tga
new file mode 100644
index 0000000..5309e46
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow44.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow45.tga b/ElvUI/Media/Arrows/Arrow45.tga
new file mode 100644
index 0000000..2aff66b
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow45.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow46.tga b/ElvUI/Media/Arrows/Arrow46.tga
new file mode 100644
index 0000000..46f285b
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow46.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow47.tga b/ElvUI/Media/Arrows/Arrow47.tga
new file mode 100644
index 0000000..e856e3d
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow47.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow48.tga b/ElvUI/Media/Arrows/Arrow48.tga
new file mode 100644
index 0000000..844ba81
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow48.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow49.tga b/ElvUI/Media/Arrows/Arrow49.tga
new file mode 100644
index 0000000..42d9cf6
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow49.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow5.tga b/ElvUI/Media/Arrows/Arrow5.tga
new file mode 100644
index 0000000..479d98a
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow5.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow50.tga b/ElvUI/Media/Arrows/Arrow50.tga
new file mode 100644
index 0000000..ab4599f
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow50.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow51.tga b/ElvUI/Media/Arrows/Arrow51.tga
new file mode 100644
index 0000000..f208f57
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow51.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow52.tga b/ElvUI/Media/Arrows/Arrow52.tga
new file mode 100644
index 0000000..b3cd785
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow52.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow53.tga b/ElvUI/Media/Arrows/Arrow53.tga
new file mode 100644
index 0000000..8909ad8
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow53.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow54.tga b/ElvUI/Media/Arrows/Arrow54.tga
new file mode 100644
index 0000000..ddf8e0b
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow54.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow55.tga b/ElvUI/Media/Arrows/Arrow55.tga
new file mode 100644
index 0000000..d6d0aa9
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow55.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow56.tga b/ElvUI/Media/Arrows/Arrow56.tga
new file mode 100644
index 0000000..c963366
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow56.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow57.tga b/ElvUI/Media/Arrows/Arrow57.tga
new file mode 100644
index 0000000..f96411e
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow57.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow58.tga b/ElvUI/Media/Arrows/Arrow58.tga
new file mode 100644
index 0000000..cedbe26
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow58.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow59.tga b/ElvUI/Media/Arrows/Arrow59.tga
new file mode 100644
index 0000000..27a6384
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow59.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow6.tga b/ElvUI/Media/Arrows/Arrow6.tga
new file mode 100644
index 0000000..c351d41
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow6.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow60.tga b/ElvUI/Media/Arrows/Arrow60.tga
new file mode 100644
index 0000000..23e6110
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow60.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow61.tga b/ElvUI/Media/Arrows/Arrow61.tga
new file mode 100644
index 0000000..55efdef
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow61.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow62.tga b/ElvUI/Media/Arrows/Arrow62.tga
new file mode 100644
index 0000000..eea57b7
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow62.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow63.tga b/ElvUI/Media/Arrows/Arrow63.tga
new file mode 100644
index 0000000..4376d0a
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow63.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow64.tga b/ElvUI/Media/Arrows/Arrow64.tga
new file mode 100644
index 0000000..0546d47
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow64.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow65.tga b/ElvUI/Media/Arrows/Arrow65.tga
new file mode 100644
index 0000000..db4fb86
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow65.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow66.tga b/ElvUI/Media/Arrows/Arrow66.tga
new file mode 100644
index 0000000..8007cba
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow66.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow67.tga b/ElvUI/Media/Arrows/Arrow67.tga
new file mode 100644
index 0000000..33b9538
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow67.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow68.tga b/ElvUI/Media/Arrows/Arrow68.tga
new file mode 100644
index 0000000..1dca756
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow68.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow69.tga b/ElvUI/Media/Arrows/Arrow69.tga
new file mode 100644
index 0000000..fa259a2
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow69.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow7.tga b/ElvUI/Media/Arrows/Arrow7.tga
new file mode 100644
index 0000000..f65e27c
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow7.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow70.tga b/ElvUI/Media/Arrows/Arrow70.tga
new file mode 100644
index 0000000..bb8bd71
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow70.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow71.tga b/ElvUI/Media/Arrows/Arrow71.tga
new file mode 100644
index 0000000..f37fe5e
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow71.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow72.tga b/ElvUI/Media/Arrows/Arrow72.tga
new file mode 100644
index 0000000..ce8d7ab
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow72.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow8.tga b/ElvUI/Media/Arrows/Arrow8.tga
new file mode 100644
index 0000000..535fe79
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow8.tga differ
diff --git a/ElvUI/Media/Arrows/Arrow9.tga b/ElvUI/Media/Arrows/Arrow9.tga
new file mode 100644
index 0000000..fd8791b
Binary files /dev/null and b/ElvUI/Media/Arrows/Arrow9.tga differ
diff --git a/ElvUI/Media/Arrows/ArrowRed.tga b/ElvUI/Media/Arrows/ArrowRed.tga
new file mode 100644
index 0000000..fe22ec8
Binary files /dev/null and b/ElvUI/Media/Arrows/ArrowRed.tga differ
diff --git a/ElvUI/Media/Arrows/OldArrow2.tga b/ElvUI/Media/Arrows/OldArrow2.tga
new file mode 100644
index 0000000..20fcf76
Binary files /dev/null and b/ElvUI/Media/Arrows/OldArrow2.tga differ
diff --git a/ElvUI/Media/Arrows/RLArrow.tga b/ElvUI/Media/Arrows/RLArrow.tga
new file mode 100644
index 0000000..3607826
Binary files /dev/null and b/ElvUI/Media/Arrows/RLArrow.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Angry.tga b/ElvUI/Media/ChatEmojis/Angry.tga
new file mode 100644
index 0000000..b29f721
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Angry.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Blush.tga b/ElvUI/Media/ChatEmojis/Blush.tga
new file mode 100644
index 0000000..9b62dcd
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Blush.tga differ
diff --git a/ElvUI/Media/ChatEmojis/BrokenHeart.tga b/ElvUI/Media/ChatEmojis/BrokenHeart.tga
new file mode 100644
index 0000000..f4bf1a9
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/BrokenHeart.tga differ
diff --git a/ElvUI/Media/ChatEmojis/CallMe.tga b/ElvUI/Media/ChatEmojis/CallMe.tga
new file mode 100644
index 0000000..5823f3a
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/CallMe.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Cry.tga b/ElvUI/Media/ChatEmojis/Cry.tga
new file mode 100644
index 0000000..7e50fe1
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Cry.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Facepalm.tga b/ElvUI/Media/ChatEmojis/Facepalm.tga
new file mode 100644
index 0000000..a5b5e2d
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Facepalm.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Grin.tga b/ElvUI/Media/ChatEmojis/Grin.tga
new file mode 100644
index 0000000..5224a55
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Grin.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Heart.tga b/ElvUI/Media/ChatEmojis/Heart.tga
new file mode 100644
index 0000000..263efe1
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Heart.tga differ
diff --git a/ElvUI/Media/ChatEmojis/HeartEyes.tga b/ElvUI/Media/ChatEmojis/HeartEyes.tga
new file mode 100644
index 0000000..869f9ed
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/HeartEyes.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Joy.tga b/ElvUI/Media/ChatEmojis/Joy.tga
new file mode 100644
index 0000000..08bef7d
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Joy.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Kappa.tga b/ElvUI/Media/ChatEmojis/Kappa.tga
new file mode 100644
index 0000000..7ec7cb3
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Kappa.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Meaw.tga b/ElvUI/Media/ChatEmojis/Meaw.tga
new file mode 100644
index 0000000..dc71ace
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Meaw.tga differ
diff --git a/ElvUI/Media/ChatEmojis/MiddleFinger.tga b/ElvUI/Media/ChatEmojis/MiddleFinger.tga
new file mode 100644
index 0000000..810f94b
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/MiddleFinger.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Murloc.tga b/ElvUI/Media/ChatEmojis/Murloc.tga
new file mode 100644
index 0000000..6febe49
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Murloc.tga differ
diff --git a/ElvUI/Media/ChatEmojis/OkHand.tga b/ElvUI/Media/ChatEmojis/OkHand.tga
new file mode 100644
index 0000000..b530bd4
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/OkHand.tga differ
diff --git a/ElvUI/Media/ChatEmojis/OpenMouth.tga b/ElvUI/Media/ChatEmojis/OpenMouth.tga
new file mode 100644
index 0000000..85cf529
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/OpenMouth.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Poop.tga b/ElvUI/Media/ChatEmojis/Poop.tga
new file mode 100644
index 0000000..f36d95d
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Poop.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Rage.tga b/ElvUI/Media/ChatEmojis/Rage.tga
new file mode 100644
index 0000000..ce6aa56
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Rage.tga differ
diff --git a/ElvUI/Media/ChatEmojis/SadKitty.tga b/ElvUI/Media/ChatEmojis/SadKitty.tga
new file mode 100644
index 0000000..e55ec05
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/SadKitty.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Scream.tga b/ElvUI/Media/ChatEmojis/Scream.tga
new file mode 100644
index 0000000..8d2f06d
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Scream.tga differ
diff --git a/ElvUI/Media/ChatEmojis/ScreamCat.tga b/ElvUI/Media/ChatEmojis/ScreamCat.tga
new file mode 100644
index 0000000..f40b291
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/ScreamCat.tga differ
diff --git a/ElvUI/Media/ChatEmojis/SemiColon.tga b/ElvUI/Media/ChatEmojis/SemiColon.tga
new file mode 100644
index 0000000..43e1180
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/SemiColon.tga differ
diff --git a/ElvUI/Media/ChatEmojis/SlightFrown.tga b/ElvUI/Media/ChatEmojis/SlightFrown.tga
new file mode 100644
index 0000000..cc0f409
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/SlightFrown.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Smile.tga b/ElvUI/Media/ChatEmojis/Smile.tga
new file mode 100644
index 0000000..5c0e3db
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Smile.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Smirk.tga b/ElvUI/Media/ChatEmojis/Smirk.tga
new file mode 100644
index 0000000..5c5719c
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Smirk.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Sob.tga b/ElvUI/Media/ChatEmojis/Sob.tga
new file mode 100644
index 0000000..73cb03b
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Sob.tga differ
diff --git a/ElvUI/Media/ChatEmojis/StuckOutTongue.tga b/ElvUI/Media/ChatEmojis/StuckOutTongue.tga
new file mode 100644
index 0000000..7f07ce8
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/StuckOutTongue.tga differ
diff --git a/ElvUI/Media/ChatEmojis/StuckOutTongueClosedEyes.tga b/ElvUI/Media/ChatEmojis/StuckOutTongueClosedEyes.tga
new file mode 100644
index 0000000..4bec52b
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/StuckOutTongueClosedEyes.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Sunglasses.tga b/ElvUI/Media/ChatEmojis/Sunglasses.tga
new file mode 100644
index 0000000..ebbbf9c
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Sunglasses.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Thinking.tga b/ElvUI/Media/ChatEmojis/Thinking.tga
new file mode 100644
index 0000000..3de2167
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Thinking.tga differ
diff --git a/ElvUI/Media/ChatEmojis/ThumbsUp.tga b/ElvUI/Media/ChatEmojis/ThumbsUp.tga
new file mode 100644
index 0000000..45a7582
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/ThumbsUp.tga differ
diff --git a/ElvUI/Media/ChatEmojis/Wink.tga b/ElvUI/Media/ChatEmojis/Wink.tga
new file mode 100644
index 0000000..437310a
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/Wink.tga differ
diff --git a/ElvUI/Media/ChatEmojis/ZZZ.tga b/ElvUI/Media/ChatEmojis/ZZZ.tga
new file mode 100644
index 0000000..33b6a81
Binary files /dev/null and b/ElvUI/Media/ChatEmojis/ZZZ.tga differ
diff --git a/ElvUI/Media/ChatLogos/Bathrobe.tga b/ElvUI/Media/ChatLogos/Bathrobe.tga
new file mode 100644
index 0000000..c60c6ed
Binary files /dev/null and b/ElvUI/Media/ChatLogos/Bathrobe.tga differ
diff --git a/ElvUI/Media/ChatLogos/ElvBlue.tga b/ElvUI/Media/ChatLogos/ElvBlue.tga
new file mode 100644
index 0000000..0429ff5
Binary files /dev/null and b/ElvUI/Media/ChatLogos/ElvBlue.tga differ
diff --git a/ElvUI/Media/ChatLogos/ElvGreen.tga b/ElvUI/Media/ChatLogos/ElvGreen.tga
new file mode 100644
index 0000000..2101844
Binary files /dev/null and b/ElvUI/Media/ChatLogos/ElvGreen.tga differ
diff --git a/ElvUI/Media/ChatLogos/ElvMelon.tga b/ElvUI/Media/ChatLogos/ElvMelon.tga
new file mode 100644
index 0000000..ca6ef65
Binary files /dev/null and b/ElvUI/Media/ChatLogos/ElvMelon.tga differ
diff --git a/ElvUI/Media/ChatLogos/ElvOrange.tga b/ElvUI/Media/ChatLogos/ElvOrange.tga
new file mode 100644
index 0000000..096dd74
Binary files /dev/null and b/ElvUI/Media/ChatLogos/ElvOrange.tga differ
diff --git a/ElvUI/Media/ChatLogos/ElvPink.tga b/ElvUI/Media/ChatLogos/ElvPink.tga
new file mode 100644
index 0000000..f269b54
Binary files /dev/null and b/ElvUI/Media/ChatLogos/ElvPink.tga differ
diff --git a/ElvUI/Media/ChatLogos/ElvPurple.tga b/ElvUI/Media/ChatLogos/ElvPurple.tga
new file mode 100644
index 0000000..2cdd5a9
Binary files /dev/null and b/ElvUI/Media/ChatLogos/ElvPurple.tga differ
diff --git a/ElvUI/Media/ChatLogos/ElvRainbow.tga b/ElvUI/Media/ChatLogos/ElvRainbow.tga
new file mode 100644
index 0000000..35430a7
Binary files /dev/null and b/ElvUI/Media/ChatLogos/ElvRainbow.tga differ
diff --git a/ElvUI/Media/ChatLogos/ElvRed.tga b/ElvUI/Media/ChatLogos/ElvRed.tga
new file mode 100644
index 0000000..55ddb47
Binary files /dev/null and b/ElvUI/Media/ChatLogos/ElvRed.tga differ
diff --git a/ElvUI/Media/ChatLogos/ElvYellow.tga b/ElvUI/Media/ChatLogos/ElvYellow.tga
new file mode 100644
index 0000000..d12e652
Binary files /dev/null and b/ElvUI/Media/ChatLogos/ElvYellow.tga differ
diff --git a/ElvUI/Media/ChatLogos/HelloKitty.tga b/ElvUI/Media/ChatLogos/HelloKitty.tga
new file mode 100644
index 0000000..9a29fcb
Binary files /dev/null and b/ElvUI/Media/ChatLogos/HelloKitty.tga differ
diff --git a/ElvUI/Media/ChatLogos/Illuminati.tga b/ElvUI/Media/ChatLogos/Illuminati.tga
new file mode 100644
index 0000000..a4daa55
Binary files /dev/null and b/ElvUI/Media/ChatLogos/Illuminati.tga differ
diff --git a/ElvUI/Media/ChatLogos/MrHankey.tga b/ElvUI/Media/ChatLogos/MrHankey.tga
new file mode 100644
index 0000000..0c23946
Binary files /dev/null and b/ElvUI/Media/ChatLogos/MrHankey.tga differ
diff --git a/ElvUI/Media/ChatLogos/Rainbow.tga b/ElvUI/Media/ChatLogos/Rainbow.tga
new file mode 100644
index 0000000..96f7e20
Binary files /dev/null and b/ElvUI/Media/ChatLogos/Rainbow.tga differ
diff --git a/ElvUI/Media/ChatLogos/TyroneBiggums.tga b/ElvUI/Media/ChatLogos/TyroneBiggums.tga
new file mode 100644
index 0000000..bc40f34
Binary files /dev/null and b/ElvUI/Media/ChatLogos/TyroneBiggums.tga differ
diff --git a/ElvUI/Media/Fonts/ActionMan.ttf b/ElvUI/Media/Fonts/ActionMan.ttf
new file mode 100644
index 0000000..4663bf9
Binary files /dev/null and b/ElvUI/Media/Fonts/ActionMan.ttf differ
diff --git a/ElvUI/Media/Fonts/ContinuumMedium.ttf b/ElvUI/Media/Fonts/ContinuumMedium.ttf
new file mode 100644
index 0000000..08c8df8
Binary files /dev/null and b/ElvUI/Media/Fonts/ContinuumMedium.ttf differ
diff --git a/ElvUI/Media/Fonts/DieDieDie.ttf b/ElvUI/Media/Fonts/DieDieDie.ttf
new file mode 100644
index 0000000..ba2936e
Binary files /dev/null and b/ElvUI/Media/Fonts/DieDieDie.ttf differ
diff --git a/ElvUI/Media/Fonts/Expressway.ttf b/ElvUI/Media/Fonts/Expressway.ttf
new file mode 100644
index 0000000..d295ee2
Binary files /dev/null and b/ElvUI/Media/Fonts/Expressway.ttf differ
diff --git a/ElvUI/Media/Fonts/Homespun.ttf b/ElvUI/Media/Fonts/Homespun.ttf
new file mode 100644
index 0000000..2f3eb9e
Binary files /dev/null and b/ElvUI/Media/Fonts/Homespun.ttf differ
diff --git a/ElvUI/Media/Fonts/Invisible.ttf b/ElvUI/Media/Fonts/Invisible.ttf
new file mode 100644
index 0000000..39748bc
Binary files /dev/null and b/ElvUI/Media/Fonts/Invisible.ttf differ
diff --git a/ElvUI/Media/Fonts/PTSansNarrow.ttf b/ElvUI/Media/Fonts/PTSansNarrow.ttf
new file mode 100644
index 0000000..30a67b8
Binary files /dev/null and b/ElvUI/Media/Fonts/PTSansNarrow.ttf differ
diff --git a/ElvUI/Media/Load_Media.xml b/ElvUI/Media/Load_Media.xml
new file mode 100644
index 0000000..7c28da6
--- /dev/null
+++ b/ElvUI/Media/Load_Media.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Media/SharedMedia.lua b/ElvUI/Media/SharedMedia.lua
new file mode 100644
index 0000000..7e36112
--- /dev/null
+++ b/ElvUI/Media/SharedMedia.lua
@@ -0,0 +1,159 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local LSM = E.Libs.LSM
+local M = [[Interface\AddOns\ElvUI\Media\]]
+
+function E:TextureString(texString, dataString)
+ return "|T"..texString..(dataString or "").."|t"
+end
+
+E.Media = {
+ Fonts = {
+ ActionMan = M..[[Fonts\ActionMan.ttf]],
+ ContinuumMedium = M..[[Fonts\ContinuumMedium.ttf]],
+ DieDieDie = M..[[Fonts\DieDieDie.ttf]],
+ Expressway = M..[[Fonts\Expressway.ttf]],
+ Homespun = M..[[Fonts\Homespun.ttf]],
+ Invisible = M..[[Fonts\Invisible.ttf]],
+ PTSansNarrow = M..[[Fonts\PTSansNarrow.ttf]]
+ },
+ Sounds = {
+ AwwCrap = M..[[Sounds\AwwCrap.ogg]],
+ BbqAss = M..[[Sounds\BbqAss.ogg]],
+ DumbShit = M..[[Sounds\DumbShit.ogg]],
+ HarlemShake = M..[[Sounds\HarlemShake.ogg]],
+ HelloKitty = M..[[Sounds\HelloKitty.ogg]],
+ MamaWeekends = M..[[Sounds\MamaWeekends.ogg]],
+ RunFast = M..[[Sounds\RunFast.ogg]],
+ ElvUIAska = M..[[Sounds\SndIncMsg.ogg]],
+ StopRunningSlimeBall = M..[[Sounds\StopRunningSlimeBall.ogg]],
+ Warning = M..[[Sounds\Warning.ogg]],
+ Whisper = M..[[Sounds\Whisper.ogg]],
+ YankieBangBang = M..[[Sounds\YankieBangBang.ogg]]
+ },
+ ChatEmojis = {
+ Angry = M..[[ChatEmojis\Angry.tga]],
+ Blush = M..[[ChatEmojis\Blush.tga]],
+ BrokenHeart = M..[[ChatEmojis\BrokenHeart.tga]],
+ CallMe = M..[[ChatEmojis\CallMe.tga]],
+ Cry = M..[[ChatEmojis\Cry.tga]],
+ Facepalm = M..[[ChatEmojis\Facepalm.tga]],
+ Grin = M..[[ChatEmojis\Grin.tga]],
+ Heart = M..[[ChatEmojis\Heart.tga]],
+ HeartEyes = M..[[ChatEmojis\HeartEyes.tga]],
+ Joy = M..[[ChatEmojis\Joy.tga]],
+ Kappa = M..[[ChatEmojis\Kappa.tga]],
+ Meaw = M..[[ChatEmojis\Meaw.tga]],
+ MiddleFinger = M..[[ChatEmojis\MiddleFinger.tga]],
+ Murloc = M..[[ChatEmojis\Murloc.tga]],
+ OkHand = M..[[ChatEmojis\OkHand.tga]],
+ OpenMouth = M..[[ChatEmojis\OpenMouth.tga]],
+ Poop = M..[[ChatEmojis\Poop.tga]],
+ Rage = M..[[ChatEmojis\Rage.tga]],
+ SadKitty = M..[[ChatEmojis\SadKitty.tga]],
+ Scream = M..[[ChatEmojis\Scream.tga]],
+ ScreamCat = M..[[ChatEmojis\ScreamCat.tga]],
+ SemiColon = M..[[ChatEmojis\SemiColon.tga]],
+ SlightFrown = M..[[ChatEmojis\SlightFrown.tga]],
+ Smile = M..[[ChatEmojis\Smile.tga]],
+ Smirk = M..[[ChatEmojis\Smirk.tga]],
+ Sob = M..[[ChatEmojis\Sob.tga]],
+ StuckOutTongue = M..[[ChatEmojis\StuckOutTongue.tga]],
+ StuckOutTongueClosedEyes = M..[[ChatEmojis\StuckOutTongueClosedEyes.tga]],
+ Sunglasses = M..[[ChatEmojis\Sunglasses.tga]],
+ Thinking = M..[[ChatEmojis\Thinking.tga]],
+ ThumbsUp = M..[[ChatEmojis\ThumbsUp.tga]],
+ Wink = M..[[ChatEmojis\Wink.tga]],
+ ZZZ = M..[[ChatEmojis\ZZZ.tga]]
+ },
+ ChatLogos = {
+ ElvRainbow = M..[[ChatLogos\ElvRainbow.tga]],
+ ElvMelon = M..[[ChatLogos\ElvMelon.tga]],
+ ElvBlue = M..[[ChatLogos\ElvBlue.tga]],
+ ElvGreen = M..[[ChatLogos\ElvGreen.tga]],
+ ElvOrange = M..[[ChatLogos\ElvOrange.tga]],
+ ElvPink = M..[[ChatLogos\ElvPink.tga]],
+ ElvPurple = M..[[ChatLogos\ElvPurple.tga]],
+ ElvYellow = M..[[ChatLogos\ElvYellow.tga]],
+ ElvRed = M..[[ChatLogos\ElvRed.tga]],
+ Bathrobe = M..[[ChatLogos\Bathrobe.tga]],
+ HelloKitty = M..[[ChatLogos\HelloKitty.tga]],
+ Illuminati = M..[[ChatLogos\Illuminati.tga]],
+ MrHankey = M..[[ChatLogos\MrHankey.tga]],
+ Rainbow = M..[[ChatLogos\Rainbow.tga]],
+ TyroneBiggums = M..[[ChatLogos\TyroneBiggums.tga]]
+ },
+ Textures = {
+ AllianceLogo = M..[[Textures\Alliance-Logo.blp]],
+ Arrow = M..[[Textures\Arrow.tga]],
+ ArrowRight = M..[[Textures\ArrowRight.tga]],
+ ArrowUp = M..[[Textures\ArrowUp.tga]],
+ BagJunkIcon = M..[[Textures\BagJunkIcon.blp]],
+ BagQuestIcon = M..[[Textures\BagQuestIcon.tga]],
+ Black8x8 = M..[[Textures\Black8x8.tga]],
+ White8x8 = [[Interface\BUTTONS\WHITE8X8]], -- not elvui
+ Broom = M..[[Textures\Broom.blp]],
+ ChatEmojis = M..[[Textures\ChatEmojis]],
+ ChatLogos = M..[[Textures\ChatLogos]],
+ Close = M..[[Textures\Close.tga]],
+ Combat = M..[[Textures\Combat.tga]],
+ Copy = M..[[Textures\Copy.tga]],
+ Cross = M..[[Textures\Cross.tga]],
+ DPS = M..[[Textures\DPS.tga]],
+ GlowTex = M..[[Textures\GlowTex.tga]],
+ Healer = M..[[Textures\Healer.tga]],
+ HelloKitty = M..[[Textures\HelloKitty.tga]],
+ HelloKittyChat = M..[[Textures\HelloKittyChat.tga]],
+ Highlight = M..[[Textures\Highlight.tga]],
+ HordeLogo = M..[[Textures\Horde-Logo.blp]],
+ Leader = M..[[Textures\Leader.tga]],
+ LevelUpTex = M..[[Textures\LevelUpTex.blp]],
+ Logo = M..[[Textures\Logo.tga]],
+ Mail = M..[[Textures\Mail.tga]],
+ Melli = M..[[Textures\Melli.tga]],
+ Minimalist = M..[[Textures\Minimalist.tga]],
+ Minus = M..[[Textures\Minus.tga]],
+ MinusButton = M..[[Textures\MinusButton.tga]],
+ Nameplates = M..[[Textures\Nameplates.blp]],
+ NormTex = M..[[Textures\NormTex.tga]],
+ NormTex2 = M..[[Textures\NormTex2.tga]],
+ Pause = M..[[Textures\Pause.tga]],
+ Play = M..[[Textures\Play.tga]],
+ Plus = M..[[Textures\Plus.tga]],
+ PlusButton = M..[[Textures\PlusButton.tga]],
+ PvPIcons = M..[[Textures\PVP-Icons.blp]],
+ RaidIcons = M..[[Textures\RaidIcons.blp]],
+ Reset = M..[[Textures\Reset.tga]],
+ Resting = M..[[Textures\Resting.tga]],
+ Resting1 = M..[[Textures\Resting1.tga]],
+ RoleIcons = M..[[Textures\RoleIcons.tga]],
+ SkullIcon = M..[[Textures\SkullIcon.tga]],
+ Smooth = M..[[Textures\Smooth.tga]],
+ Spark = M..[[Textures\Spark.tga]],
+ Tank = M..[[Textures\Tank.tga]],
+ ExitVehicle = M..[[Textures\ExitVehicle.tga]]
+ }
+}
+
+LSM:Register("border", "ElvUI GlowBorder", E.Media.Textures.GlowTex)
+LSM:Register("font", "Continuum Medium", E.Media.Fonts.ContinuumMedium)
+LSM:Register("font", "Die Die Die!", E.Media.Fonts.DieDieDie, LSM.LOCALE_BIT_ruRU + LSM.LOCALE_BIT_western)
+LSM:Register("font", "Action Man", E.Media.Fonts.ActionMan)
+LSM:Register("font", "Expressway", E.Media.Fonts.Expressway, LSM.LOCALE_BIT_ruRU + LSM.LOCALE_BIT_western)
+LSM:Register("font", "PT Sans Narrow", E.Media.Fonts.PTSansNarrow, LSM.LOCALE_BIT_ruRU + LSM.LOCALE_BIT_western)
+LSM:Register("font", "Homespun", E.Media.Fonts.Homespun, LSM.LOCALE_BIT_ruRU + LSM.LOCALE_BIT_western)
+LSM:Register("sound", "ElvUI Aska", E.Media.Sounds.SndIncMsg)
+LSM:Register("sound", "Awww Crap", E.Media.Sounds.AwwCrap)
+LSM:Register("sound", "BBQ Ass", E.Media.Sounds.BbqAss)
+LSM:Register("sound", "Big Yankie Devil", E.Media.Sounds.YankieBangBang)
+LSM:Register("sound", "Dumb Shit", E.Media.Sounds.DumbShit)
+LSM:Register("sound", "Mama Weekends", E.Media.Sounds.MamaWeekends)
+LSM:Register("sound", "Runaway Fast", E.Media.Sounds.RunFast)
+LSM:Register("sound", "Stop Running", E.Media.Sounds.StopRunningSlimeBall)
+LSM:Register("sound", "Warning", E.Media.Sounds.Warning)
+LSM:Register("sound", "Whisper Alert", E.Media.Sounds.Whisper)
+LSM:Register("statusbar", "Melli", E.Media.Textures.Melli)
+LSM:Register("statusbar", "ElvUI Gloss", E.Media.Textures.NormTex)
+LSM:Register("statusbar", "ElvUI Norm", E.Media.Textures.NormTex2)
+LSM:Register("statusbar", "Minimalist", E.Media.Textures.Minimalist)
+LSM:Register("statusbar", "ElvUI Blank", E.Media.Textures.White8x8)
+LSM:Register("background", "ElvUI Blank", E.Media.Textures.White8x8)
\ No newline at end of file
diff --git a/ElvUI/Media/Sounds/AwwCrap.ogg b/ElvUI/Media/Sounds/AwwCrap.ogg
new file mode 100644
index 0000000..91a9136
Binary files /dev/null and b/ElvUI/Media/Sounds/AwwCrap.ogg differ
diff --git a/ElvUI/Media/Sounds/BbqAss.ogg b/ElvUI/Media/Sounds/BbqAss.ogg
new file mode 100644
index 0000000..ed28e17
Binary files /dev/null and b/ElvUI/Media/Sounds/BbqAss.ogg differ
diff --git a/ElvUI/Media/Sounds/DumbShit.ogg b/ElvUI/Media/Sounds/DumbShit.ogg
new file mode 100644
index 0000000..5d1f2e7
Binary files /dev/null and b/ElvUI/Media/Sounds/DumbShit.ogg differ
diff --git a/ElvUI/Media/Sounds/HarlemShake.ogg b/ElvUI/Media/Sounds/HarlemShake.ogg
new file mode 100644
index 0000000..ebe4fd6
Binary files /dev/null and b/ElvUI/Media/Sounds/HarlemShake.ogg differ
diff --git a/ElvUI/Media/Sounds/HelloKitty.ogg b/ElvUI/Media/Sounds/HelloKitty.ogg
new file mode 100644
index 0000000..9d3a2f8
Binary files /dev/null and b/ElvUI/Media/Sounds/HelloKitty.ogg differ
diff --git a/ElvUI/Media/Sounds/MamaWeekends.ogg b/ElvUI/Media/Sounds/MamaWeekends.ogg
new file mode 100644
index 0000000..8c8995b
Binary files /dev/null and b/ElvUI/Media/Sounds/MamaWeekends.ogg differ
diff --git a/ElvUI/Media/Sounds/RunFast.ogg b/ElvUI/Media/Sounds/RunFast.ogg
new file mode 100644
index 0000000..715f4c1
Binary files /dev/null and b/ElvUI/Media/Sounds/RunFast.ogg differ
diff --git a/ElvUI/Media/Sounds/SndIncMsg.ogg b/ElvUI/Media/Sounds/SndIncMsg.ogg
new file mode 100644
index 0000000..f105002
Binary files /dev/null and b/ElvUI/Media/Sounds/SndIncMsg.ogg differ
diff --git a/ElvUI/Media/Sounds/StopRunningSlimBall.ogg b/ElvUI/Media/Sounds/StopRunningSlimBall.ogg
new file mode 100644
index 0000000..2d9d670
Binary files /dev/null and b/ElvUI/Media/Sounds/StopRunningSlimBall.ogg differ
diff --git a/ElvUI/Media/Sounds/Warning.ogg b/ElvUI/Media/Sounds/Warning.ogg
new file mode 100644
index 0000000..1d07d8b
Binary files /dev/null and b/ElvUI/Media/Sounds/Warning.ogg differ
diff --git a/ElvUI/Media/Sounds/Whisper.ogg b/ElvUI/Media/Sounds/Whisper.ogg
new file mode 100644
index 0000000..2079476
Binary files /dev/null and b/ElvUI/Media/Sounds/Whisper.ogg differ
diff --git a/ElvUI/Media/Sounds/YankieBangBang.ogg b/ElvUI/Media/Sounds/YankieBangBang.ogg
new file mode 100644
index 0000000..7392204
Binary files /dev/null and b/ElvUI/Media/Sounds/YankieBangBang.ogg differ
diff --git a/ElvUI/Media/Textures/Alliance-Logo-Small.blp b/ElvUI/Media/Textures/Alliance-Logo-Small.blp
new file mode 100644
index 0000000..23811c9
Binary files /dev/null and b/ElvUI/Media/Textures/Alliance-Logo-Small.blp differ
diff --git a/ElvUI/Media/Textures/Alliance-Logo.blp b/ElvUI/Media/Textures/Alliance-Logo.blp
new file mode 100644
index 0000000..e6218ff
Binary files /dev/null and b/ElvUI/Media/Textures/Alliance-Logo.blp differ
diff --git a/ElvUI/Media/Textures/ArrowRight.tga b/ElvUI/Media/Textures/ArrowRight.tga
new file mode 100644
index 0000000..4225b80
Binary files /dev/null and b/ElvUI/Media/Textures/ArrowRight.tga differ
diff --git a/ElvUI/Media/Textures/BagJunkIcon.blp b/ElvUI/Media/Textures/BagJunkIcon.blp
new file mode 100644
index 0000000..e525f15
Binary files /dev/null and b/ElvUI/Media/Textures/BagJunkIcon.blp differ
diff --git a/ElvUI/Media/Textures/Black8x8.tga b/ElvUI/Media/Textures/Black8x8.tga
new file mode 100644
index 0000000..bc9440e
Binary files /dev/null and b/ElvUI/Media/Textures/Black8x8.tga differ
diff --git a/ElvUI/Media/Textures/Broom.blp b/ElvUI/Media/Textures/Broom.blp
new file mode 100644
index 0000000..964469a
Binary files /dev/null and b/ElvUI/Media/Textures/Broom.blp differ
diff --git a/ElvUI/Media/Textures/ExitVehicle.tga b/ElvUI/Media/Textures/ExitVehicle.tga
new file mode 100644
index 0000000..c42dde8
Binary files /dev/null and b/ElvUI/Media/Textures/ExitVehicle.tga differ
diff --git a/ElvUI/Media/Textures/HelloKitty.tga b/ElvUI/Media/Textures/HelloKitty.tga
new file mode 100644
index 0000000..119791e
Binary files /dev/null and b/ElvUI/Media/Textures/HelloKitty.tga differ
diff --git a/ElvUI/Media/Textures/Highlight.tga b/ElvUI/Media/Textures/Highlight.tga
new file mode 100644
index 0000000..5602c05
Binary files /dev/null and b/ElvUI/Media/Textures/Highlight.tga differ
diff --git a/ElvUI/Media/Textures/Horde-Logo-Small.blp b/ElvUI/Media/Textures/Horde-Logo-Small.blp
new file mode 100644
index 0000000..f27f974
Binary files /dev/null and b/ElvUI/Media/Textures/Horde-Logo-Small.blp differ
diff --git a/ElvUI/Media/Textures/Horde-Logo.blp b/ElvUI/Media/Textures/Horde-Logo.blp
new file mode 100644
index 0000000..2c489da
Binary files /dev/null and b/ElvUI/Media/Textures/Horde-Logo.blp differ
diff --git a/ElvUI/Media/Textures/Leader.tga b/ElvUI/Media/Textures/Leader.tga
new file mode 100644
index 0000000..8257cf1
Binary files /dev/null and b/ElvUI/Media/Textures/Leader.tga differ
diff --git a/ElvUI/Media/Textures/LevelUpTex.blp b/ElvUI/Media/Textures/LevelUpTex.blp
new file mode 100644
index 0000000..2d8f34a
Binary files /dev/null and b/ElvUI/Media/Textures/LevelUpTex.blp differ
diff --git a/ElvUI/Media/Textures/Melli.tga b/ElvUI/Media/Textures/Melli.tga
new file mode 100644
index 0000000..d2677ca
Binary files /dev/null and b/ElvUI/Media/Textures/Melli.tga differ
diff --git a/ElvUI/Media/Textures/Minimalist.tga b/ElvUI/Media/Textures/Minimalist.tga
new file mode 100644
index 0000000..2748468
Binary files /dev/null and b/ElvUI/Media/Textures/Minimalist.tga differ
diff --git a/ElvUI/Media/Textures/Minus.tga b/ElvUI/Media/Textures/Minus.tga
new file mode 100644
index 0000000..9d4b331
Binary files /dev/null and b/ElvUI/Media/Textures/Minus.tga differ
diff --git a/ElvUI/Media/Textures/MinusButton.tga b/ElvUI/Media/Textures/MinusButton.tga
new file mode 100644
index 0000000..f5a004c
Binary files /dev/null and b/ElvUI/Media/Textures/MinusButton.tga differ
diff --git a/ElvUI/Media/Textures/PVP-Icons.blp b/ElvUI/Media/Textures/PVP-Icons.blp
new file mode 100644
index 0000000..4a99fb8
Binary files /dev/null and b/ElvUI/Media/Textures/PVP-Icons.blp differ
diff --git a/ElvUI/Media/Textures/Pause.tga b/ElvUI/Media/Textures/Pause.tga
new file mode 100644
index 0000000..63b724c
Binary files /dev/null and b/ElvUI/Media/Textures/Pause.tga differ
diff --git a/ElvUI/Media/Textures/Play.tga b/ElvUI/Media/Textures/Play.tga
new file mode 100644
index 0000000..5d41afb
Binary files /dev/null and b/ElvUI/Media/Textures/Play.tga differ
diff --git a/ElvUI/Media/Textures/Plus.tga b/ElvUI/Media/Textures/Plus.tga
new file mode 100644
index 0000000..eb2dde6
Binary files /dev/null and b/ElvUI/Media/Textures/Plus.tga differ
diff --git a/ElvUI/Media/Textures/PlusButton.tga b/ElvUI/Media/Textures/PlusButton.tga
new file mode 100644
index 0000000..e043999
Binary files /dev/null and b/ElvUI/Media/Textures/PlusButton.tga differ
diff --git a/ElvUI/Media/Textures/Raid-Icon-Rez.blp b/ElvUI/Media/Textures/Raid-Icon-Rez.blp
new file mode 100644
index 0000000..1d956c2
Binary files /dev/null and b/ElvUI/Media/Textures/Raid-Icon-Rez.blp differ
diff --git a/ElvUI/Media/Textures/Reset.tga b/ElvUI/Media/Textures/Reset.tga
new file mode 100644
index 0000000..e18e705
Binary files /dev/null and b/ElvUI/Media/Textures/Reset.tga differ
diff --git a/ElvUI/Media/Textures/Resting1.tga b/ElvUI/Media/Textures/Resting1.tga
new file mode 100644
index 0000000..7780ae3
Binary files /dev/null and b/ElvUI/Media/Textures/Resting1.tga differ
diff --git a/ElvUI/Media/Textures/RoleIcons.tga b/ElvUI/Media/Textures/RoleIcons.tga
new file mode 100644
index 0000000..a3ecba5
Binary files /dev/null and b/ElvUI/Media/Textures/RoleIcons.tga differ
diff --git a/ElvUI/Media/Textures/SkullIcon.tga b/ElvUI/Media/Textures/SkullIcon.tga
new file mode 100644
index 0000000..e84730a
Binary files /dev/null and b/ElvUI/Media/Textures/SkullIcon.tga differ
diff --git a/ElvUI/Media/Textures/Smooth.tga b/ElvUI/Media/Textures/Smooth.tga
new file mode 100644
index 0000000..9c18f2b
Binary files /dev/null and b/ElvUI/Media/Textures/Smooth.tga differ
diff --git a/ElvUI/Media/Textures/StreamBackground.blp b/ElvUI/Media/Textures/StreamBackground.blp
new file mode 100644
index 0000000..ce9a62d
Binary files /dev/null and b/ElvUI/Media/Textures/StreamBackground.blp differ
diff --git a/ElvUI/Media/Textures/StreamCircle.blp b/ElvUI/Media/Textures/StreamCircle.blp
new file mode 100644
index 0000000..9cc9d06
Binary files /dev/null and b/ElvUI/Media/Textures/StreamCircle.blp differ
diff --git a/ElvUI/Media/Textures/StreamFrame.blp b/ElvUI/Media/Textures/StreamFrame.blp
new file mode 100644
index 0000000..c1f14cf
Binary files /dev/null and b/ElvUI/Media/Textures/StreamFrame.blp differ
diff --git a/ElvUI/Media/Textures/StreamSpark.blp b/ElvUI/Media/Textures/StreamSpark.blp
new file mode 100644
index 0000000..c9e39a8
Binary files /dev/null and b/ElvUI/Media/Textures/StreamSpark.blp differ
diff --git a/ElvUI/Media/Textures/arrow.tga b/ElvUI/Media/Textures/arrow.tga
new file mode 100644
index 0000000..23acdab
Binary files /dev/null and b/ElvUI/Media/Textures/arrow.tga differ
diff --git a/ElvUI/Media/Textures/arrowup.tga b/ElvUI/Media/Textures/arrowup.tga
new file mode 100644
index 0000000..828386c
Binary files /dev/null and b/ElvUI/Media/Textures/arrowup.tga differ
diff --git a/ElvUI/Media/Textures/bagQuestIcon.tga b/ElvUI/Media/Textures/bagQuestIcon.tga
new file mode 100644
index 0000000..37da839
Binary files /dev/null and b/ElvUI/Media/Textures/bagQuestIcon.tga differ
diff --git a/ElvUI/Media/Textures/close.tga b/ElvUI/Media/Textures/close.tga
new file mode 100644
index 0000000..ceb4017
Binary files /dev/null and b/ElvUI/Media/Textures/close.tga differ
diff --git a/ElvUI/Media/Textures/combat.tga b/ElvUI/Media/Textures/combat.tga
new file mode 100644
index 0000000..35fb4d0
Binary files /dev/null and b/ElvUI/Media/Textures/combat.tga differ
diff --git a/ElvUI/Media/Textures/copy.tga b/ElvUI/Media/Textures/copy.tga
new file mode 100644
index 0000000..d04ad68
Binary files /dev/null and b/ElvUI/Media/Textures/copy.tga differ
diff --git a/ElvUI/Media/Textures/cross.tga b/ElvUI/Media/Textures/cross.tga
new file mode 100644
index 0000000..e26def2
Binary files /dev/null and b/ElvUI/Media/Textures/cross.tga differ
diff --git a/ElvUI/Media/Textures/dps.tga b/ElvUI/Media/Textures/dps.tga
new file mode 100644
index 0000000..2fc2497
Binary files /dev/null and b/ElvUI/Media/Textures/dps.tga differ
diff --git a/ElvUI/Media/Textures/glowTex.tga b/ElvUI/Media/Textures/glowTex.tga
new file mode 100644
index 0000000..0f123b6
Binary files /dev/null and b/ElvUI/Media/Textures/glowTex.tga differ
diff --git a/ElvUI/Media/Textures/healer.tga b/ElvUI/Media/Textures/healer.tga
new file mode 100644
index 0000000..e453a0e
Binary files /dev/null and b/ElvUI/Media/Textures/healer.tga differ
diff --git a/ElvUI/Media/Textures/helloKittyChat.tga b/ElvUI/Media/Textures/helloKittyChat.tga
new file mode 100644
index 0000000..20b03ab
Binary files /dev/null and b/ElvUI/Media/Textures/helloKittyChat.tga differ
diff --git a/ElvUI/Media/Textures/logo.tga b/ElvUI/Media/Textures/logo.tga
new file mode 100644
index 0000000..4175ebc
Binary files /dev/null and b/ElvUI/Media/Textures/logo.tga differ
diff --git a/ElvUI/Media/Textures/mail.tga b/ElvUI/Media/Textures/mail.tga
new file mode 100644
index 0000000..812719f
Binary files /dev/null and b/ElvUI/Media/Textures/mail.tga differ
diff --git a/ElvUI/Media/Textures/nameplates.BLP b/ElvUI/Media/Textures/nameplates.BLP
new file mode 100644
index 0000000..2079d3b
Binary files /dev/null and b/ElvUI/Media/Textures/nameplates.BLP differ
diff --git a/ElvUI/Media/Textures/normTex.tga b/ElvUI/Media/Textures/normTex.tga
new file mode 100644
index 0000000..5024f71
Binary files /dev/null and b/ElvUI/Media/Textures/normTex.tga differ
diff --git a/ElvUI/Media/Textures/normTex2.tga b/ElvUI/Media/Textures/normTex2.tga
new file mode 100644
index 0000000..9c18f2b
Binary files /dev/null and b/ElvUI/Media/Textures/normTex2.tga differ
diff --git a/ElvUI/Media/Textures/raidicons.blp b/ElvUI/Media/Textures/raidicons.blp
new file mode 100644
index 0000000..81c7f7c
Binary files /dev/null and b/ElvUI/Media/Textures/raidicons.blp differ
diff --git a/ElvUI/Media/Textures/resting.tga b/ElvUI/Media/Textures/resting.tga
new file mode 100644
index 0000000..6f4a31d
Binary files /dev/null and b/ElvUI/Media/Textures/resting.tga differ
diff --git a/ElvUI/Media/Textures/spark.tga b/ElvUI/Media/Textures/spark.tga
new file mode 100644
index 0000000..ee83b7e
Binary files /dev/null and b/ElvUI/Media/Textures/spark.tga differ
diff --git a/ElvUI/Media/Textures/tank.tga b/ElvUI/Media/Textures/tank.tga
new file mode 100644
index 0000000..a9fa112
Binary files /dev/null and b/ElvUI/Media/Textures/tank.tga differ
diff --git a/ElvUI/Modules/ActionBars/ActionBars.lua b/ElvUI/Modules/ActionBars/ActionBars.lua
new file mode 100644
index 0000000..f7c337c
--- /dev/null
+++ b/ElvUI/Modules/ActionBars/ActionBars.lua
@@ -0,0 +1,997 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local AB = E:GetModule("ActionBars")
+
+--Lua functions
+local _G = _G
+local pairs, select, unpack = pairs, select, unpack
+local ceil = math.ceil
+local format, gsub, match, split = string.format, string.gsub, string.match, string.split
+--WoW API / Variables
+local hooksecurefunc = hooksecurefunc
+local CreateFrame = CreateFrame
+local UnitHealth = UnitHealth
+local UnitHealthMax = UnitHealthMax
+local UnitCastingInfo = UnitCastingInfo
+local UnitChannelInfo = UnitChannelInfo
+local UnitAffectingCombat = UnitAffectingCombat
+local UnitExists = UnitExists
+local PetDismiss = PetDismiss
+local CanExitVehicle = CanExitVehicle
+local InCombatLockdown = InCombatLockdown
+local ClearOverrideBindings = ClearOverrideBindings
+local GetBindingKey = GetBindingKey
+local SetOverrideBindingClick = SetOverrideBindingClick
+local SetCVar = SetCVar
+local SetModifiedClick = SetModifiedClick
+local RegisterStateDriver = RegisterStateDriver
+local UnregisterStateDriver = UnregisterStateDriver
+local NUM_ACTIONBAR_BUTTONS = NUM_ACTIONBAR_BUTTONS
+local LEAVE_VEHICLE = LEAVE_VEHICLE
+
+local LAB = E.Libs.LAB
+local LSM = E.Libs.LSM
+local LBF = E.Libs.LBF
+
+local UIHider
+
+AB.RegisterCooldown = E.RegisterCooldown
+
+AB.handledBars = {} --List of all bars
+AB.handledbuttons = {} --List of all buttons that have been modified.
+AB.barDefaults = {
+ bar1 = {
+ page = 1,
+ bindButtons = "ACTIONBUTTON",
+ conditions = "[bonusbar:5] 11; [bar:2] 2; [bar:3] 3; [bar:4] 4; [bar:5] 5; [bar:6] 6;",
+ position = "BOTTOM,ElvUIParent,BOTTOM,0,4",
+ },
+ bar2 = {
+ page = 5,
+ bindButtons = "MULTIACTIONBAR2BUTTON",
+ conditions = "",
+ position = "BOTTOM,ElvUI_Bar1,TOP,0,2"
+ },
+ bar3 = {
+ page = 6,
+ bindButtons = "MULTIACTIONBAR1BUTTON",
+ conditions = "",
+ position = "LEFT,ElvUI_Bar1,RIGHT,4,0"
+ },
+ bar4 = {
+ page = 4,
+ bindButtons = "MULTIACTIONBAR4BUTTON",
+ conditions = "",
+ position = "RIGHT,ElvUIParent,RIGHT,-4,0"
+ },
+ bar5 = {
+ page = 3,
+ bindButtons = "MULTIACTIONBAR3BUTTON",
+ conditions = "",
+ position = "RIGHT,ElvUI_Bar1,LEFT,-4,0"
+ },
+ bar6 = {
+ page = 2,
+ bindButtons = "ELVUIBAR6BUTTON",
+ conditions = "",
+ position = "BOTTOM,ElvUI_Bar2,TOP,0,2"
+ }
+}
+
+AB.customExitButton = {
+ func = function()
+ if UnitExists("vehicle") then
+ VehicleExit()
+ else
+ PetDismiss()
+ end
+ end,
+ texture = "Interface\\Icons\\Spell_Shadow_SacrificialShield",
+ tooltip = LEAVE_VEHICLE
+}
+
+function AB:PositionAndSizeBar(barName)
+ local buttonSpacing = E:Scale(self.db[barName].buttonspacing)
+ local backdropSpacing = E:Scale((self.db[barName].backdropSpacing or self.db[barName].buttonspacing))
+ local buttonsPerRow = self.db[barName].buttonsPerRow
+ local numButtons = self.db[barName].buttons
+ local size = E:Scale(self.db[barName].buttonsize)
+ local point = self.db[barName].point
+ local numColumns = ceil(numButtons / buttonsPerRow)
+ local widthMult = self.db[barName].widthMult
+ local heightMult = self.db[barName].heightMult
+ local visibility = self.db[barName].visibility
+ local bar = self.handledBars[barName]
+
+ bar.db = self.db[barName]
+
+ if visibility and match(visibility, "[\n\r]") then
+ visibility = gsub(visibility, "[\n\r]","")
+ end
+
+ if numButtons < buttonsPerRow then
+ buttonsPerRow = numButtons
+ end
+
+ if numColumns < 1 then
+ numColumns = 1
+ end
+
+ if bar.db.backdrop then
+ bar.backdrop:Show()
+ else
+ bar.backdrop:Hide()
+ --Set size multipliers to 1 when backdrop is disabled
+ widthMult = 1
+ heightMult = 1
+ end
+
+ local sideSpacing = (bar.db.backdrop == true and (E.Border + backdropSpacing) or E.Spacing)
+ --Size of all buttons + Spacing between all buttons + Spacing between additional rows of buttons + Spacing between backdrop and buttons + Spacing on end borders with non-thin borders
+ local barWidth = (size * (buttonsPerRow * widthMult)) + ((buttonSpacing * (buttonsPerRow - 1)) * widthMult) + (buttonSpacing * (widthMult - 1)) + (sideSpacing*2)
+ local barHeight = (size * (numColumns * heightMult)) + ((buttonSpacing * (numColumns - 1)) * heightMult) + (buttonSpacing * (heightMult - 1)) + (sideSpacing*2)
+ bar:Width(barWidth)
+ bar:Height(barHeight)
+
+ bar.mouseover = bar.db.mouseover
+
+ local horizontalGrowth, verticalGrowth
+ if point == "TOPLEFT" or point == "TOPRIGHT" then
+ verticalGrowth = "DOWN"
+ else
+ verticalGrowth = "UP"
+ end
+
+ if point == "BOTTOMLEFT" or point == "TOPLEFT" then
+ horizontalGrowth = "RIGHT"
+ else
+ horizontalGrowth = "LEFT"
+ end
+
+ if bar.db.mouseover then
+ bar:SetAlpha(0)
+ else
+ bar:SetAlpha(bar.db.alpha)
+ end
+
+ if bar.db.inheritGlobalFade then
+ bar:SetParent(self.fadeParent)
+ else
+ bar:SetParent(E.UIParent)
+ end
+
+ local button, lastButton, lastColumnButton
+ for i = 1, NUM_ACTIONBAR_BUTTONS do
+ button = bar.buttons[i]
+ lastButton = bar.buttons[i - 1]
+ lastColumnButton = bar.buttons[i-buttonsPerRow]
+ button:SetParent(bar)
+ button:ClearAllPoints()
+ button:Size(size)
+ button:SetAttribute("showgrid", 1)
+
+ if i == 1 then
+ local x, y
+ if point == "BOTTOMLEFT" then
+ x, y = sideSpacing, sideSpacing
+ elseif point == "TOPRIGHT" then
+ x, y = -sideSpacing, -sideSpacing
+ elseif point == "TOPLEFT" then
+ x, y = sideSpacing, -sideSpacing
+ else
+ x, y = -sideSpacing, sideSpacing
+ end
+
+ button:Point(point, bar, point, x, y)
+ elseif (i - 1) % buttonsPerRow == 0 then
+ local y = -buttonSpacing
+ local buttonPoint, anchorPoint = "TOP", "BOTTOM"
+ if verticalGrowth == "UP" then
+ y = buttonSpacing
+ buttonPoint = "BOTTOM"
+ anchorPoint = "TOP"
+ end
+ button:Point(buttonPoint, lastColumnButton, anchorPoint, 0, y)
+ else
+ local x = buttonSpacing
+ local buttonPoint, anchorPoint = "LEFT", "RIGHT"
+ if horizontalGrowth == "LEFT" then
+ x = -buttonSpacing
+ buttonPoint = "RIGHT"
+ anchorPoint = "LEFT"
+ end
+
+ button:Point(buttonPoint, lastButton, anchorPoint, x, 0)
+ end
+
+ if i > numButtons then
+ button:Hide()
+ else
+ button:Show()
+ end
+
+ self:StyleButton(button, nil, self.LBFGroup and E.private.actionbar.lbf.enable and true or nil)
+ end
+
+ if bar.db.enabled or not bar.initialized then
+ if not bar.db.mouseover then
+ bar:SetAlpha(bar.db.alpha)
+ end
+
+ local page = self:GetPage(barName, self.barDefaults[barName].page, self.barDefaults[barName].conditions)
+ bar:Show()
+ RegisterStateDriver(bar, "visibility", visibility) -- this is ghetto
+ RegisterStateDriver(bar, "page", page)
+ bar:SetAttribute("page", page)
+
+ if not bar.initialized then
+ bar.initialized = true
+ AB:PositionAndSizeBar(barName)
+ return
+ end
+ E:EnableMover(bar.mover:GetName())
+ else
+ E:DisableMover(bar.mover:GetName())
+ bar:Hide()
+ UnregisterStateDriver(bar, "visibility")
+ end
+
+ E:SetMoverSnapOffset("ElvAB_"..bar.id, bar.db.buttonspacing / 2)
+
+ if self.LBFGroup and E.private.actionbar.lbf.enable then
+ self.LBFGroup:Skin(E.private.actionbar.lbf.skin)
+ end
+end
+
+function AB:CreateBar(id)
+ local bar = CreateFrame("Frame", "ElvUI_Bar"..id, E.UIParent, "SecureHandlerStateTemplate")
+ local point, anchor, attachTo, x, y = split(",", self.barDefaults["bar"..id].position)
+ bar:Point(point, anchor, attachTo, x, y)
+ bar.id = id
+ bar:CreateBackdrop(self.db.transparentBackdrops and "Transparent")
+ bar:SetFrameStrata("LOW")
+
+ --Use this method instead of :SetAllPoints, as the size of the mover would otherwise be incorrect
+ bar.backdrop:SetPoint("TOPLEFT", bar, "TOPLEFT", E.Spacing, -E.Spacing)
+ bar.backdrop:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT", -E.Spacing, E.Spacing)
+
+ bar.buttons = {}
+ bar.bindButtons = self.barDefaults["bar"..id].bindButtons
+ self:HookScript(bar, "OnEnter", "Bar_OnEnter")
+ self:HookScript(bar, "OnLeave", "Bar_OnLeave")
+
+ for i = 1, 12 do
+ bar.buttons[i] = LAB:CreateButton(i, format(bar:GetName().."Button%d", i), bar, nil)
+ bar.buttons[i]:SetState(0, "action", i)
+ for k = 1, 11 do
+ bar.buttons[i]:SetState(k, "action", (k - 1) * 12 + i)
+ end
+
+ if i == 12 then
+ bar.buttons[i]:SetState(11, "custom", AB.customExitButton)
+ end
+
+ if self.LBFGroup and E.private.actionbar.lbf.enable then
+ self.LBFGroup:AddButton(bar.buttons[i])
+ end
+
+ self:HookScript(bar.buttons[i], "OnEnter", "Button_OnEnter")
+ self:HookScript(bar.buttons[i], "OnLeave", "Button_OnLeave")
+ end
+ self:UpdateButtonConfig(bar, bar.bindButtons)
+
+ bar:SetAttribute("_onstate-page", [[
+ if newstate ~= 0 then
+ self:SetAttribute("state", newstate)
+ control:ChildUpdate("state", newstate)
+ else
+ local newCondition = self:GetAttribute("newCondition")
+ if newCondition then
+ newstate = SecureCmdOptionParse(newCondition)
+ self:SetAttribute("state", newstate)
+ control:ChildUpdate("state", newstate)
+ end
+ end
+ ]])
+
+ self.handledBars["bar"..id] = bar
+ E:CreateMover(bar, "ElvAB_"..id, L["Bar "]..id, nil, nil, nil,"ALL,ACTIONBARS",nil,"actionbar,bar"..id)
+ self:PositionAndSizeBar("bar"..id)
+ return bar
+end
+
+function AB:PLAYER_REGEN_ENABLED()
+ if AB.NeedsUpdateButtonSettings then
+ self:UpdateButtonSettings()
+ AB.NeedsUpdateButtonSettings = nil
+ end
+ if AB.NeedsUpdateMicroBarVisibility then
+ self:UpdateMicroBarVisibility()
+ AB.NeedsUpdateMicroBarVisibility = nil
+ end
+ if AB.NeedsAdjustMaxStanceButtons then
+ AB:AdjustMaxStanceButtons(AB.NeedsAdjustMaxStanceButtons) --sometimes it holds the event, otherwise true. pass it before we nil it.
+ AB.NeedsAdjustMaxStanceButtons = nil
+ end
+ if AB.NeedsPositionAndSizeBarTotem then
+ self:PositionAndSizeBarTotem()
+ AB.NeedsPositionAndSizeBarTotem = nil
+ end
+ if AB.NeedRecallButtonUpdate then
+ MultiCastRecallSpellButton_Update(MultiCastRecallSpellButton)
+ AB.NeedRecallButtonUpdate = nil
+ end
+
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED")
+end
+
+local function Vehicle_OnEvent(self, event)
+ if CanExitVehicle() and not E.db.general.minimap.icons.vehicleLeave.hide then
+ self:Show()
+ else
+ self:Hide()
+ end
+end
+
+function AB:UpdateVehicleLeave()
+ if not self.vehicle then return end
+
+ local pos = E.db.general.minimap.icons.vehicleLeave.position
+
+ self.vehicle:ClearAllPoints()
+ self.vehicle:Point(pos, Minimap, pos, E.db.general.minimap.icons.vehicleLeave.xOffset, E.db.general.minimap.icons.vehicleLeave.yOffset)
+ self.vehicle:Size(26 * E.db.general.minimap.icons.vehicleLeave.scale)
+
+ Vehicle_OnEvent(self.vehicle)
+end
+
+function AB:CreateVehicleLeave()
+ local vehicle = CreateFrame("Button", "ElvUI_LeaveVehicleButton", E.UIParent)
+ vehicle:Hide()
+ vehicle:SetFrameStrata("HIGH")
+ vehicle:SetNormalTexture(E.Media.Textures.ExitVehicle)
+ vehicle:SetPushedTexture(E.Media.Textures.ExitVehicle)
+ vehicle:SetHighlightTexture(E.Media.Textures.ExitVehicle)
+ vehicle:SetTemplate()
+ vehicle:EnableMouse(true)
+ vehicle:RegisterForClicks("AnyUp")
+
+ vehicle:SetScript("OnClick", VehicleExit)
+ vehicle:SetScript("OnEvent", Vehicle_OnEvent)
+ vehicle:RegisterEvent("PLAYER_ENTERING_WORLD")
+ vehicle:RegisterEvent("UPDATE_BONUS_ACTIONBAR")
+ vehicle:RegisterEvent("UPDATE_MULTI_CAST_ACTIONBAR")
+ vehicle:RegisterEvent("UNIT_ENTERED_VEHICLE")
+ vehicle:RegisterEvent("UNIT_EXITED_VEHICLE")
+ vehicle:RegisterEvent("VEHICLE_UPDATE")
+
+ self.vehicle = vehicle
+ self:UpdateVehicleLeave()
+end
+
+function AB:ReassignBindings(event)
+ if event == "UPDATE_BINDINGS" then
+ self:UpdatePetBindings()
+ self:UpdateStanceBindings()
+ end
+
+ self:UnregisterEvent("PLAYER_REGEN_DISABLED")
+
+ if InCombatLockdown() then return end
+
+ for _, bar in pairs(self.handledBars) do
+ if bar then
+ ClearOverrideBindings(bar)
+ for i = 1, #bar.buttons do
+ local button = format(bar.bindButtons.."%d", i)
+ local real_button = format(bar:GetName().."Button%d", i)
+ for k = 1, select("#", GetBindingKey(button)) do
+ local key = select(k, GetBindingKey(button))
+ if key and key ~= "" then
+ SetOverrideBindingClick(bar, false, key, real_button)
+ end
+ end
+ end
+ end
+ end
+end
+
+function AB:RemoveBindings()
+ if InCombatLockdown() then return end
+
+ for _, bar in pairs(self.handledBars) do
+ if bar then
+ ClearOverrideBindings(bar)
+ end
+ end
+
+ self:RegisterEvent("PLAYER_REGEN_DISABLED", "ReassignBindings")
+end
+
+function AB:UpdateBar1Paging()
+ if self.db.bar6.enabled then
+ AB.barDefaults.bar1.conditions = "[bonusbar:5] 11; [bar:3] 3; [bar:4] 4; [bar:5] 5; [bar:6] 6;"
+ else
+ AB.barDefaults.bar1.conditions = "[bonusbar:5] 11; [bar:2] 2; [bar:3] 3; [bar:4] 4; [bar:5] 5; [bar:6] 6;"
+ end
+
+ if (E.private.actionbar.enable ~= true or InCombatLockdown()) or not self.isInitialized then return end
+ local bar2Option = InterfaceOptionsActionBarsPanelBottomRight
+ local bar3Option = InterfaceOptionsActionBarsPanelBottomLeft
+ local bar4Option = InterfaceOptionsActionBarsPanelRightTwo
+ local bar5Option = InterfaceOptionsActionBarsPanelRight
+
+ if (self.db.bar2.enabled and not bar2Option:GetChecked()) or (not self.db.bar2.enabled and bar2Option:GetChecked()) then
+ bar2Option:Click()
+ end
+
+ if (self.db.bar3.enabled and not bar3Option:GetChecked()) or (not self.db.bar3.enabled and bar3Option:GetChecked()) then
+ bar3Option:Click()
+ end
+
+ if not self.db.bar5.enabled and not self.db.bar4.enabled then
+ if bar4Option:GetChecked() then
+ bar4Option:Click()
+ end
+
+ if bar5Option:GetChecked() then
+ bar5Option:Click()
+ end
+ elseif not self.db.bar5.enabled then
+ if not bar5Option:GetChecked() then
+ bar5Option:Click()
+ end
+
+ if not bar4Option:GetChecked() then
+ bar4Option:Click()
+ end
+ elseif (self.db.bar4.enabled and not bar4Option:GetChecked()) or (not self.db.bar4.enabled and bar4Option:GetChecked()) then
+ bar4Option:Click()
+ elseif (self.db.bar5.enabled and not bar5Option:GetChecked()) or (not self.db.bar5.enabled and bar5Option:GetChecked()) then
+ bar5Option:Click()
+ end
+end
+
+function AB:UpdateButtonSettingsForBar(barName)
+ local bar = self.handledBars[barName]
+ self:UpdateButtonConfig(bar, bar.bindButtons)
+end
+
+function AB:UpdateButtonSettings()
+ if E.private.actionbar.enable ~= true then return end
+
+ if InCombatLockdown() then
+ AB.NeedsUpdateButtonSettings = true
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ return
+ end
+
+ for button in pairs(self.handledbuttons) do
+ if button then
+ self:StyleButton(button, button.noBackdrop, button.useMasque)
+ else
+ self.handledbuttons[button] = nil
+ end
+ end
+
+ self:UpdatePetBindings()
+ self:UpdateStanceBindings()
+
+ for barName, bar in pairs(self.handledBars) do
+ if bar then
+ self:UpdateButtonConfig(bar, bar.bindButtons)
+ self:PositionAndSizeBar(barName)
+ end
+ end
+
+ self:AdjustMaxStanceButtons()
+ self:PositionAndSizeBarPet()
+ self:PositionAndSizeBarShapeShift()
+end
+
+function AB:GetPage(bar, defaultPage, condition)
+ local page = self.db[bar].paging[E.myclass]
+ if not condition then condition = "" end
+ if not page then
+ page = ""
+ elseif match(page, "[\n\r]") then
+ page = gsub(page, "[\n\r]","")
+ end
+
+ if page then
+ condition = condition.." "..page
+ end
+ condition = condition.." "..defaultPage
+
+ return condition
+end
+
+function AB:StyleButton(button, noBackdrop, useMasque)
+ local name = button:GetName()
+ local icon = _G[name.."Icon"]
+ local count = _G[name.."Count"]
+ local flash = _G[name.."Flash"]
+ local hotkey = _G[name.."HotKey"]
+ local border = _G[name.."Border"]
+ local macroText = _G[name.."Name"]
+ local normal = _G[name.."NormalTexture"]
+ local normal2 = button:GetNormalTexture()
+ local buttonCooldown = _G[name.."Cooldown"]
+
+ local color = self.db.fontColor
+ local countPosition = self.db.countTextPosition or "BOTTOMRIGHT"
+ local countXOffset = self.db.countTextXOffset or 0
+ local countYOffset = self.db.countTextYOffset or 2
+
+ button.noBackdrop = noBackdrop
+ button.useMasque = useMasque
+
+ if flash then flash:SetTexture(nil) end
+ if normal then normal:SetTexture(nil) normal:Hide() normal:SetAlpha(0) end
+ if normal2 then normal2:SetTexture(nil) normal2:Hide() normal2:SetAlpha(0) end
+ if border and not button.useMasque then border:Kill() end
+
+ if count then
+ count:ClearAllPoints()
+ count:Point(countPosition, countXOffset, countYOffset)
+ count:FontTemplate(LSM:Fetch("font", self.db.font), self.db.fontSize, self.db.fontOutline)
+ count:SetTextColor(color.r, color.g, color.b)
+ end
+
+ if macroText then
+ macroText:ClearAllPoints()
+ macroText:Point("BOTTOM", 0, 1)
+ macroText:FontTemplate(LSM:Fetch("font", self.db.font), self.db.fontSize, self.db.fontOutline)
+ macroText:SetTextColor(color.r, color.g, color.b)
+ end
+
+ if not button.noBackdrop and not button.backdrop and not button.useMasque then
+ button:CreateBackdrop(self.db.transparentButtons and "Transparent", true)
+ button.backdrop:SetAllPoints()
+ end
+
+ if icon then
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetInside()
+ end
+
+ if self.db.hotkeytext or self.db.useRangeColorText then
+ hotkey:FontTemplate(LSM:Fetch("font", self.db.font), self.db.fontSize, self.db.fontOutline)
+ if button.config and (button.config.outOfRangeColoring ~= "hotkey") then
+ button.hotkey:SetTextColor(color.r, color.g, color.b)
+ end
+ end
+
+ self:FixKeybindText(button)
+
+ if not button.useMasque then
+ button:StyleButton()
+ else
+ button:StyleButton(true, true, true)
+ end
+
+ if not self.handledbuttons[button] then
+ buttonCooldown.CooldownOverride = "actionbar"
+
+ E:RegisterCooldown(buttonCooldown)
+
+ self.handledbuttons[button] = true
+ end
+end
+
+function AB:Bar_OnEnter(bar)
+ if bar:GetParent() == self.fadeParent then
+ if not self.fadeParent.mouseLock then
+ E:UIFrameFadeIn(self.fadeParent, 0.2, self.fadeParent:GetAlpha(), 1)
+ end
+ end
+
+ if bar.mouseover then
+ E:UIFrameFadeIn(bar, 0.2, bar:GetAlpha(), bar.db.alpha)
+ end
+end
+
+function AB:Bar_OnLeave(bar)
+ if bar:GetParent() == self.fadeParent then
+ if not self.fadeParent.mouseLock then
+ E:UIFrameFadeOut(self.fadeParent, 0.2, self.fadeParent:GetAlpha(), 1 - self.db.globalFadeAlpha)
+ end
+ end
+
+ if bar.mouseover then
+ E:UIFrameFadeOut(bar, 0.2, bar:GetAlpha(), 0)
+ end
+end
+
+function AB:Button_OnEnter(button)
+ local bar = button:GetParent()
+ if bar:GetParent() == self.fadeParent then
+ if not self.fadeParent.mouseLock then
+ E:UIFrameFadeIn(self.fadeParent, 0.2, self.fadeParent:GetAlpha(), 1)
+ end
+ end
+
+ if bar.mouseover then
+ E:UIFrameFadeIn(bar, 0.2, bar:GetAlpha(), bar.db.alpha)
+ end
+end
+
+function AB:Button_OnLeave(button)
+ local bar = button:GetParent()
+ if bar:GetParent() == self.fadeParent then
+ if not self.fadeParent.mouseLock then
+ E:UIFrameFadeOut(self.fadeParent, 0.2, self.fadeParent:GetAlpha(), 1 - self.db.globalFadeAlpha)
+ end
+ end
+
+ if bar.mouseover then
+ E:UIFrameFadeOut(bar, 0.2, bar:GetAlpha(), 0)
+ end
+end
+
+function AB:BlizzardOptionsPanel_OnEvent()
+ InterfaceOptionsActionBarsPanelBottomRightText:SetFormattedText(L["Remove Bar %d Action Page"], 2)
+ InterfaceOptionsActionBarsPanelBottomLeftText:SetFormattedText(L["Remove Bar %d Action Page"], 3)
+ InterfaceOptionsActionBarsPanelRightTwoText:SetFormattedText(L["Remove Bar %d Action Page"], 4)
+ InterfaceOptionsActionBarsPanelRightText:SetFormattedText(L["Remove Bar %d Action Page"], 5)
+
+ InterfaceOptionsActionBarsPanelBottomRight:SetScript("OnEnter", nil)
+ InterfaceOptionsActionBarsPanelBottomLeft:SetScript("OnEnter", nil)
+ InterfaceOptionsActionBarsPanelRightTwo:SetScript("OnEnter", nil)
+ InterfaceOptionsActionBarsPanelRight:SetScript("OnEnter", nil)
+end
+
+function AB:FadeParent_OnEvent(event, unit)
+ if (event == "UNIT_SPELLCAST_START"
+ or event == "UNIT_SPELLCAST_STOP"
+ or event == "UNIT_SPELLCAST_CHANNEL_START"
+ or event == "UNIT_SPELLCAST_CHANNEL_STOP"
+ or event == "UNIT_HEALTH") and unit ~= "player" then return end
+
+ local cur, max = UnitHealth("player"), UnitHealthMax("player")
+ local cast, channel = UnitCastingInfo("player"), UnitChannelInfo("player")
+ local target, focus = UnitExists("target"), UnitExists("focus")
+ local combat = UnitAffectingCombat("player")
+ if (cast or channel) or (cur ~= max) or (target or focus) or combat then
+ self.mouseLock = true
+ E:UIFrameFadeIn(self, 0.2, self:GetAlpha(), 1)
+ else
+ self.mouseLock = false
+ E:UIFrameFadeOut(self, 0.2, self:GetAlpha(), 1 - AB.db.globalFadeAlpha)
+ end
+end
+
+function AB:DisableBlizzard()
+ UIHider = CreateFrame("Frame")
+ UIHider:Hide()
+
+ MultiBarBottomLeft:SetParent(UIHider)
+ MultiBarBottomLeft.Show = E.noop
+ MultiBarBottomLeft.Hide = E.noop
+ MultiBarBottomRight:SetParent(UIHider)
+ MultiBarBottomRight.Hide = E.noop
+ MultiBarBottomRight.Show = E.noop
+ MultiBarLeft:SetParent(UIHider)
+ MultiBarLeft.Show = E.noop
+ MultiBarLeft.Hide = E.noop
+ MultiBarRight:SetParent(UIHider)
+ MultiBarRight.Show = E.noop
+ MultiBarRight.Hide = E.noop
+
+ -- Hide MultiBar Buttons, but keep the bars alive
+ for i = 1, 12 do
+ _G["ActionButton"..i]:Hide()
+ _G["ActionButton"..i]:UnregisterAllEvents()
+ _G["ActionButton"..i]:SetAttribute("statehidden", true)
+
+ _G["MultiBarBottomLeftButton"..i]:Hide()
+ _G["MultiBarBottomLeftButton"..i]:UnregisterAllEvents()
+ _G["MultiBarBottomLeftButton"..i]:SetAttribute("statehidden", true)
+
+ _G["MultiBarBottomRightButton"..i]:Hide()
+ _G["MultiBarBottomRightButton"..i]:UnregisterAllEvents()
+ _G["MultiBarBottomRightButton"..i]:SetAttribute("statehidden", true)
+
+ _G["MultiBarRightButton"..i]:Hide()
+ _G["MultiBarRightButton"..i]:UnregisterAllEvents()
+ _G["MultiBarRightButton"..i]:SetAttribute("statehidden", true)
+
+ _G["MultiBarLeftButton"..i]:Hide()
+ _G["MultiBarLeftButton"..i]:UnregisterAllEvents()
+ _G["MultiBarLeftButton"..i]:SetAttribute("statehidden", true)
+
+ if _G["VehicleMenuBarActionButton"..i] then
+ _G["VehicleMenuBarActionButton"..i]:Hide()
+ _G["VehicleMenuBarActionButton"..i]:UnregisterAllEvents()
+ _G["VehicleMenuBarActionButton"..i]:SetAttribute("statehidden", true)
+ end
+
+ _G["BonusActionButton"..i]:Hide()
+ _G["BonusActionButton"..i]:UnregisterAllEvents()
+ _G["BonusActionButton"..i]:SetAttribute("statehidden", true)
+
+ end
+
+ MultiCastActionBarFrame.ignoreFramePositionManager = true
+
+ MainMenuBar:Hide()
+ MainMenuBar:SetParent(UIHider)
+
+ MainMenuExpBar:UnregisterAllEvents()
+ MainMenuExpBar:Hide()
+ MainMenuExpBar:SetParent(UIHider)
+
+ ReputationWatchBar:UnregisterAllEvents()
+ ReputationWatchBar:Hide()
+ ReputationWatchBar:SetParent(UIHider)
+
+ MainMenuBarArtFrame:UnregisterAllEvents()
+ MainMenuBarArtFrame:RegisterEvent("KNOWN_CURRENCY_TYPES_UPDATE")
+ MainMenuBarArtFrame:RegisterEvent("CURRENCY_DISPLAY_UPDATE")
+ MainMenuBarArtFrame:Hide()
+ MainMenuBarArtFrame:SetParent(UIHider)
+
+ ShapeshiftBarFrame:UnregisterAllEvents()
+ ShapeshiftBarFrame:Hide()
+ ShapeshiftBarFrame:SetParent(UIHider)
+
+ BonusActionBarFrame:UnregisterAllEvents()
+ BonusActionBarFrame:Hide()
+ BonusActionBarFrame:SetParent(UIHider)
+
+ PossessBarFrame:UnregisterAllEvents()
+ PossessBarFrame:Hide()
+ PossessBarFrame:SetParent(UIHider)
+
+ PetActionBarFrame:UnregisterAllEvents()
+ PetActionBarFrame:Hide()
+ PetActionBarFrame:SetParent(UIHider)
+
+ VehicleMenuBar:UnregisterAllEvents()
+ VehicleMenuBar:Hide()
+ VehicleMenuBar:SetParent(UIHider)
+
+ InterfaceOptionsActionBarsPanelAlwaysShowActionBars:EnableMouse(false)
+ InterfaceOptionsActionBarsPanelAlwaysShowActionBars:SetAlpha(0)
+
+ InterfaceOptionsActionBarsPanelLockActionBars:EnableMouse(false)
+ InterfaceOptionsActionBarsPanelLockActionBars:SetAlpha(0)
+
+ InterfaceOptionsStatusTextPanelXP:SetAlpha(0)
+ InterfaceOptionsStatusTextPanelXP:SetScale(0.0001)
+
+ self:SecureHook("BlizzardOptionsPanel_OnEvent")
+
+ if PlayerTalentFrame then
+ PlayerTalentFrame:UnregisterEvent("ACTIVE_TALENT_GROUP_CHANGED")
+ else
+ hooksecurefunc("TalentFrame_LoadUI", function() PlayerTalentFrame:UnregisterEvent("ACTIVE_TALENT_GROUP_CHANGED") end)
+ end
+end
+
+function AB:UpdateButtonConfig(bar, buttonName)
+ if InCombatLockdown() then
+ AB.NeedsUpdateButtonSettings = true
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ return
+ end
+
+ if not bar.buttonConfig then bar.buttonConfig = {hideElements = {}, colors = {}} end
+ bar.buttonConfig.hideElements.macro = not self.db.macrotext
+ bar.buttonConfig.hideElements.hotkey = not self.db.hotkeytext
+ bar.buttonConfig.showGrid = self.db["bar"..bar.id].showGrid
+ bar.buttonConfig.clickOnDown = self.db.keyDown
+ bar.buttonConfig.outOfRangeColoring = (self.db.useRangeColorText and "hotkey") or "button"
+ SetModifiedClick("PICKUPACTION", self.db.movementModifier)
+ bar.buttonConfig.colors.range = E:SetColorTable(bar.buttonConfig.colors.range, self.db.noRangeColor)
+ bar.buttonConfig.colors.mana = E:SetColorTable(bar.buttonConfig.colors.mana, self.db.noPowerColor)
+ bar.buttonConfig.colors.usable = E:SetColorTable(bar.buttonConfig.colors.usable, self.db.usableColor)
+ bar.buttonConfig.colors.notUsable = E:SetColorTable(bar.buttonConfig.colors.notUsable, self.db.notUsableColor)
+
+ for i, button in pairs(bar.buttons) do
+ bar.buttonConfig.keyBoundTarget = format(buttonName.."%d", i)
+ button.keyBoundTarget = bar.buttonConfig.keyBoundTarget
+ button.postKeybind = AB.FixKeybindText
+ button:SetAttribute("buttonlock", self.db.lockActionBars)
+ button:SetAttribute("checkselfcast", true)
+ button:SetAttribute("checkfocuscast", true)
+ if self.db.rightClickSelfCast then
+ button:SetAttribute("unit2", "player")
+ else
+ button:SetAttribute("unit2", nil)
+ end
+
+ button:UpdateConfig(bar.buttonConfig)
+ end
+end
+
+function AB:FixKeybindText(button)
+ local hotkey = _G[button:GetName().."HotKey"]
+ local text = hotkey:GetText()
+
+ local hotkeyPosition = E.db.actionbar.hotkeyTextPosition or "TOPRIGHT"
+ local hotkeyXOffset = E.db.actionbar.hotkeyTextXOffset or 0
+ local hotkeyYOffset = E.db.actionbar.hotkeyTextYOffset or -3
+
+ local justify = "RIGHT"
+ if hotkeyPosition == "TOPLEFT" or hotkeyPosition == "BOTTOMLEFT" then
+ justify = "LEFT"
+ elseif hotkeyPosition == "TOP" or hotkeyPosition == "BOTTOM" then
+ justify = "CENTER"
+ end
+
+ if text then
+ text = gsub(text, "SHIFT%-", L["KEY_SHIFT"])
+ text = gsub(text, "ALT%-", L["KEY_ALT"])
+ text = gsub(text, "CTRL%-", L["KEY_CTRL"])
+ text = gsub(text, "BUTTON", L["KEY_MOUSEBUTTON"])
+ text = gsub(text, "MOUSEWHEELUP", L["KEY_MOUSEWHEELUP"])
+ text = gsub(text, "MOUSEWHEELDOWN", L["KEY_MOUSEWHEELDOWN"])
+ text = gsub(text, "NUMPAD", L["KEY_NUMPAD"])
+ text = gsub(text, "PAGEUP", L["KEY_PAGEUP"])
+ text = gsub(text, "PAGEDOWN", L["KEY_PAGEDOWN"])
+ text = gsub(text, "SPACE", L["KEY_SPACE"])
+ text = gsub(text, "INSERT", L["KEY_INSERT"])
+ text = gsub(text, "HOME", L["KEY_HOME"])
+ text = gsub(text, "DELETE", L["KEY_DELETE"])
+ text = gsub(text, "NMULTIPLY", "*")
+ text = gsub(text, "NMINUS", "N-")
+ text = gsub(text, "NPLUS", "N+")
+
+ hotkey:SetText(text)
+ hotkey:SetJustifyH(justify)
+ end
+
+ if not button.useMasque then
+ hotkey:ClearAllPoints()
+ hotkey:Point(hotkeyPosition, hotkeyXOffset, hotkeyYOffset)
+ end
+end
+
+function AB:LAB_ButtonUpdate(button)
+ local color = AB.db.fontColor
+ button.count:SetTextColor(color.r, color.g, color.b)
+ if button.config and (button.config.outOfRangeColoring ~= "hotkey") then
+ button.hotkey:SetTextColor(color.r, color.g, color.b)
+ end
+
+ if button.backdrop then
+ if AB.db.equippedItem then
+ if button:IsEquipped() and AB.db.equippedItemColor then
+ color = AB.db.equippedItemColor
+ button.backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
+ button.backdrop.isColored = true
+ elseif button.backdrop.isColored then
+ button.backdrop.isColored = nil
+ button.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ elseif button.backdrop.isColored then
+ button.backdrop.isColored = nil
+ button.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end
+end
+LAB.RegisterCallback(AB, "OnButtonUpdate", AB.LAB_ButtonUpdate)
+
+local function OnCooldownUpdate(_, button, start, duration)
+ if button._state_type ~= "action" then return end
+
+ if duration and duration > 1.5 then
+ button.saturationLocked = true --Lock any new actions that are created after we activated desaturation option
+
+ button.icon:SetDesaturated(true)
+
+ if (E.db.cooldown.enable and AB.db.cooldown.reverse) or (not E.db.cooldown.enable and not AB.db.cooldown.reverse) then
+ if not button.onCooldownDoneHooked then
+ AB:HookScript(button.cooldown, "OnHide", function()
+ button.icon:SetDesaturated(false)
+ end)
+
+ button.onCooldownDoneHooked = true
+ end
+ else
+ if not button.onCooldownTimerDoneHooked then
+ if button.cooldown.timer then
+ AB:HookScript(button.cooldown.timer, "OnHide", function()
+ if (E.db.cooldown.enable and AB.db.cooldown.reverse) or (not E.db.cooldown.enable and not AB.db.cooldown.reverse) then return end
+
+ button.icon:SetDesaturated(false)
+ end)
+
+ button.onCooldownTimerDoneHooked = true
+ end
+ end
+ end
+ end
+end
+
+function AB:ToggleDesaturation(value)
+ value = value or self.db.desaturateOnCooldown
+
+ if value then
+ LAB.RegisterCallback(AB, "OnCooldownUpdate", OnCooldownUpdate)
+ local start, duration
+ for button in pairs(LAB.actionButtons) do
+ button.saturationLocked = true
+ start, duration = button:GetCooldown()
+ OnCooldownUpdate(nil, button, start, duration)
+ end
+ else
+ LAB.UnregisterCallback(AB, "OnCooldownUpdate")
+ for button in pairs(LAB.actionButtons) do
+ button.saturationLocked = nil
+ button.icon:SetDesaturated(false)
+ if (E.db.cooldown.enable and AB.db.cooldown.reverse) or (not E.db.cooldown.enable and not AB.db.cooldown.reverse) then
+ if button.onCooldownDoneHooked then
+ AB:Unhook(button.cooldown, "OnHide")
+
+ button.onCooldownDoneHooked = nil
+ end
+ else
+ if button.onCooldownTimerDoneHooked then
+ if button.cooldown.timer then
+ if (E.db.cooldown.enable and AB.db.cooldown.reverse) or (not E.db.cooldown.enable and not AB.db.cooldown.reverse) then return end
+
+ AB:Unhook(button.cooldown.timer, "OnHide")
+
+ button.onCooldownTimerDoneHooked = nil
+ end
+ end
+ end
+ end
+ end
+end
+
+function AB:Initialize()
+ self.db = E.db.actionbar
+ if E.private.actionbar.enable ~= true then return end
+ self.Initialized = true
+
+ self.LBFGroup = LBF and LBF:Group("ElvUI", "ActionBars")
+
+ self.fadeParent = CreateFrame("Frame", "Elv_ABFade", UIParent)
+ self.fadeParent:SetAlpha(1 - self.db.globalFadeAlpha)
+ self.fadeParent:RegisterEvent("PLAYER_REGEN_DISABLED")
+ self.fadeParent:RegisterEvent("PLAYER_REGEN_ENABLED")
+ self.fadeParent:RegisterEvent("PLAYER_TARGET_CHANGED")
+ self.fadeParent:RegisterEvent("UNIT_SPELLCAST_START")
+ self.fadeParent:RegisterEvent("UNIT_SPELLCAST_STOP")
+ self.fadeParent:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
+ self.fadeParent:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
+ self.fadeParent:RegisterEvent("UNIT_HEALTH")
+ self.fadeParent:RegisterEvent("PLAYER_FOCUS_CHANGED")
+ self.fadeParent:SetScript("OnEvent", self.FadeParent_OnEvent)
+
+ self:DisableBlizzard()
+ self:SetupMicroBar()
+ self:UpdateBar1Paging()
+
+ for i = 1, 6 do
+ self:CreateBar(i)
+ end
+
+ self:CreateBarPet()
+ self:CreateBarShapeShift()
+ self:CreateVehicleLeave()
+
+ if self.db.barTotem.enabled then
+ self:CreateTotemBar()
+ end
+
+ self:UpdateButtonSettings()
+ self:LoadKeyBinder()
+
+ self:RegisterEvent("UPDATE_BINDINGS", "ReassignBindings")
+ self:ReassignBindings()
+
+ --We handle actionbar lock for regular bars, but the lock on PetBar needs to be handled by WoW so make some necessary updates
+ SetCVar("lockActionBars", (self.db.lockActionBars == true and 1 or 0))
+ LOCK_ACTIONBAR = (self.db.lockActionBars == true and "1" or "0") --Keep an eye on this, in case it taints
+
+ self:ToggleDesaturation()
+end
+
+local function InitializeCallback()
+ AB:Initialize()
+end
+
+E:RegisterModule(AB:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/ActionBars/Bind.lua b/ElvUI/Modules/ActionBars/Bind.lua
new file mode 100644
index 0000000..a80e36b
--- /dev/null
+++ b/ElvUI/Modules/ActionBars/Bind.lua
@@ -0,0 +1,392 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local AB = E:GetModule("ActionBars")
+local Skins = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local select, tonumber, pairs = select, tonumber, pairs
+local floor = math.floor
+local find, format, upper = string.find, string.format, string.upper
+--WoW API / Variables
+local hooksecurefunc = hooksecurefunc
+local CreateFrame = CreateFrame
+local IsAddOnLoaded = IsAddOnLoaded
+local LoadBindings, SaveBindings = LoadBindings, SaveBindings
+local GetCurrentBindingSet = GetCurrentBindingSet
+local SetBinding = SetBinding
+local GetBindingKey = GetBindingKey
+local IsAltKeyDown, IsControlKeyDown = IsAltKeyDown, IsControlKeyDown
+local IsShiftKeyDown, IsModifiedClick = IsShiftKeyDown, IsModifiedClick
+local InCombatLockdown = InCombatLockdown
+local GameTooltip_ShowCompareItem = GameTooltip_ShowCompareItem
+local GetMacroInfo = GetMacroInfo
+local SecureActionButton_OnClick = SecureActionButton_OnClick
+local GameTooltip_Hide = GameTooltip_Hide
+local CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP = CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP
+local CHARACTER_SPECIFIC_KEYBINDINGS = CHARACTER_SPECIFIC_KEYBINDINGS
+
+local bind = CreateFrame("Frame", "ElvUI_KeyBinder", E.UIParent)
+
+function AB:ActivateBindMode()
+ if InCombatLockdown() then
+ return
+ end
+
+ bind.active = true
+ E:StaticPopupSpecial_Show(ElvUIBindPopupWindow)
+ AB:RegisterEvent("PLAYER_REGEN_DISABLED", "DeactivateBindMode", false)
+end
+
+function AB:DeactivateBindMode(save)
+ if save then
+ SaveBindings(GetCurrentBindingSet())
+ E:Print(L["Binds Saved"])
+ else
+ LoadBindings(GetCurrentBindingSet())
+ E:Print(L["Binds Discarded"])
+ end
+
+ bind.active = false
+ self:BindHide()
+ self:UnregisterEvent("PLAYER_REGEN_DISABLED")
+ E:StaticPopupSpecial_Hide(ElvUIBindPopupWindow)
+ AB.bindingsChanged = false
+end
+
+function AB:BindHide()
+ bind:ClearAllPoints()
+ bind:Hide()
+ GameTooltip:Hide()
+end
+
+function AB:BindListener(key)
+ AB.bindingsChanged = true
+ if key == "ESCAPE" or key == "RightButton" then
+ if bind.button.bindings then
+ for i = 1, #bind.button.bindings do
+ SetBinding(bind.button.bindings[i])
+ end
+ end
+ E:Print(format(L["All keybindings cleared for |cff00ff00%s|r."], bind.button.name))
+ self:BindUpdate(bind.button, bind.spellmacro)
+ if bind.spellmacro ~= "MACRO" then
+ GameTooltip:Hide()
+ end
+ return
+ end
+
+ if key == "LSHIFT"
+ or key == "RSHIFT"
+ or key == "LCTRL"
+ or key == "RCTRL"
+ or key == "LALT"
+ or key == "RALT"
+ or key == "UNKNOWN"
+ or key == "LeftButton"
+ then return end
+
+ if key == "MiddleButton" then key = "BUTTON3" end
+ if find(key, "Button%d") then
+ key = upper(key)
+ end
+
+ local alt = IsAltKeyDown() and "ALT-" or ""
+ local ctrl = IsControlKeyDown() and "CTRL-" or ""
+ local shift = IsShiftKeyDown() and "SHIFT-" or ""
+ local keybind = format("%s%s%s%s", alt, ctrl, shift, key)
+
+ if not bind.spellmacro or bind.spellmacro == "PET" or bind.spellmacro == "SHAPESHIFT" then
+ SetBinding(keybind, bind.button.bindstring)
+ else
+ SetBinding(keybind, bind.spellmacro.." "..bind.button.name)
+ end
+
+ E:Print(format("%s%s%s.", keybind, L[" |cff00ff00bound to |r"], bind.button.name))
+ self:BindUpdate(bind.button, bind.spellmacro)
+
+ if bind.spellmacro ~= "MACRO" then
+ GameTooltip:Hide()
+ end
+end
+
+function AB:BindUpdate(button, spellmacro)
+ if not bind.active or InCombatLockdown() then return end
+
+ bind.button = button
+ bind.spellmacro = spellmacro
+
+ bind:ClearAllPoints()
+ bind:SetAllPoints(button)
+ bind:Show()
+
+ ShoppingTooltip1:Hide()
+
+ if not bind:IsMouseEnabled() then
+ bind:EnableMouse(true)
+ end
+
+ if spellmacro == "MACRO" then
+ bind.button.id = bind.button:GetID()
+
+ if floor(.5 + select(2, MacroFrameTab1Text:GetTextColor()) * 10) / 10 == .8 then bind.button.id = bind.button.id + MAX_ACCOUNT_MACROS end
+
+ bind.button.name = GetMacroInfo(bind.button.id)
+
+ GameTooltip:SetOwner(bind, "ANCHOR_TOP")
+ GameTooltip:SetPoint("BOTTOM", bind, "TOP", 0, 1)
+ GameTooltip:AddLine(bind.button.name, 1, 1, 1)
+
+ bind.button.bindings = {GetBindingKey(spellmacro.." "..bind.button.name)}
+
+ if #bind.button.bindings == 0 then
+ GameTooltip:AddLine(L["No bindings set."], .6, .6, .6)
+ else
+ GameTooltip:AddDoubleLine(L["Binding"], L["Key"], .6, .6, .6, .6, .6, .6)
+ for i = 1, #bind.button.bindings do
+ GameTooltip:AddDoubleLine(L["Binding"]..i, bind.button.bindings[i], 1, 1, 1)
+ end
+ end
+
+ GameTooltip:Show()
+ elseif spellmacro == "SHAPESHIFT" or spellmacro == "PET" then
+ bind.button.id = tonumber(button:GetID())
+ bind.button.name = button:GetName()
+
+ if not bind.button.name then return end
+
+ if not bind.button.id or bind.button.id < 1 or bind.button.id > (spellmacro=="SHAPESHIFT" and 10 or 12) then
+ bind.button.bindstring = "CLICK "..bind.button.name..":LeftButton"
+ else
+ bind.button.bindstring = (spellmacro=="SHAPESHIFT" and "SHAPESHIFTBUTTON" or "BONUSACTIONBUTTON")..bind.button.id
+ end
+
+ GameTooltip:AddLine(L["Trigger"])
+ GameTooltip:Show()
+ GameTooltip:SetScript("OnHide", function(tt)
+ tt:SetOwner(bind, "ANCHOR_NONE")
+ tt:SetPoint("BOTTOM", bind, "TOP", 0, 1)
+ tt:AddLine(bind.button.name, 1, 1, 1)
+ bind.button.bindings = {GetBindingKey(bind.button.bindstring)}
+ if #bind.button.bindings == 0 then
+ tt:AddLine(L["No bindings set."], .6, .6, .6)
+ else
+ tt:AddDoubleLine(L["Binding"], L["Key"], .6, .6, .6, .6, .6, .6)
+ for i = 1, #bind.button.bindings do
+ tt:AddDoubleLine(i, bind.button.bindings[i])
+ end
+ end
+ tt:Show()
+ tt:SetScript("OnHide", nil)
+ end)
+ else
+ bind.button.action = tonumber(button.action)
+ bind.button.name = button:GetName()
+
+ if not bind.button.name then return end
+ if (not bind.button.action or bind.button.action < 1 or bind.button.action > 132) and not (bind.button.keyBoundTarget) then
+ bind.button.bindstring = "CLICK "..bind.button.name..":LeftButton"
+ elseif bind.button.keyBoundTarget then
+ bind.button.bindstring = bind.button.keyBoundTarget
+ else
+ local modact = 1 + (bind.button.action-1) % 12
+ if bind.button.action < 25 or bind.button.action > 72 then
+ bind.button.bindstring = "ACTIONBUTTON"..modact
+ elseif bind.button.action < 73 and bind.button.action > 60 then
+ bind.button.bindstring = "MULTIACTIONBAR1BUTTON"..modact
+ elseif bind.button.action < 61 and bind.button.action > 48 then
+ bind.button.bindstring = "MULTIACTIONBAR2BUTTON"..modact
+ elseif bind.button.action < 49 and bind.button.action > 36 then
+ bind.button.bindstring = "MULTIACTIONBAR4BUTTON"..modact
+ elseif bind.button.action < 37 and bind.button.action > 24 then
+ bind.button.bindstring = "MULTIACTIONBAR3BUTTON"..modact
+ end
+ end
+
+ GameTooltip:AddLine(L["Trigger"])
+ GameTooltip:Show()
+ GameTooltip:SetScript("OnHide", function(tt)
+ tt:SetOwner(bind, "ANCHOR_TOP")
+ tt:SetPoint("BOTTOM", bind, "TOP", 0, 4)
+ tt:AddLine(bind.button.name, 1, 1, 1)
+ bind.button.bindings = {GetBindingKey(bind.button.bindstring)}
+ if #bind.button.bindings == 0 then
+ tt:AddLine(L["No bindings set."], .6, .6, .6)
+ else
+ tt:AddDoubleLine(L["Binding"], L["Key"], .6, .6, .6, .6, .6, .6)
+ for i = 1, #bind.button.bindings do
+ tt:AddDoubleLine(i, bind.button.bindings[i])
+ end
+ end
+ tt:Show()
+ tt:SetScript("OnHide", nil)
+ end)
+ end
+end
+
+function AB:RegisterButton(button, override)
+ local shapeshift = ShapeshiftButton1:GetScript("OnClick")
+ local pet = PetActionButton1:GetScript("OnClick")
+ local secureOnClick = SecureActionButton_OnClick
+
+ if button.IsProtected and button.GetObjectType and button.GetScript and button:GetObjectType() == "CheckButton" and button:IsProtected() then
+ local script = button:GetScript("OnClick")
+
+ if script == secureOnClick or override then
+ button:HookScript("OnEnter", function(b) self:BindUpdate(b) end)
+
+ if script == shapeshift then
+ button:HookScript("OnEnter", function(b) self:BindUpdate(b, "SHAPESHIFT") end)
+ elseif script == pet then
+ button:HookScript("OnEnter", function(b) self:BindUpdate(b, "PET") end)
+ end
+ end
+ end
+end
+
+local elapsed = 0
+function AB:Tooltip_OnUpdate(tooltip, e)
+ elapsed = elapsed + e
+ if elapsed < .2 then return else elapsed = 0 end
+
+ local compareItems = IsModifiedClick("COMPAREITEMS")
+ if not tooltip.comparing and compareItems and tooltip:GetItem() then
+ GameTooltip_ShowCompareItem(tooltip)
+ tooltip.comparing = true
+ elseif tooltip.comparing and not compareItems then
+ for _, frame in pairs(tooltip.shoppingTooltips) do frame:Hide() end
+ tooltip.comparing = false
+ end
+end
+
+function AB:RegisterMacro(addon)
+ if addon == "Blizzard_MacroUI" then
+ for i = 1, MAX_ACCOUNT_MACROS do
+ local button = _G["MacroButton"..i]
+ button:HookScript("OnEnter", function(b) AB:BindUpdate(b, "MACRO") end)
+ end
+ end
+end
+
+function AB:ChangeBindingProfile()
+ if ElvUIBindPopupWindowCheckButton:GetChecked() then
+ LoadBindings(2)
+ SaveBindings(2)
+ else
+ LoadBindings(1)
+ SaveBindings(1)
+ end
+end
+
+function AB:LoadKeyBinder()
+ bind:SetFrameStrata("DIALOG")
+ bind:SetFrameLevel(99)
+ bind:EnableMouse(true)
+ bind:EnableKeyboard(true)
+ bind:EnableMouseWheel(true)
+ bind.texture = bind:CreateTexture()
+ bind.texture:SetAllPoints(bind)
+ bind.texture:SetTexture(0, 0, 0, .25)
+ bind:Hide()
+
+ self:HookScript(GameTooltip, "OnUpdate", "Tooltip_OnUpdate")
+ hooksecurefunc(GameTooltip, "Hide", function(tooltip) for _, tt in pairs(tooltip.shoppingTooltips) do tt:Hide() end end)
+
+ bind:SetScript("OnEnter", function(self) local db = self.button:GetParent().db if db and db.mouseover then AB:Button_OnEnter(self.button) end end)
+ bind:SetScript("OnLeave", function(self) AB:BindHide() local db = self.button:GetParent().db if db and db.mouseover then AB:Button_OnLeave(self.button) end end)
+ bind:SetScript("OnKeyUp", function(_, key) self:BindListener(key) end)
+ bind:SetScript("OnMouseUp", function(_, key) self:BindListener(key) end)
+ bind:SetScript("OnMouseWheel", function(_, delta) if delta > 0 then self:BindListener("MOUSEWHEELUP") else self:BindListener("MOUSEWHEELDOWN") end end)
+
+ for b, _ in pairs(self.handledbuttons) do
+ self:RegisterButton(b, true)
+ end
+
+ if not IsAddOnLoaded("Blizzard_MacroUI") then
+ self:SecureHook("LoadAddOn", "RegisterMacro")
+ else
+ self:RegisterMacro("Blizzard_MacroUI")
+ end
+
+ --Special Popup
+ local f = CreateFrame("Frame", "ElvUIBindPopupWindow", UIParent)
+ f:SetFrameStrata("DIALOG")
+ f:SetToplevel(true)
+ f:EnableMouse(true)
+ f:SetMovable(true)
+ f:SetFrameLevel(99)
+ f:SetClampedToScreen(true)
+ f:SetWidth(360)
+ f:SetHeight(130)
+ f:SetTemplate("Transparent")
+ f:Hide()
+
+ local header = CreateFrame("Button", nil, f)
+ header:SetTemplate(nil, true)
+ header:Width(100)
+ header:Height(25)
+ header:Point("CENTER", f, "TOP")
+ header:SetFrameLevel(header:GetFrameLevel() + 2)
+ header:EnableMouse(true)
+ header:RegisterForClicks("AnyUp", "AnyDown")
+ header:SetScript("OnMouseDown", function() f:StartMoving() end)
+ header:SetScript("OnMouseUp", function() f:StopMovingOrSizing() end)
+
+ local title = header:CreateFontString("OVERLAY")
+ title:FontTemplate()
+ title:Point("CENTER", header, "CENTER")
+ title:SetText("Key Binds")
+
+ local desc = f:CreateFontString("ARTWORK")
+ desc:SetFontObject("GameFontHighlight")
+ desc:SetJustifyV("TOP")
+ desc:SetJustifyH("LEFT")
+ desc:Point("TOPLEFT", 18, -32)
+ desc:Point("BOTTOMRIGHT", -18, 48)
+ desc:SetText(L["Hover your mouse over any actionbutton or spellbook button to bind it. Press the ESC key to clear the current actionbutton's keybinding."])
+
+ local perCharCheck = CreateFrame("CheckButton", f:GetName().."CheckButton", f, "OptionsCheckButtonTemplate")
+ _G[perCharCheck:GetName().."Text"]:SetText(CHARACTER_SPECIFIC_KEYBINDINGS)
+
+ perCharCheck:SetScript("OnShow", function(self)
+ self:SetChecked(GetCurrentBindingSet() == 2)
+ end)
+
+ perCharCheck:SetScript("OnClick", function()
+ if ( AB.bindingsChanged ) then
+ E:StaticPopup_Show("CONFIRM_LOSE_BINDING_CHANGES")
+ else
+ AB:ChangeBindingProfile()
+ end
+ end)
+
+ perCharCheck:SetScript("OnEnter", function(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
+ GameTooltip:SetText(CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP, nil, nil, nil, nil, 1)
+ end)
+
+ perCharCheck:SetScript("OnLeave", GameTooltip_Hide)
+
+ local save = CreateFrame("Button", f:GetName().."SaveButton", f, "OptionsButtonTemplate")
+ _G[save:GetName().."Text"]:SetText(L["Save"])
+ save:Width(150)
+ save:SetScript("OnClick", function()
+ AB:DeactivateBindMode(true)
+ end)
+
+ local discard = CreateFrame("Button", f:GetName().."DiscardButton", f, "OptionsButtonTemplate")
+ discard:Width(150)
+ _G[discard:GetName().."Text"]:SetText(L["Discard"])
+
+ discard:SetScript("OnClick", function()
+ AB:DeactivateBindMode(false)
+ end)
+
+ --position buttons
+ perCharCheck:Point("BOTTOMLEFT", discard, "TOPLEFT", 0, 2)
+ save:Point("BOTTOMRIGHT", -14, 10)
+ discard:Point("BOTTOMLEFT", 14, 10)
+
+ Skins:HandleCheckBox(perCharCheck)
+ Skins:HandleButton(save)
+ Skins:HandleButton(discard)
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/ActionBars/Load_ActionBars.xml b/ElvUI/Modules/ActionBars/Load_ActionBars.xml
new file mode 100644
index 0000000..10529f0
--- /dev/null
+++ b/ElvUI/Modules/ActionBars/Load_ActionBars.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/ActionBars/MicroBar.lua b/ElvUI/Modules/ActionBars/MicroBar.lua
new file mode 100644
index 0000000..3e45462
--- /dev/null
+++ b/ElvUI/Modules/ActionBars/MicroBar.lua
@@ -0,0 +1,194 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local AB = E:GetModule("ActionBars")
+
+--Lua functions
+local _G = _G
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local InCombatLockdown = InCombatLockdown
+local RegisterStateDriver = RegisterStateDriver
+
+local MICRO_BUTTONS = {
+ "CharacterMicroButton",
+ "SpellbookMicroButton",
+ "TalentMicroButton",
+ "AchievementMicroButton",
+ "QuestLogMicroButton",
+ "SocialsMicroButton",
+ "PVPMicroButton",
+ "LFDMicroButton",
+ "MainMenuMicroButton",
+ "HelpMicroButton"
+}
+
+local function onEnter(button)
+ if AB.db.microbar.mouseover then
+ E:UIFrameFadeIn(ElvUI_MicroBar, 0.2, ElvUI_MicroBar:GetAlpha(), AB.db.microbar.alpha)
+ end
+
+ if button and button ~= ElvUI_MicroBar and button.backdrop then
+ button.backdrop:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
+ end
+end
+
+local function onLeave(button)
+ if AB.db.microbar.mouseover then
+ E:UIFrameFadeOut(ElvUI_MicroBar, 0.2, ElvUI_MicroBar:GetAlpha(), 0)
+ end
+
+ if button and button ~= ElvUI_MicroBar and button.backdrop then
+ button.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+end
+
+function AB:HandleMicroButton(button)
+ local pushed = button:GetPushedTexture()
+ local normal = button:GetNormalTexture()
+ local disabled = button:GetDisabledTexture()
+
+ local f = CreateFrame("Frame", nil, button)
+ f:SetFrameLevel(button:GetFrameLevel() - 1)
+ f:SetTemplate("Default", true)
+ f:SetOutside(button)
+ button.backdrop = f
+
+ button:SetParent(ElvUI_MicroBar)
+ button:GetHighlightTexture():Kill()
+ button:HookScript("OnEnter", onEnter)
+ button:HookScript("OnLeave", onLeave)
+ button:SetHitRectInsets(0, 0, 0, 0)
+ button:Show()
+
+ pushed:SetTexCoord(0.17, 0.87, 0.5, 0.908)
+ pushed:SetInside(f)
+
+ normal:SetTexCoord(0.17, 0.87, 0.5, 0.908)
+ normal:SetInside(f)
+
+ if disabled then
+ disabled:SetTexCoord(0.17, 0.87, 0.5, 0.908)
+ disabled:SetInside(f)
+ end
+end
+
+function AB:UpdateMicroButtonsParent()
+ if CharacterMicroButton:GetParent() == ElvUI_MicroBar then return end
+
+ for i = 1, #MICRO_BUTTONS do
+ _G[MICRO_BUTTONS[i]]:SetParent(ElvUI_MicroBar)
+ end
+
+ AB:UpdateMicroPositionDimensions()
+end
+
+function AB:UpdateMicroBarVisibility()
+ if InCombatLockdown() then
+ AB.NeedsUpdateMicroBarVisibility = true
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ return
+ end
+
+ local visibility = self.db.microbar.visibility
+ if visibility and string.match(visibility, "[\n\r]") then
+ visibility = string.gsub(visibility, "[\n\r]", "")
+ end
+
+ RegisterStateDriver(ElvUI_MicroBar.visibility, "visibility", (self.db.microbar.enabled and visibility) or "hide")
+end
+
+function AB:UpdateMicroPositionDimensions()
+ if not ElvUI_MicroBar then return end
+
+ local numRows = 1
+ local prevButton = ElvUI_MicroBar
+ local offset = E:Scale(E.PixelMode and 1 or 3)
+ local spacing = E:Scale(offset + self.db.microbar.buttonSpacing)
+
+ for i = 1, #MICRO_BUTTONS do
+ local button = _G[MICRO_BUTTONS[i]]
+ local lastColumnButton = i - self.db.microbar.buttonsPerRow
+ lastColumnButton = _G[MICRO_BUTTONS[lastColumnButton]]
+
+ button:Size(self.db.microbar.buttonSize, self.db.microbar.buttonSize * 1.4)
+ button:ClearAllPoints()
+
+ if prevButton == ElvUI_MicroBar then
+ button:Point("TOPLEFT", prevButton, "TOPLEFT", offset, -offset)
+ elseif (i - 1) % self.db.microbar.buttonsPerRow == 0 then
+ button:Point("TOP", lastColumnButton, "BOTTOM", 0, -spacing)
+ numRows = numRows + 1
+ else
+ button:Point("LEFT", prevButton, "RIGHT", spacing, 0)
+ end
+
+ prevButton = button
+ end
+
+ if AB.db.microbar.mouseover and not ElvUI_MicroBar:IsMouseOver() then
+ ElvUI_MicroBar:SetAlpha(0)
+ else
+ ElvUI_MicroBar:SetAlpha(self.db.microbar.alpha)
+ end
+
+ AB.MicroWidth = (((CharacterMicroButton:GetWidth() + spacing) * self.db.microbar.buttonsPerRow) - spacing) + (offset * 2)
+ AB.MicroHeight = (((CharacterMicroButton:GetHeight() + spacing) * numRows) - spacing) + (offset * 2)
+ ElvUI_MicroBar:Size(AB.MicroWidth, AB.MicroHeight)
+
+ if ElvUI_MicroBar.mover then
+ if self.db.microbar.enabled then
+ E:EnableMover(ElvUI_MicroBar.mover:GetName())
+ else
+ E:DisableMover(ElvUI_MicroBar.mover:GetName())
+ end
+ end
+
+ self:UpdateMicroBarVisibility()
+end
+
+function AB:UpdateMicroButtons()
+ -- PvP Micro Button
+ PVPMicroButtonTexture:Point("TOPLEFT", PVPMicroButton, "TOPLEFT")
+ PVPMicroButtonTexture:Point("BOTTOMRIGHT", PVPMicroButton, "BOTTOMRIGHT")
+ PVPMicroButtonTexture:SetTexture("Interface\\AddOns\\ElvUI\\media\\textures\\PVP-Icons")
+
+ if E.mylevel < PVPMicroButton.minLevel then
+ PVPMicroButtonTexture:SetDesaturated(true)
+ else
+ PVPMicroButtonTexture:SetDesaturated(false)
+ end
+
+ self:UpdateMicroPositionDimensions()
+end
+
+function AB:SetupMicroBar()
+ local microBar = CreateFrame("Frame", "ElvUI_MicroBar", E.UIParent)
+ microBar:Point("TOPLEFT", E.UIParent, "TOPLEFT", 4, -48)
+ microBar:SetFrameStrata("LOW")
+ microBar:EnableMouse(true)
+ microBar:SetScript("OnEnter", onEnter)
+ microBar:SetScript("OnLeave", onLeave)
+
+ microBar.visibility = CreateFrame("Frame", nil, E.UIParent, "SecureHandlerStateTemplate")
+ microBar.visibility:SetScript("OnShow", function() microBar:Show() end)
+ microBar.visibility:SetScript("OnHide", function() microBar:Hide() end)
+
+ for i = 1, #MICRO_BUTTONS do
+ self:HandleMicroButton(_G[MICRO_BUTTONS[i]])
+ end
+
+ MicroButtonPortrait:SetInside(CharacterMicroButton.backdrop)
+
+ if E.myfaction == "Alliance" then
+ PVPMicroButtonTexture:SetTexCoord(0.545, 0.935, 0.070, 0.940)
+ else
+ PVPMicroButtonTexture:SetTexCoord(0.100, 0.475, 0.070, 0.940)
+ end
+
+ self:SecureHook("VehicleMenuBar_MoveMicroButtons", "UpdateMicroButtonsParent")
+ self:SecureHook("UpdateMicroButtons")
+
+ self:UpdateMicroPositionDimensions()
+ MainMenuBarPerformanceBar:Kill()
+
+ E:CreateMover(microBar, "MicrobarMover", L["Micro Bar"], nil, nil, nil, "ALL,ACTIONBARS", nil, "actionbar,microbar")
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/ActionBars/PetBar.lua b/ElvUI/Modules/ActionBars/PetBar.lua
new file mode 100644
index 0000000..48c032b
--- /dev/null
+++ b/ElvUI/Modules/ActionBars/PetBar.lua
@@ -0,0 +1,308 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local AB = E:GetModule("ActionBars")
+
+--Lua functions
+local _G = _G
+local ceil = math.ceil
+--WoW API / Variables
+local RegisterStateDriver = RegisterStateDriver
+local GetBindingKey = GetBindingKey
+local PetHasActionBar = PetHasActionBar
+local GetPetActionInfo = GetPetActionInfo
+local IsPetAttackAction = IsPetAttackAction
+local PetActionButton_StartFlash = PetActionButton_StartFlash
+local PetActionButton_StopFlash = PetActionButton_StopFlash
+local AutoCastShine_AutoCastStart = AutoCastShine_AutoCastStart
+local AutoCastShine_AutoCastStop = AutoCastShine_AutoCastStop
+local GetPetActionSlotUsable = GetPetActionSlotUsable
+local SetDesaturation = SetDesaturation
+local PetActionBar_ShowGrid = PetActionBar_ShowGrid
+local PetActionBar_UpdateCooldowns = PetActionBar_UpdateCooldowns
+local NUM_PET_ACTION_SLOTS = NUM_PET_ACTION_SLOTS
+
+local bar = CreateFrame("Frame", "ElvUI_BarPet", E.UIParent, "SecureHandlerStateTemplate")
+bar:SetFrameStrata("LOW")
+
+function AB:UpdatePet(event, unit)
+ if (event == "UNIT_FLAGS" or event == "UNIT_AURA") and unit ~= "pet" then return end
+ if event == "UNIT_PET" and unit ~= "player" then return end
+
+ for i = 1, NUM_PET_ACTION_SLOTS, 1 do
+ local buttonName = "PetActionButton"..i
+ local button = _G[buttonName]
+ local icon = _G[buttonName.."Icon"]
+ local autoCast = _G[buttonName.."AutoCastable"]
+ local shine = _G[buttonName.."Shine"]
+ local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(i)
+
+ if not isToken then
+ icon:SetTexture(texture)
+ button.tooltipName = name
+ else
+ icon:SetTexture(_G[texture])
+ button.tooltipName = _G[name]
+ end
+
+ button.isToken = isToken
+ button.tooltipSubtext = subtext
+
+ if isActive --[[and name ~= "PET_ACTION_FOLLOW"]] then
+ button:SetChecked(true)
+
+ if IsPetAttackAction(i) then
+ PetActionButton_StartFlash(button)
+ end
+ else
+ button:SetChecked(false)
+ if IsPetAttackAction(i) then
+ PetActionButton_StopFlash(button)
+ end
+ end
+
+ if autoCastAllowed then
+ autoCast:Show()
+ else
+ autoCast:Hide()
+ end
+
+ if autoCastEnabled then
+ AutoCastShine_AutoCastStart(shine)
+ else
+ AutoCastShine_AutoCastStop(shine)
+ end
+
+ if texture then
+ if GetPetActionSlotUsable(i) then
+ SetDesaturation(icon, nil)
+ SetDesaturation(autoCast, nil)
+ else
+ SetDesaturation(icon, 1)
+ SetDesaturation(autoCast, 1)
+ end
+ icon:Show()
+ else
+ icon:Hide()
+ end
+
+ if not PetHasActionBar() and texture --[[and name ~= "PET_ACTION_FOLLOW"]] then
+ PetActionButton_StopFlash(button)
+ SetDesaturation(icon, 1)
+ button:SetChecked(0)
+ end
+ end
+end
+
+function AB:PositionAndSizeBarPet()
+ local buttonSpacing = E:Scale(self.db.barPet.buttonspacing)
+ local backdropSpacing = E:Scale((self.db.barPet.backdropSpacing or self.db.barPet.buttonspacing))
+ local buttonsPerRow = self.db.barPet.buttonsPerRow
+ local numButtons = self.db.barPet.buttons
+ local size = E:Scale(self.db.barPet.buttonsize)
+ local autoCastSize = (size / 2) - (size / 7.5)
+ local point = self.db.barPet.point
+ local numColumns = ceil(numButtons / buttonsPerRow)
+ local widthMult = self.db.barPet.widthMult
+ local heightMult = self.db.barPet.heightMult
+ local visibility = self.db.barPet.visibility
+
+ bar.db = self.db.barPet
+
+ if visibility and string.match(visibility, "[\n\r]") then
+ visibility = string.gsub(visibility, "[\n\r]","")
+ end
+
+ if numButtons < buttonsPerRow then
+ buttonsPerRow = numButtons
+ end
+
+ if numColumns < 1 then
+ numColumns = 1
+ end
+
+ if self.db.barPet.backdrop == true then
+ bar.backdrop:Show()
+ else
+ bar.backdrop:Hide()
+ --Set size multipliers to 1 when backdrop is disabled
+ widthMult = 1
+ heightMult = 1
+ end
+
+ local barWidth = (size * (buttonsPerRow * widthMult)) + ((buttonSpacing * (buttonsPerRow - 1)) * widthMult) + (buttonSpacing * (widthMult-1)) + ((self.db.barPet.backdrop == true and (E.Border + backdropSpacing) or E.Spacing)*2)
+ local barHeight = (size * (numColumns * heightMult)) + ((buttonSpacing * (numColumns - 1)) * heightMult) + (buttonSpacing * (heightMult-1)) + ((self.db.barPet.backdrop == true and (E.Border + backdropSpacing) or E.Spacing)*2)
+ bar:Width(barWidth)
+ bar:Height(barHeight)
+
+ if self.db.barPet.enabled then
+ bar:SetScale(1)
+ bar:SetAlpha(bar.db.alpha)
+ E:EnableMover(bar.mover:GetName())
+ else
+ bar:SetScale(0.0001)
+ bar:SetAlpha(0)
+ E:DisableMover(bar.mover:GetName())
+ end
+
+ local horizontalGrowth, verticalGrowth
+ if point == "TOPLEFT" or point == "TOPRIGHT" then
+ verticalGrowth = "DOWN"
+ else
+ verticalGrowth = "UP"
+ end
+
+ if point == "BOTTOMLEFT" or point == "TOPLEFT" then
+ horizontalGrowth = "RIGHT"
+ else
+ horizontalGrowth = "LEFT"
+ end
+
+ bar.mouseover = self.db.barPet.mouseover
+ if bar.mouseover then
+ bar:SetAlpha(0)
+ else
+ bar:SetAlpha(bar.db.alpha)
+ end
+
+ if self.db.barPet.inheritGlobalFade then
+ bar:SetParent(self.fadeParent)
+ else
+ bar:SetParent(E.UIParent)
+ end
+
+ local button, lastButton, lastColumnButton, autoCast, shine
+ local firstButtonSpacing = (self.db.barPet.backdrop == true and (E.Border + backdropSpacing) or E.Spacing)
+ for i = 1, NUM_PET_ACTION_SLOTS do
+ button = _G["PetActionButton"..i]
+ lastButton = _G["PetActionButton"..i - 1]
+ autoCast = _G["PetActionButton"..i.."AutoCastable"]
+ shine = _G["PetActionButton"..i.."Shine"]
+ lastColumnButton = _G["PetActionButton"..i - buttonsPerRow]
+
+ button:SetParent(bar)
+ button:ClearAllPoints()
+ button:Size(size)
+ autoCast:SetOutside(button, autoCastSize, autoCastSize)
+ shine:Size(size - E.Border*2)
+ button:SetAttribute("showgrid", 1)
+
+ if i == 1 then
+ local x, y
+ if point == "BOTTOMLEFT" then
+ x, y = firstButtonSpacing, firstButtonSpacing
+ elseif point == "TOPRIGHT" then
+ x, y = -firstButtonSpacing, -firstButtonSpacing
+ elseif point == "TOPLEFT" then
+ x, y = firstButtonSpacing, -firstButtonSpacing
+ else
+ x, y = -firstButtonSpacing, firstButtonSpacing
+ end
+
+ button:Point(point, bar, point, x, y)
+ elseif (i - 1) % buttonsPerRow == 0 then
+ local x = 0
+ local y = -buttonSpacing
+ local buttonPoint, anchorPoint = "TOP", "BOTTOM"
+ if verticalGrowth == "UP" then
+ y = buttonSpacing
+ buttonPoint = "BOTTOM"
+ anchorPoint = "TOP"
+ end
+ button:Point(buttonPoint, lastColumnButton, anchorPoint, x, y)
+ else
+ local x = buttonSpacing
+ local y = 0
+ local buttonPoint, anchorPoint = "LEFT", "RIGHT"
+ if horizontalGrowth == "LEFT" then
+ x = -buttonSpacing
+ buttonPoint = "RIGHT"
+ anchorPoint = "LEFT"
+ end
+
+ button:Point(buttonPoint, lastButton, anchorPoint, x, y)
+ end
+
+ if i > numButtons then
+ button:SetScale(0.0001)
+ button:SetAlpha(0)
+ else
+ button:SetScale(1)
+ button:SetAlpha(bar.db.alpha)
+ end
+
+ self:StyleButton(button, nil, self.LBFGroup and E.private.actionbar.lbf.enable and true or nil)
+ end
+
+ RegisterStateDriver(bar, "show", visibility)
+
+ --Fix issue with mover not updating size when bar is hidden
+ bar:GetScript("OnSizeChanged")(bar)
+
+ if self.LBFGroup and E.private.actionbar.lbf.enable then self.LBFGroup:Skin(E.private.actionbar.lbf.skin) end
+end
+
+function AB:UpdatePetBindings()
+ local color = self.db.fontColor
+
+ for i = 1, NUM_PET_ACTION_SLOTS do
+ if self.db.hotkeytext then
+ local key = GetBindingKey("BONUSACTIONBUTTON"..i)
+ _G["PetActionButton"..i.."HotKey"]:Show()
+ _G["PetActionButton"..i.."HotKey"]:SetText(key)
+ _G["PetActionButton"..i.."HotKey"]:SetTextColor(color.r, color.g, color.b)
+ self:FixKeybindText(_G["PetActionButton"..i])
+ else
+ _G["PetActionButton"..i.."HotKey"]:Hide()
+ end
+ end
+end
+
+function AB:CreateBarPet()
+ bar:CreateBackdrop(self.db.transparentBackdrops and "Transparent")
+ bar.backdrop:SetAllPoints()
+ if self.db.bar4.enabled then
+ bar:Point("RIGHT", ElvUI_Bar4, "LEFT", -4, 0)
+ else
+ bar:Point("RIGHT", E.UIParent, "RIGHT", -4, 0)
+ end
+
+ bar:SetAttribute("_onstate-show", [[
+ if newstate == "hide" then
+ self:Hide()
+ else
+ self:Show()
+ end
+ ]])
+
+ PetActionBarFrame.showgrid = 1
+ PetActionBar_ShowGrid()
+
+ self:HookScript(bar, "OnEnter", "Bar_OnEnter")
+ self:HookScript(bar, "OnLeave", "Bar_OnLeave")
+
+ self:RegisterEvent("SPELLS_CHANGED", "UpdatePet")
+ self:RegisterEvent("PLAYER_CONTROL_GAINED", "UpdatePet")
+ self:RegisterEvent("PLAYER_ENTERING_WORLD", "UpdatePet")
+ self:RegisterEvent("PLAYER_CONTROL_LOST", "UpdatePet")
+ self:RegisterEvent("PET_BAR_UPDATE", "UpdatePet")
+ self:RegisterEvent("UNIT_PET", "UpdatePet")
+ self:RegisterEvent("UNIT_FLAGS", "UpdatePet")
+ self:RegisterEvent("UNIT_AURA", "UpdatePet")
+ self:RegisterEvent("PLAYER_FARSIGHT_FOCUS_CHANGED", "UpdatePet")
+ self:RegisterEvent("PET_BAR_UPDATE_COOLDOWN", PetActionBar_UpdateCooldowns)
+
+ E:CreateMover(bar, "ElvBar_Pet", L["Pet Bar"], nil, nil, nil,"ALL,ACTIONBARS", nil, "actionbar,barPet")
+
+ self:PositionAndSizeBarPet()
+ self:UpdatePetBindings()
+
+ for i = 1, NUM_PET_ACTION_SLOTS do
+ local button = _G["PetActionButton"..i]
+
+ self:HookScript(button, "OnEnter", "Button_OnEnter")
+ self:HookScript(button, "OnLeave", "Button_OnLeave")
+
+ if self.LBFGroup and E.private.actionbar.lbf.enable then
+ self.LBFGroup:AddButton(button)
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/ActionBars/StanceBar.lua b/ElvUI/Modules/ActionBars/StanceBar.lua
new file mode 100644
index 0000000..757d908
--- /dev/null
+++ b/ElvUI/Modules/ActionBars/StanceBar.lua
@@ -0,0 +1,330 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local AB = E:GetModule("ActionBars")
+
+--Lua functions
+local _G = _G
+local ceil = math.ceil
+local format, gsub, match = string.format, string.gsub, string.match
+--WoW API / Variables
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local CreateFrame = CreateFrame
+local GetBindingKey = GetBindingKey
+local GetNumShapeshiftForms = GetNumShapeshiftForms
+local GetShapeshiftForm = GetShapeshiftForm
+local GetShapeshiftFormCooldown = GetShapeshiftFormCooldown
+local GetShapeshiftFormInfo = GetShapeshiftFormInfo
+local GetSpellInfo = GetSpellInfo
+local InCombatLockdown = InCombatLockdown
+local RegisterStateDriver = RegisterStateDriver
+
+local NUM_SHAPESHIFT_SLOTS = NUM_SHAPESHIFT_SLOTS
+
+local bar = CreateFrame("Frame", "ElvUI_StanceBar", E.UIParent, "SecureHandlerStateTemplate")
+bar:SetFrameStrata("LOW")
+
+function AB:UPDATE_SHAPESHIFT_COOLDOWN()
+ local numForms = GetNumShapeshiftForms()
+ local start, duration, enable, cooldown
+ for i = 1, NUM_SHAPESHIFT_SLOTS do
+ if i <= numForms then
+ cooldown = _G["ElvUI_StanceBarButton"..i.."Cooldown"]
+ start, duration, enable = GetShapeshiftFormCooldown(i)
+ CooldownFrame_SetTimer(cooldown, start, duration, enable)
+ end
+ end
+
+ self:StyleShapeShift("UPDATE_SHAPESHIFT_COOLDOWN")
+end
+
+function AB:StyleShapeShift()
+ local numForms = GetNumShapeshiftForms()
+ local texture, name, isActive, isCastable, _
+ local buttonName, button, icon, cooldown
+ local stance = GetShapeshiftForm()
+
+ for i = 1, NUM_SHAPESHIFT_SLOTS do
+ buttonName = "ElvUI_StanceBarButton"..i
+ button = _G[buttonName]
+ icon = _G[buttonName.."Icon"]
+ cooldown = _G[buttonName.."Cooldown"]
+
+ if i <= numForms then
+ texture, name, isActive, isCastable = GetShapeshiftFormInfo(i)
+
+ if self.db.stanceBar.style == "darkenInactive" then
+ if name then
+ _, _, texture = GetSpellInfo(name)
+ end
+ end
+
+ if not texture then
+ texture = "Interface\\Icons\\Spell_Nature_WispSplode"
+ end
+
+ if texture then
+ cooldown:SetAlpha(1)
+ else
+ cooldown:SetAlpha(0)
+ end
+
+ if isActive then
+ button:GetCheckedTexture():SetTexture(1, 1, 1, 0.5)
+
+ if numForms == 1 then
+ button:SetChecked(true)
+ else
+ button:SetChecked(self.db.stanceBar.style ~= "darkenInactive")
+ end
+ else
+ if numForms == 1 or stance == 0 then
+ button:SetChecked(false)
+ else
+ button:SetChecked(self.db.stanceBar.style == "darkenInactive")
+ button:GetCheckedTexture():SetAlpha(1)
+ if self.db.stanceBar.style == "darkenInactive" then
+ button:GetCheckedTexture():SetTexture(0, 0, 0, 0.5)
+ else
+ button:GetCheckedTexture():SetTexture(1, 1, 1, 0.5)
+ end
+ end
+ end
+
+ icon:SetTexture(texture)
+
+ if isCastable then
+ icon:SetVertexColor(1.0, 1.0, 1.0)
+ else
+ icon:SetVertexColor(0.4, 0.4, 0.4)
+ end
+ end
+ end
+end
+
+function AB:PositionAndSizeBarShapeShift()
+ local buttonSpacing = E:Scale(self.db.stanceBar.buttonspacing)
+ local backdropSpacing = E:Scale((self.db.stanceBar.backdropSpacing or self.db.stanceBar.buttonspacing))
+ local buttonsPerRow = self.db.stanceBar.buttonsPerRow
+ local numButtons = self.db.stanceBar.buttons
+ local size = E:Scale(self.db.stanceBar.buttonsize)
+ local point = self.db.stanceBar.point
+ local widthMult = self.db.stanceBar.widthMult
+ local heightMult = self.db.stanceBar.heightMult
+ if bar.mover then
+ bar.mover.positionOverride = point
+ E:UpdatePositionOverride(bar.mover:GetName())
+ end
+ bar.db = self.db.stanceBar
+ bar.mouseover = self.db.stanceBar.mouseover
+
+ if bar.LastButton and numButtons > bar.LastButton then
+ numButtons = bar.LastButton
+ end
+
+ if bar.LastButton and buttonsPerRow > bar.LastButton then
+ buttonsPerRow = bar.LastButton
+ end
+
+ if numButtons < buttonsPerRow then
+ buttonsPerRow = numButtons
+ end
+
+ local numColumns = ceil(numButtons / buttonsPerRow)
+ if numColumns < 1 then
+ numColumns = 1
+ end
+
+ if self.db.stanceBar.backdrop then
+ bar.backdrop:Show()
+ else
+ bar.backdrop:Hide()
+ --Set size multipliers to 1 when backdrop is disabled
+ widthMult = 1
+ heightMult = 1
+ end
+
+ local barWidth = (size * (buttonsPerRow * widthMult)) + ((buttonSpacing * (buttonsPerRow - 1)) * widthMult) + (buttonSpacing * (widthMult-1)) + ((self.db.stanceBar.backdrop and (E.Border + backdropSpacing) or E.Spacing)*2)
+ local barHeight = (size * (numColumns * heightMult)) + ((buttonSpacing * (numColumns - 1)) * heightMult) + (buttonSpacing * (heightMult-1)) + ((self.db.stanceBar.backdrop and (E.Border + backdropSpacing) or E.Spacing)*2)
+ bar:Width(barWidth)
+ bar:Height(barHeight)
+
+ if self.db.stanceBar.enabled then
+ bar:SetScale(1)
+ bar:SetAlpha(bar.db.alpha)
+ E:EnableMover(bar.mover:GetName())
+ else
+ bar:SetScale(0.0001)
+ bar:SetAlpha(0)
+ E:DisableMover(bar.mover:GetName())
+ end
+
+ local horizontalGrowth, verticalGrowth
+ if point == "TOPLEFT" or point == "TOPRIGHT" then
+ verticalGrowth = "DOWN"
+ else
+ verticalGrowth = "UP"
+ end
+
+ if point == "BOTTOMLEFT" or point == "TOPLEFT" then
+ horizontalGrowth = "RIGHT"
+ else
+ horizontalGrowth = "LEFT"
+ end
+
+ if self.db.stanceBar.inheritGlobalFade then
+ bar:SetParent(self.fadeParent)
+ else
+ bar:SetParent(E.UIParent)
+ end
+
+ local button, lastButton, lastColumnButton
+ local firstButtonSpacing = (self.db.stanceBar.backdrop and (E.Border + backdropSpacing) or E.Spacing)
+ for i = 1, NUM_SHAPESHIFT_SLOTS do
+ button = _G["ElvUI_StanceBarButton"..i]
+ lastButton = _G["ElvUI_StanceBarButton"..i - 1]
+ lastColumnButton = _G["ElvUI_StanceBarButton"..i - buttonsPerRow]
+
+ button:SetParent(bar)
+ button:ClearAllPoints()
+ button:Size(size)
+
+ if self.db.stanceBar.mouseover then
+ bar:SetAlpha(0)
+ else
+ bar:SetAlpha(bar.db.alpha)
+ end
+
+ if i == 1 then
+ local x, y
+ if point == "BOTTOMLEFT" then
+ x, y = firstButtonSpacing, firstButtonSpacing
+ elseif point == "TOPRIGHT" then
+ x, y = -firstButtonSpacing, -firstButtonSpacing
+ elseif point == "TOPLEFT" then
+ x, y = firstButtonSpacing, -firstButtonSpacing
+ else
+ x, y = -firstButtonSpacing, firstButtonSpacing
+ end
+
+ button:Point(point, bar, point, x, y)
+ elseif (i - 1) % buttonsPerRow == 0 then
+ local x = 0
+ local y = -buttonSpacing
+ local buttonPoint, anchorPoint = "TOP", "BOTTOM"
+ if verticalGrowth == "UP" then
+ y = buttonSpacing
+ buttonPoint = "BOTTOM"
+ anchorPoint = "TOP"
+ end
+ button:Point(buttonPoint, lastColumnButton, anchorPoint, x, y)
+ else
+ local x = buttonSpacing
+ local y = 0
+ local buttonPoint, anchorPoint = "LEFT", "RIGHT"
+ if horizontalGrowth == "LEFT" then
+ x = -buttonSpacing
+ buttonPoint = "RIGHT"
+ anchorPoint = "LEFT"
+ end
+
+ button:Point(buttonPoint, lastButton, anchorPoint, x, y)
+ end
+
+ if i > numButtons then
+ button:SetScale(0.0001)
+ button:SetAlpha(0)
+ else
+ button:SetScale(1)
+ button:SetAlpha(bar.db.alpha)
+ end
+
+ self:StyleButton(button, nil, self.LBFGroup and E.private.actionbar.lbf.enable or nil)
+ end
+
+ if self.LBFGroup and E.private.actionbar.lbf.enable then self.LBFGroup:Skin(E.private.actionbar.lbf.skin) end
+end
+
+function AB:AdjustMaxStanceButtons(event)
+ if InCombatLockdown() then
+ AB.NeedsAdjustMaxStanceButtons = event or true
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ return
+ end
+
+ local visibility = self.db.stanceBar.visibility
+ if visibility and match(visibility, "[\n\r]") then
+ visibility = gsub(visibility, "[\n\r]", "")
+ end
+
+ for i = 1, #bar.buttons do
+ bar.buttons[i]:Hide()
+ end
+
+ local numButtons = GetNumShapeshiftForms()
+ for i = 1, NUM_SHAPESHIFT_SLOTS do
+ if not bar.buttons[i] then
+ bar.buttons[i] = CreateFrame("CheckButton", format(bar:GetName().."Button%d", i), bar, "ShapeshiftButtonTemplate")
+ bar.buttons[i]:SetID(i)
+ if self.LBFGroup and E.private.actionbar.lbf.enable then
+ self.LBFGroup:AddButton(bar.buttons[i])
+ end
+ self:HookScript(bar.buttons[i], "OnEnter", "Button_OnEnter")
+ self:HookScript(bar.buttons[i], "OnLeave", "Button_OnLeave")
+ end
+
+ if i <= numButtons then
+ bar.buttons[i]:Show()
+ bar.LastButton = i
+ else
+ bar.buttons[i]:Hide()
+ end
+ end
+
+ self:PositionAndSizeBarShapeShift()
+
+ -- sometimes after combat lock down `event` may be true because of passing it back with `AB.NeedsAdjustMaxStanceButtons`
+ if event == "UPDATE_SHAPESHIFT_FORMS" then
+ self:StyleShapeShift()
+ end
+
+ RegisterStateDriver(bar, "visibility", (numButtons == 0 and "hide") or visibility)
+end
+
+function AB:UpdateStanceBindings()
+ local color = self.db.fontColor
+
+ for i = 1, NUM_SHAPESHIFT_SLOTS do
+ if self.db.hotkeytext then
+ local key = GetBindingKey("SHAPESHIFTBUTTON"..i)
+ local hotkey = _G["ElvUI_StanceBarButton"..i.."HotKey"]
+ hotkey:Show()
+ hotkey:SetText(key)
+ hotkey:SetTextColor(color.r, color.g, color.b)
+ self:FixKeybindText(_G["ElvUI_StanceBarButton"..i])
+ else
+ _G["ElvUI_StanceBarButton"..i.."HotKey"]:Hide()
+ end
+ end
+end
+
+function AB:CreateBarShapeShift()
+ bar:CreateBackdrop(self.db.transparentBackdrops and "Transparent")
+ bar.backdrop:SetAllPoints()
+ bar:Point("TOPLEFT", E.UIParent, "TOPLEFT", 4, -4)
+ bar.buttons = {}
+
+ self:HookScript(bar, "OnEnter", "Bar_OnEnter")
+ self:HookScript(bar, "OnLeave", "Bar_OnLeave")
+
+ self:RegisterEvent("UPDATE_SHAPESHIFT_FORMS", "AdjustMaxStanceButtons")
+ self:RegisterEvent("UPDATE_SHAPESHIFT_COOLDOWN")
+ self:RegisterEvent("UPDATE_SHAPESHIFT_USABLE", "StyleShapeShift")
+ self:RegisterEvent("UPDATE_SHAPESHIFT_FORM", "StyleShapeShift")
+ self:RegisterEvent("ACTIONBAR_PAGE_CHANGED", "StyleShapeShift")
+ E:ShapeshiftDelayedUpdate(AB.StyleShapeShift, self)
+
+ E:CreateMover(bar, "ShiftAB", L["Stance Bar"], nil, -3, nil, "ALL,ACTIONBARS", nil, "actionbar,stanceBar")
+ self:AdjustMaxStanceButtons()
+ self:PositionAndSizeBarShapeShift()
+ self:StyleShapeShift()
+ self:UpdateStanceBindings()
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/ActionBars/TotemBar.lua b/ElvUI/Modules/ActionBars/TotemBar.lua
new file mode 100644
index 0000000..99f17fd
--- /dev/null
+++ b/ElvUI/Modules/ActionBars/TotemBar.lua
@@ -0,0 +1,347 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local AB = E:GetModule("ActionBars")
+
+--Lua functions
+local _G = _G
+local unpack, ipairs, pairs = unpack, ipairs, pairs
+local gsub, match = string.gsub, string.match
+--WoW API / Variables
+local InCombatLockdown = InCombatLockdown
+local RegisterStateDriver = RegisterStateDriver
+
+local bar = CreateFrame("Frame", "ElvUI_BarTotem", E.UIParent, "SecureHandlerStateTemplate")
+bar:SetFrameStrata("LOW")
+
+local SLOT_BORDER_COLORS = {
+ ["summon"] = {r = 0, g = 0, b = 0},
+ [EARTH_TOTEM_SLOT] = {r = 0.23, g = 0.45, b = 0.13},
+ [FIRE_TOTEM_SLOT] = {r = 0.58, g = 0.23, b = 0.10},
+ [WATER_TOTEM_SLOT] = {r = 0.19, g = 0.48, b = 0.60},
+ [AIR_TOTEM_SLOT] = {r = 0.42, g = 0.18, b = 0.74}
+}
+
+local SLOT_EMPTY_TCOORDS = {
+ [EARTH_TOTEM_SLOT] = {left = 66/128, right = 96/128, top = 3/256, bottom = 33/256},
+ [FIRE_TOTEM_SLOT] = {left = 67/128, right = 97/128, top = 100/256, bottom = 130/256},
+ [WATER_TOTEM_SLOT] = {left = 39/128, right = 69/128, top = 209/256, bottom = 239/256},
+ [AIR_TOTEM_SLOT] = {left = 66/128, right = 96/128, top = 36/256, bottom = 66/256}
+}
+
+local oldMultiCastRecallSpellButton_Update = MultiCastRecallSpellButton_Update
+function MultiCastRecallSpellButton_Update(self)
+ if InCombatLockdown() then AB.NeedRecallButtonUpdate = true; AB:RegisterEvent("PLAYER_REGEN_ENABLED") return end
+
+ oldMultiCastRecallSpellButton_Update(self)
+end
+
+function AB:MultiCastFlyoutFrameOpenButton_Show(button, type, parent)
+ local color = type == "page" and SLOT_BORDER_COLORS.summon or SLOT_BORDER_COLORS[parent:GetID()]
+ button.backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
+
+ button:ClearAllPoints()
+ if AB.db.barTotem.flyoutDirection == "UP" then
+ button:Point("BOTTOM", parent, "TOP")
+ button.icon:SetRotation(0)
+ elseif AB.db.barTotem.flyoutDirection == "DOWN" then
+ button:Point("TOP", parent, "BOTTOM")
+ button.icon:SetRotation(3.14)
+ end
+end
+
+function AB:MultiCastActionButton_Update(button, _, _, slot)
+ local color = SLOT_BORDER_COLORS[slot]
+ if color then
+ button:SetBackdropBorderColor(color.r, color.g, color.b)
+ end
+
+ if InCombatLockdown() then bar.eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED") return end
+ button:ClearAllPoints()
+ button:SetAllPoints(button.slotButton)
+end
+
+function AB:StyleTotemSlotButton(button, slot)
+ local color = SLOT_BORDER_COLORS[slot]
+ if color then
+ button:SetBackdropBorderColor(color.r, color.g, color.b)
+ button.ignoreBorderColors = true
+ end
+end
+
+function AB:SkinSummonButton(button)
+ local name = button:GetName()
+ local icon = _G[name.."Icon"]
+ local highlight = _G[name.."Highlight"]
+ local normal = _G[name.."NormalTexture"]
+
+ button:SetTemplate("Default")
+ button:StyleButton()
+
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetDrawLayer("ARTWORK")
+ icon:SetInside(button)
+
+ highlight:SetTexture(nil)
+ normal:SetTexture(nil)
+end
+
+function AB:MultiCastFlyoutFrame_ToggleFlyout(frame, type, parent)
+ frame.top:SetTexture(nil)
+ frame.middle:SetTexture(nil)
+
+ local color = type == "page" and SLOT_BORDER_COLORS.summon or SLOT_BORDER_COLORS[parent:GetID()]
+ local numButtons = 0
+ for i, button in ipairs(frame.buttons) do
+ if not button.isSkinned then
+ button:SetTemplate("Default")
+ button:StyleButton()
+
+ AB:HookScript(button, "OnEnter", "TotemOnEnter")
+ AB:HookScript(button, "OnLeave", "TotemOnLeave")
+
+ button.icon:SetDrawLayer("ARTWORK")
+ button.icon:SetInside(button)
+
+ bar.buttons[button] = true
+
+ button.isSkinned = true
+ end
+
+ if button:IsShown() then
+ numButtons = numButtons + 1
+ button:Size(AB.db.barTotem.buttonsize)
+ button:ClearAllPoints()
+
+ if AB.db.barTotem.flyoutDirection == "UP" then
+ if i == 1 then
+ button:Point("BOTTOM", parent, "TOP", 0, AB.db.barTotem.flyoutSpacing)
+ else
+ button:Point("BOTTOM", frame.buttons[i - 1], "TOP", 0, AB.db.barTotem.flyoutSpacing)
+ end
+ elseif AB.db.barTotem.flyoutDirection == "DOWN" then
+ if i == 1 then
+ button:Point("TOP", parent, "BOTTOM", 0, -AB.db.barTotem.flyoutSpacing)
+ else
+ button:Point("TOP", frame.buttons[i - 1], "BOTTOM", 0, -AB.db.barTotem.flyoutSpacing)
+ end
+ end
+
+ button:SetBackdropBorderColor(color.r, color.g, color.b)
+
+ button.icon:SetTexCoord(unpack(E.TexCoords))
+ end
+ end
+
+ if type == "slot" then
+ local tCoords = SLOT_EMPTY_TCOORDS[parent:GetID()]
+ frame.buttons[1].icon:SetTexCoord(tCoords.left, tCoords.right, tCoords.top, tCoords.bottom)
+ end
+
+ frame.buttons[1]:SetBackdropBorderColor(color.r, color.g, color.b)
+ MultiCastFlyoutFrameCloseButton.backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
+
+ frame:ClearAllPoints()
+ MultiCastFlyoutFrameCloseButton:ClearAllPoints()
+ if AB.db.barTotem.flyoutDirection == "UP" then
+ frame:Point("BOTTOM", parent, "TOP")
+
+ MultiCastFlyoutFrameCloseButton:Point("TOP", frame, "TOP")
+ MultiCastFlyoutFrameCloseButton.icon:SetRotation(3.14)
+ elseif AB.db.barTotem.flyoutDirection == "DOWN" then
+ frame:Point("TOP", parent, "BOTTOM")
+
+ MultiCastFlyoutFrameCloseButton:Point("BOTTOM", frame, "BOTTOM")
+ MultiCastFlyoutFrameCloseButton.icon:SetRotation(0)
+ end
+
+ frame:Height(((AB.db.barTotem.buttonsize + AB.db.barTotem.flyoutSpacing) * numButtons) + MultiCastFlyoutFrameCloseButton:GetHeight())
+end
+
+function AB:TotemOnEnter()
+ if bar.mouseover then
+ E:UIFrameFadeIn(bar, 0.2, bar:GetAlpha(), AB.db.barTotem.alpha)
+ end
+end
+
+function AB:TotemOnLeave()
+ if bar.mouseover then
+ E:UIFrameFadeOut(bar, 0.2, bar:GetAlpha(), 0)
+ end
+end
+
+function AB:ShowMultiCastActionBar()
+ self:PositionAndSizeBarTotem()
+end
+
+function AB:PositionAndSizeBarTotem()
+ if InCombatLockdown() then
+ AB.NeedsPositionAndSizeBarTotem = true
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ return
+ end
+
+ local buttonSpacing = E:Scale(self.db.barTotem.buttonspacing)
+ local size = E:Scale(self.db.barTotem.buttonsize)
+ local numActiveSlots = MultiCastActionBarFrame.numActiveSlots
+
+ bar:Width((size * (2 + numActiveSlots)) + (buttonSpacing * (2 + numActiveSlots - 1)))
+ MultiCastActionBarFrame:Width((size * (2 + numActiveSlots)) + (buttonSpacing * (2 + numActiveSlots - 1)))
+ bar:Height(size + 2)
+ MultiCastActionBarFrame:Height(size + 2)
+ bar.db = self.db.barTotem
+
+ bar.mouseover = self.db.barTotem.mouseover
+ if bar.mouseover then
+ bar:SetAlpha(0)
+ else
+ bar:SetAlpha(self.db.barTotem.alpha)
+ end
+
+ local visibility = bar.db.visibility
+ if visibility and match(visibility, "[\n\r]") then
+ visibility = gsub(visibility, "[\n\r]","")
+ end
+
+ RegisterStateDriver(bar, "visibility", visibility)
+
+ MultiCastSummonSpellButton:ClearAllPoints()
+ MultiCastSummonSpellButton:Size(size)
+ MultiCastSummonSpellButton:Point("BOTTOMLEFT", E.Border*2, E.Border*2)
+
+ for i = 1, numActiveSlots do
+ local button = _G["MultiCastSlotButton"..i]
+ local lastButton = _G["MultiCastSlotButton"..i - 1]
+
+ button:ClearAllPoints()
+ button:Size(size)
+
+ if i == 1 then
+ button:Point("LEFT", MultiCastSummonSpellButton, "RIGHT", buttonSpacing, 0)
+ else
+ button:Point("LEFT", lastButton, "RIGHT", buttonSpacing, 0)
+ end
+ end
+
+ MultiCastRecallSpellButton:Size(size)
+ MultiCastRecallSpellButton_Update(MultiCastRecallSpellButton)
+
+ MultiCastFlyoutFrameCloseButton:Width(size)
+ MultiCastFlyoutFrameOpenButton:Width(size)
+end
+
+function AB:CreateTotemBar()
+ bar:Point("BOTTOM", E.UIParent, "BOTTOM", 0, 250)
+ bar.buttons = {}
+
+ bar.eventFrame = CreateFrame("Frame")
+ bar.eventFrame:Hide()
+ bar.eventFrame:SetScript("OnEvent", function(self)
+ AB:PositionAndSizeBarTotem()
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED")
+ end)
+
+ MultiCastActionBarFrame:SetParent(bar)
+ MultiCastActionBarFrame:ClearAllPoints()
+ MultiCastActionBarFrame:SetPoint("BOTTOMLEFT", bar, "BOTTOMLEFT", -E.Border, -E.Border)
+ MultiCastActionBarFrame:SetScript("OnUpdate", nil)
+ MultiCastActionBarFrame:SetScript("OnShow", nil)
+ MultiCastActionBarFrame:SetScript("OnHide", nil)
+ MultiCastActionBarFrame.SetParent = E.noop
+ MultiCastActionBarFrame.SetPoint = E.noop
+
+ self:HookScript(MultiCastActionBarFrame, "OnEnter", "TotemOnEnter")
+ self:HookScript(MultiCastActionBarFrame, "OnLeave", "TotemOnLeave")
+
+ self:HookScript(MultiCastFlyoutFrame, "OnEnter", "TotemOnEnter")
+ self:HookScript(MultiCastFlyoutFrame, "OnLeave", "TotemOnLeave")
+
+ local closeButton = MultiCastFlyoutFrameCloseButton
+ closeButton:CreateBackdrop("Default", true, true)
+ closeButton.backdrop:SetPoint("TOPLEFT", 0, -(E.Border + E.Spacing))
+ closeButton.backdrop:SetPoint("BOTTOMRIGHT", 0, E.Border + E.Spacing)
+ closeButton.icon = closeButton:CreateTexture(nil, "ARTWORK")
+ closeButton.icon:Size(16)
+ closeButton.icon:SetPoint("CENTER")
+ closeButton.icon:SetTexture(E.Media.Textures.ArrowUp)
+ closeButton.normalTexture:SetTexture("")
+ closeButton:StyleButton()
+ closeButton.hover:SetInside(closeButton.backdrop)
+ closeButton.pushed:SetInside(closeButton.backdrop)
+ bar.buttons[closeButton] = true
+
+ local openButton = MultiCastFlyoutFrameOpenButton
+ openButton:CreateBackdrop("Default", true, true)
+ openButton.backdrop:SetPoint("TOPLEFT", 0, -(E.Border + E.Spacing))
+ openButton.backdrop:SetPoint("BOTTOMRIGHT", 0, E.Border + E.Spacing)
+ openButton.icon = openButton:CreateTexture(nil, "ARTWORK")
+ openButton.icon:Size(16)
+ openButton.icon:SetPoint("CENTER")
+ openButton.icon:SetTexture(E.Media.Textures.ArrowUp)
+ openButton.normalTexture:SetTexture("")
+ openButton:StyleButton()
+ openButton.hover:SetInside(openButton.backdrop)
+ openButton.pushed:SetInside(openButton.backdrop)
+ bar.buttons[openButton] = true
+
+ self:SkinSummonButton(MultiCastSummonSpellButton)
+ bar.buttons[MultiCastSummonSpellButton] = true
+
+ hooksecurefunc(MultiCastRecallSpellButton, "SetPoint", function(self, point, attachTo, anchorPoint, xOffset, yOffset)
+ if xOffset ~= AB.db.barTotem.buttonspacing then
+ if InCombatLockdown() then AB.NeedRecallButtonUpdate = true AB:RegisterEvent("PLAYER_REGEN_ENABLED") return end
+
+ self:SetPoint(point, attachTo, anchorPoint, AB.db.barTotem.buttonspacing, yOffset)
+ end
+ end)
+
+ self:SkinSummonButton(MultiCastRecallSpellButton)
+ bar.buttons[MultiCastRecallSpellButton] = true
+
+ for i = 1, 4 do
+ local button = _G["MultiCastSlotButton"..i]
+
+ button:StyleButton()
+ button:SetTemplate("Default")
+
+ button.background:SetTexCoord(unpack(E.TexCoords))
+ button.background:SetDrawLayer("ARTWORK")
+ button.background:SetInside(button)
+
+ button.overlay:SetTexture(nil)
+ bar.buttons[button] = true
+ end
+
+ for i = 1, 12 do
+ local button = _G["MultiCastActionButton"..i]
+ local icon = _G["MultiCastActionButton"..i.."Icon"]
+ local normal = _G["MultiCastActionButton"..i.."NormalTexture"]
+ local cooldown = _G["MultiCastActionButton"..i.."Cooldown"]
+
+ button:StyleButton()
+
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetDrawLayer("ARTWORK")
+ icon:SetInside()
+
+ button.overlay:SetTexture(nil)
+ normal:SetTexture(nil)
+ normal:Hide()
+ normal:SetAlpha(0)
+
+ E:RegisterCooldown(cooldown)
+
+ bar.buttons[button] = true
+ end
+
+ for button in pairs(bar.buttons) do
+ button:HookScript("OnEnter", AB.TotemOnEnter)
+ button:HookScript("OnLeave", AB.TotemOnLeave)
+ end
+
+ self:SecureHook("MultiCastFlyoutFrameOpenButton_Show")
+ self:SecureHook("MultiCastActionButton_Update")
+ self:SecureHook("MultiCastSlotButton_Update", "StyleTotemSlotButton")
+ self:SecureHook("MultiCastFlyoutFrame_ToggleFlyout")
+ self:SecureHook("ShowMultiCastActionBar")
+
+ E:CreateMover(bar, "ElvBar_Totem", TUTORIAL_TITLE47, nil, nil, nil,"ALL,ACTIONBARS", nil, "actionbar,barTotem")
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Auras/Auras.lua b/ElvUI/Modules/Auras/Auras.lua
new file mode 100644
index 0000000..bcc0722
--- /dev/null
+++ b/ElvUI/Modules/Auras/Auras.lua
@@ -0,0 +1,648 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local A = E:GetModule("Auras")
+local LSM = E.Libs.LSM
+local LBF = E.Libs.LBF
+
+--Lua functions
+local _G = _G
+local unpack, pairs, ipairs, next, type = unpack, pairs, ipairs, next, type
+local floor, min, max, huge = math.floor, math.min, math.max, math.huge
+local wipe, tinsert, tsort, tremove = table.wipe, table.insert, table.sort, table.remove
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetTime = GetTime
+local UnitAura = UnitAura
+local CancelItemTempEnchantment = CancelItemTempEnchantment
+local CancelUnitBuff = CancelUnitBuff
+local GetInventoryItemQuality = GetInventoryItemQuality
+local GetItemQualityColor = GetItemQualityColor
+local GetWeaponEnchantInfo = GetWeaponEnchantInfo
+local GetInventoryItemTexture = GetInventoryItemTexture
+local DebuffTypeColor = DebuffTypeColor
+
+local DIRECTION_TO_POINT = {
+ DOWN_RIGHT = "TOPLEFT",
+ DOWN_LEFT = "TOPRIGHT",
+ UP_RIGHT = "BOTTOMLEFT",
+ UP_LEFT = "BOTTOMRIGHT",
+ RIGHT_DOWN = "TOPLEFT",
+ RIGHT_UP = "BOTTOMLEFT",
+ LEFT_DOWN = "TOPRIGHT",
+ LEFT_UP = "BOTTOMRIGHT"
+}
+
+local DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER = {
+ DOWN_RIGHT = 1,
+ DOWN_LEFT = -1,
+ UP_RIGHT = 1,
+ UP_LEFT = -1,
+ RIGHT_DOWN = 1,
+ RIGHT_UP = 1,
+ LEFT_DOWN = -1,
+ LEFT_UP = -1
+}
+
+local DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER = {
+ DOWN_RIGHT = -1,
+ DOWN_LEFT = -1,
+ UP_RIGHT = 1,
+ UP_LEFT = 1,
+ RIGHT_DOWN = -1,
+ RIGHT_UP = 1,
+ LEFT_DOWN = -1,
+ LEFT_UP = 1
+}
+
+local IS_HORIZONTAL_GROWTH = {
+ RIGHT_DOWN = true,
+ RIGHT_UP = true,
+ LEFT_DOWN = true,
+ LEFT_UP = true
+}
+
+local enchantableSlots = {
+ [1] = 16,
+ [2] = 17
+}
+
+local weaponEnchantTime = {}
+A.EnchanData = weaponEnchantTime
+
+function A:UpdateTime(elapsed)
+ self.timeLeft = self.timeLeft - elapsed
+
+ self.statusBar:SetValue(self.timeLeft)
+
+ if self.nextUpdate > 0 then
+ self.nextUpdate = self.nextUpdate - elapsed
+ return
+ end
+
+ if self.statusBar:IsShown() and A.db.barColorGradient then
+ self.statusBar:SetStatusBarColor(E.oUF:ColorGradient(self.timeLeft, self.duration or 0, .8, 0, 0, .8, .8, 0, 0, .8, 0))
+ end
+
+ local value, id, nextUpdate, remainder = E:GetTimeInfo(self.timeLeft, self.threshold, self.hhmmThreshold, self.mmssThreshold)
+ self.nextUpdate = nextUpdate
+
+ local style = E.TimeFormats[id]
+ if style then
+ local which = (self.textColors and 2 or 1) + (self.showSeconds and 0 or 2)
+ if self.textColors then
+ self.text:SetFormattedText(style[which], value, self.textColors[id], remainder)
+ else
+ self.text:SetFormattedText(style[which], value, remainder)
+ end
+ end
+
+ local color = self.timeColors[id]
+ if color then
+ self.text:SetTextColor(color.r, color.g, color.b)
+ end
+end
+
+local UpdateTooltip = function(self)
+ if self.IsWeapon then
+ GameTooltip:SetInventoryItem("player", enchantableSlots[self:GetID()])
+ else
+ GameTooltip:SetUnitAura("player", self:GetID(), self:GetParent().filter)
+ end
+end
+
+local OnEnter = function(self)
+ if not self:IsVisible() then return end
+
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT", -5, -5)
+ self:UpdateTooltip()
+end
+
+local OnLeave = function()
+ GameTooltip:Hide()
+end
+
+local OnClick = function(self)
+ if self.IsWeapon then
+ CancelItemTempEnchantment(self:GetID())
+ else
+ CancelUnitBuff("player", self:GetID(), self:GetParent().filter)
+ end
+end
+
+function A:CreateIcon(button)
+ local font = LSM:Fetch("font", self.db.font)
+ local auraType = button:GetParent().filter
+
+ local db = self.db.debuffs
+ button.auraType = "debuffs" -- used to update cooldown text
+ if auraType == "HELPFUL" then
+ db = self.db.buffs
+ button.auraType = "buffs"
+ end
+
+ button:RegisterForClicks("RightButtonUp")
+
+ button.texture = button:CreateTexture(nil, "BORDER")
+ button.texture:SetInside()
+ button.texture:SetTexCoord(unpack(E.TexCoords))
+
+ button.count = button:CreateFontString(nil, "ARTWORK")
+ button.count:Point("BOTTOMRIGHT", -1 + self.db.countXOffset, 1 + self.db.countYOffset)
+ button.count:FontTemplate(font, db.countFontSize, self.db.fontOutline)
+
+ button.text = button:CreateFontString(nil, "ARTWORK")
+ button.text:Point("TOP", button, "BOTTOM", 1 + self.db.timeXOffset, 0 + self.db.timeYOffset)
+
+ button.highlight = button:CreateTexture(nil, "HIGHLIGHT")
+ button.highlight:SetTexture(1, 1, 1, 0.45)
+ button.highlight:SetInside()
+
+ button.statusBar = CreateFrame("StatusBar", "$parentStatusBar", button)
+ button.statusBar:Hide()
+ button.statusBar:SetStatusBarTexture(LSM:Fetch("statusbar", self.db.barTexture))
+ button.statusBar:CreateBackdrop()
+ E:SetSmoothing(button.statusBar)
+
+ E:SetUpAnimGroup(button)
+
+ -- support cooldown override
+ if not button.isRegisteredCooldown then
+ button.CooldownOverride = "auras"
+ button.isRegisteredCooldown = true
+ button.forceEnabled = true
+ button.showSeconds = true
+
+ if not E.RegisteredCooldowns.auras then E.RegisteredCooldowns.auras = {} end
+ tinsert(E.RegisteredCooldowns.auras, button)
+ end
+
+ button.text:FontTemplate(font, db.durationFontSize, self.db.fontOutline)
+
+ A:Update_CooldownOptions(button)
+
+ button.UpdateTooltip = UpdateTooltip
+ button:SetScript("OnEnter", OnEnter)
+ button:SetScript("OnLeave", OnLeave)
+ button:SetScript("OnClick", OnClick)
+
+ if self.LBFGroup and E.private.auras.lbf.enable then
+ local ButtonData = {
+ Icon = button.texture,
+ Flash = nil,
+ Cooldown = nil,
+ AutoCast = nil,
+ AutoCastable = nil,
+ HotKey = nil,
+ Count = false,
+ Name = nil,
+ Highlight = button.highlight
+ }
+
+ self.LBFGroup:AddButton(button, ButtonData)
+ else
+ button:SetTemplate("Default")
+ end
+end
+
+function A:SetAuraTime(button, expiration, duration)
+ button.duration = duration
+ button.statusBar:SetMinMaxValues(0, duration)
+
+ button.nextUpdate = 0
+
+ if not button.timeLeft then
+ button.timeLeft = expiration
+ button:SetScript("OnUpdate", self.UpdateTime)
+ else
+ button.timeLeft = expiration
+ end
+end
+
+function A:ClearAuraTime(button, expired)
+ if not expired then
+ button.statusBar:SetValue(1)
+ button.statusBar:SetMinMaxValues(0, 1)
+ end
+
+ button.timeLeft = nil
+ button.text:SetText("")
+ button:SetScript("OnUpdate", nil)
+end
+
+function A:HasEnchant(index, weapon, expiration)
+ if not weapon then
+ if weaponEnchantTime[index] then
+ weaponEnchantTime[index] = nil
+ return true
+ end
+ return
+ end
+
+ if not weaponEnchantTime[index] or weaponEnchantTime[index] < expiration then
+ weaponEnchantTime[index] = expiration
+ return true
+ end
+
+ weaponEnchantTime[index] = expiration
+end
+
+function A:Update_CooldownOptions(button)
+ E:Cooldown_Options(button, self.db.cooldown, button)
+end
+
+local buttons = {}
+function A:ConfigureAuras(header, auraTable, weaponPosition)
+ local headerName = header:GetName()
+ local db = self.db.debuffs
+ if header.filter == "HELPFUL" then
+ db = self.db.buffs
+ end
+
+ local xOffset, yOffset, wrapXOffset, wrapYOffset, minWidth, minHeight
+ local size = db.size
+ local point = DIRECTION_TO_POINT[db.growthDirection]
+ local wrapAfter = db.wrapAfter
+ local maxWraps = db.maxWraps
+
+ if IS_HORIZONTAL_GROWTH[db.growthDirection] then
+ minWidth = ((wrapAfter == 1 and 0 or db.horizontalSpacing) + size) * wrapAfter
+ minHeight = (db.verticalSpacing + size) * maxWraps
+ xOffset = DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER[db.growthDirection] * (db.horizontalSpacing + size)
+ yOffset = 0
+ wrapXOffset = 0
+ wrapYOffset = DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER[db.growthDirection] * (db.verticalSpacing + size)
+ else
+ minWidth = (db.horizontalSpacing + size) * maxWraps
+ minHeight = ((wrapAfter == 1 and 0 or db.verticalSpacing) + size) * wrapAfter
+ xOffset = 0
+ yOffset = DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER[db.growthDirection] * (db.verticalSpacing + size)
+ wrapXOffset = DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER[db.growthDirection] * (db.horizontalSpacing + size)
+ wrapYOffset = 0
+ end
+
+ wipe(buttons)
+ local button
+ for i = 1, #auraTable do
+ button = _G[headerName.."AuraButton"..i]
+ if button then
+ if button:IsShown() then button:Hide() end
+ else
+ button = CreateFrame("Button", "$parentAuraButton"..i, header)
+ self:CreateIcon(button)
+ end
+ local buffInfo = auraTable[i]
+ button:SetID(buffInfo.index)
+
+ if buffInfo.duration > 0 and buffInfo.expires then
+ A:SetAuraTime(button, buffInfo.expires - GetTime(), buffInfo.duration)
+ else
+ A:ClearAuraTime(button)
+ end
+
+ if buffInfo.count > 1 then
+ button.count:SetText(buffInfo.count)
+ else
+ button.count:SetText("")
+ end
+
+ if (self.db.barShow and buffInfo.duration > 0) or (self.db.barShow and self.db.barNoDuration and buffInfo.duration == 0) then
+ button.statusBar:Show()
+
+ if not button.timeLeft or not self.db.barColorGradient then
+ button.statusBar:SetStatusBarColor(self.db.barColor.r, self.db.barColor.g, self.db.barColor.b)
+ end
+ else
+ button.statusBar:Hide()
+ end
+
+ if self.db.showDuration then
+ button.text:Show()
+ else
+ button.text:Hide()
+ end
+
+ if buffInfo.filter == "HARMFUL" then
+ local color = DebuffTypeColor[buffInfo.dispelType or ""]
+ button:SetBackdropBorderColor(color.r, color.g, color.b)
+ button.statusBar.backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
+ else
+ local cr, cg, cb = unpack(E.media.bordercolor)
+ button:SetBackdropBorderColor(cr, cg, cb)
+ button.statusBar.backdrop:SetBackdropBorderColor(cr, cg, cb)
+ end
+
+ button.texture:SetTexture(buffInfo.icon)
+
+ buttons[i] = button
+ end
+
+ if weaponPosition then
+ for weapon = 2, 1, -1 do
+ button = _G["ElvUIPlayerBuffsTempEnchant"..weapon]
+ if weaponEnchantTime[weapon] then
+ if not button then
+ button = CreateFrame("Button", "$parentTempEnchant"..weapon, header)
+ button.IsWeapon = true
+ self:CreateIcon(button)
+ end
+ if button then
+ if button:IsShown() then button:Hide() end
+
+ button:SetID(weapon)
+ local index = enchantableSlots[weapon]
+ button.texture:SetTexture(GetInventoryItemTexture("player", index))
+
+ button:SetBackdropBorderColor(GetItemQualityColor(GetInventoryItemQuality("player", index) or 1))
+
+ local duration = 600
+ local expirationTime = weaponEnchantTime[weapon]
+ if expirationTime then
+ expirationTime = expirationTime / 1000
+ if expirationTime <= 3600 and expirationTime > 1800 then
+ duration = 3600
+ elseif expirationTime <= 1800 and expirationTime > 600 then
+ duration = 1800
+ end
+
+ A:SetAuraTime(button, expirationTime, duration)
+ else
+ A:ClearAuraTime(button)
+ end
+
+ if (self.db.barShow and duration > 0) or (self.db.barShow and self.db.barNoDuration and duration == 0) then
+ button.statusBar:Show()
+
+ if not button.timeLeft or not self.db.barColorGradient then
+ button.statusBar:SetStatusBarColor(self.db.barColor.r, self.db.barColor.g, self.db.barColor.b)
+ end
+ else
+ button.statusBar:Hide()
+ end
+
+ if self.db.showDuration then
+ button.text:Show()
+ else
+ button.text:Hide()
+ end
+
+ if weaponPosition == 0 then
+ tinsert(buttons, button)
+ else
+ tinsert(buttons, weaponPosition, button)
+ end
+ end
+ else
+ if button and type(button.Hide) == "function" then
+ button:Hide()
+ end
+ end
+ end
+ end
+
+ local display = #buttons
+ if wrapAfter and maxWraps then
+ display = min(display, wrapAfter * maxWraps)
+ end
+
+ local pos, spacing, iconSize = self.db.barPosition, self.db.barSpacing, db.size - (E.Border * 2)
+ local isOnTop = pos == "TOP" and true or false
+ local isOnBottom = pos == "BOTTOM" and true or false
+ local isOnLeft = pos == "LEFT" and true or false
+ local isOnRight = pos == "RIGHT" and true or false
+
+ local left, right, top, bottom = huge, -huge, -huge, huge
+ for index = 1, display do
+ button = buttons[index]
+ local tick, cycle = floor((index - 1) % wrapAfter), floor((index - 1) / wrapAfter)
+ button:ClearAllPoints()
+ button:SetPoint(point, header, cycle * wrapXOffset + tick * xOffset, cycle * wrapYOffset + tick * yOffset)
+
+ button:SetSize(size, size)
+
+ if button.text then
+ local font = LSM:Fetch("font", self.db.font)
+ button.text:ClearAllPoints()
+ button.text:Point("TOP", button, "BOTTOM", 1 + self.db.timeXOffset, 0 + self.db.timeYOffset)
+ button.text:FontTemplate(font, db.durationFontSize, self.db.fontOutline)
+
+ button.count:ClearAllPoints()
+ button.count:Point("BOTTOMRIGHT", -1 + self.db.countXOffset, 0 + self.db.countYOffset)
+ button.count:FontTemplate(font, db.countFontSize, self.db.fontOutline)
+ end
+
+ button.statusBar:Width((isOnTop or isOnBottom) and iconSize or (self.db.barWidth + (E.PixelMode and 0 or 2)))
+ button.statusBar:Height((isOnLeft or isOnRight) and iconSize or (self.db.barHeight + (E.PixelMode and 0 or 2)))
+ button.statusBar:ClearAllPoints()
+ button.statusBar:Point(E.InversePoints[pos], button, pos, (isOnTop or isOnBottom) and 0 or ((isOnLeft and -((E.PixelMode and 1 or 3) + spacing)) or ((E.PixelMode and 1 or 3) + spacing)), (isOnLeft or isOnRight) and 0 or ((isOnTop and ((E.PixelMode and 1 or 3) + spacing) or -((E.PixelMode and 1 or 3) + spacing))))
+ button.statusBar:SetStatusBarTexture(LSM:Fetch("statusbar", self.db.barTexture))
+ if isOnLeft or isOnRight then
+ button.statusBar:SetOrientation("VERTICAL")
+ else
+ button.statusBar:SetOrientation("HORIZONTAL")
+ end
+
+ button:Show()
+ left = min(left, button:GetLeft() or huge)
+ right = max(right, button:GetRight() or -huge)
+ top = max(top, button:GetTop() or -huge)
+ bottom = min(bottom, button:GetBottom() or huge)
+ end
+ local deadIndex = #(auraTable) + 1
+ button = _G[headerName.."AuraButton"..deadIndex]
+ while button do
+ if button:IsShown() then button:Hide() end
+ deadIndex = deadIndex + 1
+ button = _G[headerName.."AuraButton"..deadIndex]
+ end
+
+ if display >= 1 then
+ header:SetWidth(max(right - left, minWidth))
+ header:SetHeight(max(top - bottom, minHeight))
+ else
+ header:SetWidth(minWidth)
+ header:SetHeight(minHeight)
+ end
+end
+
+local freshTable
+local releaseTable
+do
+ local tableReserve = {}
+ freshTable = function ()
+ local t = next(tableReserve) or {}
+ tableReserve[t] = nil
+ return t
+ end
+ releaseTable = function (t)
+ tableReserve[t] = wipe(t)
+ end
+end
+
+local function sortFactory(key, separateOwn, reverse)
+ if separateOwn ~= 0 then
+ if reverse then
+ return function(a, b)
+ if a.filter == b.filter then
+ local ownA, ownB = a.caster == "player", b.caster == "player"
+ if ownA ~= ownB then
+ return ownA == (separateOwn > 0)
+ end
+ return a[key] > b[key]
+ else
+ return a.filter < b.filter
+ end
+ end;
+ else
+ return function(a, b)
+ if a.filter == b.filter then
+ local ownA, ownB = a.caster == "player", b.caster == "player"
+ if ownA ~= ownB then
+ return ownA == (separateOwn > 0)
+ end
+ return a[key] < b[key]
+ else
+ return a.filter < b.filter
+ end
+ end;
+ end
+ else
+ if reverse then
+ return function(a, b)
+ if a.filter == b.filter then
+ return a[key] > b[key]
+ else
+ return a.filter < b.filter
+ end
+ end;
+ else
+ return function(a, b)
+ if a.filter == b.filter then
+ return a[key] < b[key]
+ else
+ return a.filter < b.filter
+ end
+ end;
+ end
+ end
+end
+
+local sorters = {}
+for _, key in ipairs{"index", "name", "expires"} do
+ local label = string.upper(key)
+ sorters[label] = {}
+ for bool in pairs{[true] = true, [false] = false} do
+ sorters[label][bool] = {}
+ for sep = -1, 1 do
+ sorters[label][bool][sep] = sortFactory(key, sep, bool)
+ end
+ end
+end
+sorters.TIME = sorters.EXPIRES
+
+local sortingTable = {}
+function A:UpdateHeader(header)
+ local filter = header.filter
+ local db = self.db.debuffs
+
+ wipe(sortingTable)
+
+ local weaponPosition
+ if filter == "HELPFUL" then
+ db = self.db.buffs
+ weaponPosition = 1
+ end
+
+ local i = 1
+ repeat
+ local aura, _ = freshTable()
+ aura.name, _, aura.icon, aura.count, aura.dispelType, aura.duration, aura.expires, aura.caster = UnitAura("player", i, filter)
+ if aura.name then
+ aura.filter = filter
+ aura.index = i
+
+ tinsert(sortingTable, aura)
+ else
+ releaseTable(aura)
+ end
+ i = i + 1
+ until not aura.name
+
+ local sortMethod = (sorters[db.sortMethod] or sorters.INDEX)[db.sortDir == "-"][db.seperateOwn]
+ tsort(sortingTable, sortMethod)
+
+ self:ConfigureAuras(header, sortingTable, weaponPosition)
+ while sortingTable[1] do
+ releaseTable(tremove(sortingTable))
+ end
+
+ if self.LBFGroup then
+ self.LBFGroup:Skin(E.private.auras.lbf.skin)
+ end
+end
+
+function A:CreateAuraHeader(filter)
+ local name = "ElvUIPlayerDebuffs"
+ if filter == "HELPFUL" then
+ name = "ElvUIPlayerBuffs"
+ end
+
+ local header = CreateFrame("Frame", name, UIParent)
+ header:SetClampedToScreen(true)
+ header.filter = filter
+
+ header:RegisterEvent("UNIT_AURA")
+ header:SetScript("OnEvent", function(self, _, unit)
+ if unit ~= "player" then return end
+
+ A:UpdateHeader(self)
+ end)
+
+ self:UpdateHeader(header)
+
+ return header
+end
+
+function A:Initialize()
+ if E.private.auras.disableBlizzard then
+ BuffFrame:Kill()
+ ConsolidatedBuffs:Kill()
+ TemporaryEnchantFrame:Kill()
+ end
+
+ if not E.private.auras.enable then return end
+
+ self.Initialized = true
+ self.db = E.db.auras
+
+ if LBF then
+ self.LBFGroup = LBF and LBF:Group("ElvUI", "Auras")
+ end
+
+ self.BuffFrame = self:CreateAuraHeader("HELPFUL")
+ self.BuffFrame:Point("TOPRIGHT", MMHolder, "TOPLEFT", -(6 + E.Border), -E.Border - E.Spacing)
+ E:CreateMover(self.BuffFrame, "BuffsMover", L["Player Buffs"], nil, nil, nil, nil, nil, "auras,buffs")
+
+ self.BuffFrame.nextUpdate = -1
+ self.BuffFrame:SetScript("OnUpdate", function(bf, elapsed)
+ if bf.nextUpdate > 0 then
+ bf.nextUpdate = bf.nextUpdate - elapsed
+ return
+ end
+
+ bf.nextUpdate = 1
+
+ local hasMainHandEnchant, mainHandExpiration, _, hasOffHandEnchant, offHandExpiration = GetWeaponEnchantInfo()
+ if A:HasEnchant(1, hasMainHandEnchant, mainHandExpiration) or A:HasEnchant(2, hasOffHandEnchant, offHandExpiration) then
+ A:UpdateHeader(bf)
+ end
+ end)
+
+ self.DebuffFrame = self:CreateAuraHeader("HARMFUL")
+ self.DebuffFrame:Point("BOTTOMRIGHT", MMHolder, "BOTTOMLEFT", -(6 + E.Border), E.Border + E.Spacing)
+ E:CreateMover(self.DebuffFrame, "DebuffsMover", L["Player Debuffs"], nil, nil, nil, nil, nil, "auras,debuffs")
+end
+
+local function InitializeCallback()
+ A:Initialize()
+end
+
+E:RegisterModule(A:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Auras/Load_Auras.xml b/ElvUI/Modules/Auras/Load_Auras.xml
new file mode 100644
index 0000000..2be9b8a
--- /dev/null
+++ b/ElvUI/Modules/Auras/Load_Auras.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/Bags/BagBar.lua b/ElvUI/Modules/Bags/BagBar.lua
new file mode 100644
index 0000000..073c7d5
--- /dev/null
+++ b/ElvUI/Modules/Bags/BagBar.lua
@@ -0,0 +1,181 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local B = E:GetModule("Bags")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+local tinsert = table.insert
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local CursorHasItem = CursorHasItem
+local PutKeyInKeyRing = PutKeyInKeyRing
+local RegisterStateDriver = RegisterStateDriver
+local ToggleKeyRing = ToggleKeyRing
+
+local KEYRING = KEYRING
+local NUM_BAG_FRAMES = NUM_BAG_FRAMES
+
+local function OnEnter()
+ if not E.db.bags.bagBar.mouseover then return end
+ E:UIFrameFadeOut(ElvUIBags, 0.2, ElvUIBags:GetAlpha(), 1)
+end
+
+local function OnLeave()
+ if not E.db.bags.bagBar.mouseover then return end
+ E:UIFrameFadeOut(ElvUIBags, 0.2, ElvUIBags:GetAlpha(), 0)
+end
+
+function B:SkinBag(bag)
+ local icon = _G[bag:GetName().."IconTexture"]
+ bag.oldTex = icon:GetTexture()
+
+ bag:StripTextures()
+ bag:SetTemplate(nil, true)
+ bag:StyleButton(true)
+
+ icon:SetTexture(bag.oldTex)
+ icon:SetInside()
+ icon:SetTexCoord(unpack(E.TexCoords))
+end
+
+function B:SizeAndPositionBagBar()
+ if not ElvUIBags then return end
+
+ local buttonSpacing = E:Scale(E.db.bags.bagBar.spacing)
+ local backdropSpacing = E:Scale(E.db.bags.bagBar.backdropSpacing)
+ local bagBarSize = E:Scale(E.db.bags.bagBar.size)
+ local showBackdrop = E.db.bags.bagBar.showBackdrop
+ local growthDirection = E.db.bags.bagBar.growthDirection
+ local sortDirection = E.db.bags.bagBar.sortDirection
+
+ local visibility = E.db.bags.bagBar.visibility
+ if visibility and string.match(visibility, "[\n\r]") then
+ visibility = string.gsub(visibility, "[\n\r]","")
+ end
+
+ RegisterStateDriver(ElvUIBags, "visibility", visibility)
+
+ if E.db.bags.bagBar.mouseover then
+ ElvUIBags:SetAlpha(0)
+ else
+ ElvUIBags:SetAlpha(1)
+ end
+
+ if showBackdrop then
+ ElvUIBags.backdrop:Show()
+ else
+ ElvUIBags.backdrop:Hide()
+ end
+
+ ElvUIKeyRingButton:Size(bagBarSize)
+ ElvUIKeyRingButton:ClearAllPoints()
+
+ local bdpSpacing = (showBackdrop and backdropSpacing + E.Border) or 0
+ local btnSpacing = (buttonSpacing + E.Border)
+
+ for i = 1, #ElvUIBags.buttons do
+ local button = ElvUIBags.buttons[i]
+ local prevButton = ElvUIBags.buttons[i-1]
+ button:SetSize(bagBarSize, bagBarSize)
+ button:ClearAllPoints()
+
+ if growthDirection == "HORIZONTAL" and sortDirection == "ASCENDING" then
+ if i == 1 then
+ button:SetPoint("LEFT", ElvUIBags, "LEFT", bdpSpacing, 0)
+ elseif prevButton then
+ button:SetPoint("LEFT", prevButton, "RIGHT", btnSpacing, 0)
+ end
+ elseif growthDirection == "VERTICAL" and sortDirection == "ASCENDING" then
+ if i == 1 then
+ button:SetPoint("TOP", ElvUIBags, "TOP", 0, -bdpSpacing)
+ elseif prevButton then
+ button:SetPoint("TOP", prevButton, "BOTTOM", 0, -btnSpacing)
+ end
+ elseif growthDirection == "HORIZONTAL" and sortDirection == "DESCENDING" then
+ if i == 1 then
+ button:SetPoint("RIGHT", ElvUIBags, "RIGHT", -bdpSpacing, 0)
+ elseif prevButton then
+ button:SetPoint("RIGHT", prevButton, "LEFT", -btnSpacing, 0)
+ end
+ else
+ if i == 1 then
+ button:SetPoint("BOTTOM", ElvUIBags, "BOTTOM", 0, bdpSpacing)
+ elseif prevButton then
+ button:SetPoint("BOTTOM", prevButton, "TOP", 0, btnSpacing)
+ end
+ end
+ end
+
+ local btnSize = bagBarSize * (NUM_BAG_FRAMES + 2)
+ local btnSpace = btnSpacing * (NUM_BAG_FRAMES + 1)
+ local bdpDoubled = bdpSpacing * 2
+
+ if growthDirection == 'HORIZONTAL' then
+ ElvUIBags:SetWidth(btnSize + btnSpace + bdpDoubled)
+ ElvUIBags:SetHeight(bagBarSize + bdpDoubled)
+ else
+ ElvUIBags:SetHeight(btnSize + btnSpace + bdpDoubled)
+ ElvUIBags:SetWidth(bagBarSize + bdpDoubled)
+ end
+end
+
+function B:LoadBagBar()
+ if not E.private.bags.bagBar then return end
+
+ local ElvUIBags = CreateFrame("Frame", "ElvUIBags", E.UIParent)
+ ElvUIBags:Point("TOPRIGHT", RightChatPanel, "TOPLEFT", -4, 0)
+ ElvUIBags.buttons = {}
+ ElvUIBags:CreateBackdrop(E.db.bags.transparent and "Transparent")
+ ElvUIBags.backdrop:SetAllPoints()
+ ElvUIBags:EnableMouse(true)
+ ElvUIBags:SetScript("OnEnter", OnEnter)
+ ElvUIBags:SetScript("OnLeave", OnLeave)
+
+ MainMenuBarBackpackButton:SetParent(ElvUIBags)
+ MainMenuBarBackpackButton.SetParent = E.noop
+ MainMenuBarBackpackButton:ClearAllPoints()
+
+ MainMenuBarBackpackButtonCount:FontTemplate(nil, 10)
+ MainMenuBarBackpackButtonCount:ClearAllPoints()
+ MainMenuBarBackpackButtonCount:Point("BOTTOMRIGHT", MainMenuBarBackpackButton, "BOTTOMRIGHT", -1, 4)
+
+ MainMenuBarBackpackButton:HookScript("OnEnter", OnEnter)
+ MainMenuBarBackpackButton:HookScript("OnLeave", OnLeave)
+
+ tinsert(ElvUIBags.buttons, MainMenuBarBackpackButton)
+ self:SkinBag(MainMenuBarBackpackButton)
+
+ for i = 0, NUM_BAG_FRAMES - 1 do
+ local b = _G["CharacterBag"..i.."Slot"]
+ b:SetParent(ElvUIBags)
+ b.SetParent = E.noop
+ b:HookScript("OnEnter", OnEnter)
+ b:HookScript("OnLeave", OnLeave)
+
+ self:SkinBag(b)
+ tinsert(ElvUIBags.buttons, b)
+ end
+
+ local ElvUIKeyRing = CreateFrame("CheckButton", "ElvUIKeyRingButton", UIParent, "ItemButtonTemplate")
+ ElvUIKeyRing:StripTextures()
+ ElvUIKeyRing:SetTemplate()
+ ElvUIKeyRing:StyleButton(true)
+ ElvUIKeyRing:SetParent(ElvUIBags)
+ ElvUIKeyRing.SetParent = E.noop
+ ElvUIKeyRing:RegisterForClicks("anyUp")
+
+ _G[ElvUIKeyRing:GetName().."IconTexture"]:SetTexture("Interface\\ContainerFrame\\KeyRing-Bag-Icon")
+ _G[ElvUIKeyRing:GetName().."IconTexture"]:SetInside()
+ _G[ElvUIKeyRing:GetName().."IconTexture"]:SetTexCoord(unpack(E.TexCoords))
+
+ ElvUIKeyRing:SetScript("OnClick", function() if CursorHasItem() then PutKeyInKeyRing() else ToggleKeyRing() end end)
+ ElvUIKeyRing:SetScript("OnReceiveDrag", function() if CursorHasItem() then PutKeyInKeyRing() end end)
+ ElvUIKeyRing:SetScript("OnEnter", function(self) GameTooltip:SetOwner(self, "ANCHOR_LEFT") GameTooltip:SetText(KEYRING, 1, 1, 1) OnEnter() end)
+ ElvUIKeyRing:SetScript("OnLeave",function() GameTooltip:Hide() OnLeave() end)
+
+ tinsert(ElvUIBags.buttons, ElvUIKeyRing)
+
+ self:SizeAndPositionBagBar()
+
+ E:CreateMover(ElvUIBags, "BagsMover", L["Bags"], nil, nil, nil, nil, nil, "bags,general")
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Bags/Bags.lua b/ElvUI/Modules/Bags/Bags.lua
new file mode 100644
index 0000000..4e71793
--- /dev/null
+++ b/ElvUI/Modules/Bags/Bags.lua
@@ -0,0 +1,1867 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local B = E:GetModule("Bags")
+local TT = E:GetModule("Tooltip")
+local Skins = E:GetModule("Skins")
+local Search = E.Libs.ItemSearch
+
+--Lua functions
+local _G = _G
+local type, ipairs, pairs, unpack, select, assert, pcall = type, ipairs, pairs, unpack, select, assert, pcall
+local floor, ceil, abs = math.floor, math.ceil, math.abs
+local format, sub, gsub = string.format, string.sub, string.gsub
+local tinsert, tremove, twipe = table.insert, table.remove, table.wipe
+--WoW API / Variables
+local BankFrameItemButton_Update = BankFrameItemButton_Update
+local BankFrameItemButton_UpdateLocked = BankFrameItemButton_UpdateLocked
+local CloseBag, CloseBackpack, CloseBankFrame = CloseBag, CloseBackpack, CloseBankFrame
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local CreateFrame = CreateFrame
+local DeleteCursorItem = DeleteCursorItem
+local GameTooltip_Hide = GameTooltip_Hide
+local GetBackpackCurrencyInfo = GetBackpackCurrencyInfo
+local GetContainerItemCooldown = GetContainerItemCooldown
+local GetContainerItemID = GetContainerItemID
+local GetContainerItemInfo = GetContainerItemInfo
+local GetContainerItemLink = GetContainerItemLink
+local GetContainerItemQuestInfo = GetContainerItemQuestInfo
+local GetContainerNumFreeSlots = GetContainerNumFreeSlots
+local GetContainerNumSlots = GetContainerNumSlots
+local GetCurrentGuildBankTab = GetCurrentGuildBankTab
+local GetCVarBool = GetCVarBool
+local GetGuildBankItemLink = GetGuildBankItemLink
+local GetGuildBankTabInfo = GetGuildBankTabInfo
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local GetMoney = GetMoney
+local GetNumBankSlots = GetNumBankSlots
+local GetKeyRingSize = GetKeyRingSize
+local GetScreenWidth, GetScreenHeight = GetScreenWidth, GetScreenHeight
+local IsBagOpen, IsOptionFrameOpen = IsBagOpen, IsOptionFrameOpen
+local IsModifiedClick = IsModifiedClick
+local IsShiftKeyDown, IsControlKeyDown = IsShiftKeyDown, IsControlKeyDown
+local PickupContainerItem = PickupContainerItem
+local PlaySound = PlaySound
+local PutItemInBackpack = PutItemInBackpack
+local PutItemInBag = PutItemInBag
+local SetItemButtonCount = SetItemButtonCount
+local SetItemButtonDesaturated = SetItemButtonDesaturated
+local SetItemButtonTexture = SetItemButtonTexture
+local SetItemButtonTextureVertexColor = SetItemButtonTextureVertexColor
+local ToggleFrame = ToggleFrame
+local UseContainerItem = UseContainerItem
+
+local BACKPACK_TOOLTIP = BACKPACK_TOOLTIP
+local BINDING_NAME_TOGGLEKEYRING = BINDING_NAME_TOGGLEKEYRING
+local CONTAINER_OFFSET_X, CONTAINER_OFFSET_Y = CONTAINER_OFFSET_X, CONTAINER_OFFSET_Y
+local CONTAINER_SCALE = CONTAINER_SCALE
+local CONTAINER_SPACING, VISIBLE_CONTAINER_SPACING = CONTAINER_SPACING, VISIBLE_CONTAINER_SPACING
+local CONTAINER_WIDTH = CONTAINER_WIDTH
+local ITEM_ACCOUNTBOUND = ITEM_ACCOUNTBOUND
+local ITEM_BIND_ON_EQUIP = ITEM_BIND_ON_EQUIP
+local ITEM_BIND_ON_USE = ITEM_BIND_ON_USE
+local ITEM_BNETACCOUNTBOUND = ITEM_BNETACCOUNTBOUND
+local ITEM_SOULBOUND = ITEM_SOULBOUND
+local KEYRING_CONTAINER = KEYRING_CONTAINER
+local MAX_CONTAINER_ITEMS = MAX_CONTAINER_ITEMS
+local MAX_WATCHED_TOKENS = MAX_WATCHED_TOKENS
+local NUM_BAG_FRAMES = NUM_BAG_FRAMES
+local NUM_CONTAINER_FRAMES = NUM_CONTAINER_FRAMES
+local SEARCH = SEARCH
+
+local SEARCH_STRING = ""
+
+function B:GetContainerFrame(arg)
+ if type(arg) == "boolean" and arg == true then
+ return B.BankFrame
+ elseif type(arg) == "number" then
+ if B.BankFrame then
+ for _, bagID in ipairs(B.BankFrame.BagIDs) do
+ if bagID == arg then
+ return B.BankFrame
+ end
+ end
+ end
+ end
+
+ return B.BagFrame
+end
+
+function B:Tooltip_Show()
+ GameTooltip:SetOwner(self)
+ GameTooltip:ClearLines()
+ GameTooltip:AddLine(self.ttText)
+
+ if self.ttText2 then
+ if self.ttText2desc then
+ GameTooltip:AddLine(" ")
+ GameTooltip:AddDoubleLine(self.ttText2, self.ttText2desc, 1, 1, 1)
+ else
+ GameTooltip:AddLine(self.ttText2)
+ end
+ end
+
+ GameTooltip:Show()
+end
+
+function B:DisableBlizzard()
+ BankFrame:UnregisterAllEvents()
+
+ for i = 1, NUM_CONTAINER_FRAMES do
+ _G["ContainerFrame"..i]:Kill()
+ end
+end
+
+function B:SearchReset()
+ SEARCH_STRING = ""
+end
+
+function B:IsSearching()
+ return SEARCH_STRING ~= "" and SEARCH_STRING ~= SEARCH
+end
+
+function B:UpdateSearch()
+ local search = self:GetText()
+ if self.Instructions then
+ self.Instructions:SetShown(search == "")
+ end
+
+ local MIN_REPEAT_CHARACTERS = 3
+ local prevSearch = SEARCH_STRING
+ if #search > MIN_REPEAT_CHARACTERS then
+ local repeatChar = true
+ for i = 1, MIN_REPEAT_CHARACTERS, 1 do
+ if sub(search,(0 - i), (0 - i)) ~= sub(search,(-1 - i),(-1 - i)) then
+ repeatChar = false
+ break
+ end
+ end
+
+ if repeatChar then
+ B:ResetAndClear()
+ return
+ end
+ end
+
+ --Keep active search term when switching between bank and reagent bank
+ if search == SEARCH and prevSearch ~= "" then
+ search = prevSearch
+ elseif search == SEARCH then
+ search = ""
+ end
+
+ SEARCH_STRING = search
+
+ B:RefreshSearch()
+ B:SetGuildBankSearch(SEARCH_STRING)
+end
+
+function B:OpenEditbox()
+ B.BagFrame.detail:Hide()
+ B.BagFrame.editBox:Show()
+ B.BagFrame.editBox:SetText(SEARCH)
+ B.BagFrame.editBox:HighlightText()
+end
+
+function B:ResetAndClear()
+ B.BagFrame.editBox:SetText(SEARCH)
+ B.BagFrame.editBox:ClearFocus()
+
+ if B.BankFrame then
+ B.BankFrame.editBox:SetText(SEARCH)
+ B.BankFrame.editBox:ClearFocus()
+ end
+
+ B:SearchReset()
+end
+
+function B:SetSearch(query)
+ local empty = (gsub(query, "%s+", "")) == ""
+
+ for _, bagFrame in pairs(B.BagFrames) do
+ for _, bagID in ipairs(bagFrame.BagIDs) do
+ for slotID = 1, GetContainerNumSlots(bagID) do
+ local _, _, _, _, _, _, link = GetContainerItemInfo(bagID, slotID)
+ local button = bagFrame.Bags[bagID][slotID]
+ local success, result = pcall(Search.Matches, Search, link, query)
+
+ if empty or (success and result) then
+ SetItemButtonDesaturated(button, button.locked or button.junkDesaturate)
+ button.searchOverlay:Hide()
+ button:SetAlpha(1)
+ else
+ SetItemButtonDesaturated(button, 1)
+ button.searchOverlay:Show()
+ button:SetAlpha(0.5)
+ end
+ end
+ end
+ end
+
+ if ElvUIKeyFrameItem1 then
+ local numKey = GetKeyRingSize()
+ for slotID = 1, numKey do
+ local button = _G["ElvUIKeyFrameItem"..slotID]
+ if button then
+ local _, _, _, _, _, _, link = GetContainerItemInfo(KEYRING_CONTAINER, slotID)
+ local success, result = pcall(Search.Matches, Search, link, query)
+ if empty or (success and result) then
+ SetItemButtonDesaturated(button, button.locked or button.junkDesaturate)
+ button.searchOverlay:Hide()
+ button:SetAlpha(1)
+ else
+ SetItemButtonDesaturated(button, 1)
+ button.searchOverlay:Show()
+ button:SetAlpha(0.5)
+ end
+ end
+ end
+ end
+end
+
+function B:SetGuildBankSearch(query)
+ if GuildBankFrame and GuildBankFrame:IsShown() then
+ local tab = GetCurrentGuildBankTab()
+ local _, _, isViewable = GetGuildBankTabInfo(tab)
+
+ if isViewable then
+ local empty = (gsub(query, "%s+", "")) == ""
+
+ for slotID = 1, MAX_GUILDBANK_SLOTS_PER_TAB do
+ local link = GetGuildBankItemLink(tab, slotID)
+ --A column goes from 1-14, e.g. GuildBankColumn1Button14 (slotID 14) or GuildBankColumn2Button3 (slotID 17)
+ local col = ceil(slotID / 14)
+ local btn = (slotID % 14)
+ if col == 0 then col = 1 end
+ if btn == 0 then btn = 14 end
+
+ local button = _G["GuildBankColumn"..col.."Button"..btn]
+ local success, result = pcall(Search.Matches, Search, link, query)
+
+ if empty or (success and result) then
+ SetItemButtonDesaturated(button, button.locked or button.junkDesaturate)
+ button:SetAlpha(1)
+ else
+ SetItemButtonDesaturated(button, 1)
+ button:SetAlpha(0.5)
+ end
+ end
+ end
+ end
+end
+
+function B:UpdateItemLevelDisplay()
+ if not E.private.bags.enable then return end
+
+ local font = E.Libs.LSM:Fetch("font", E.db.bags.itemLevelFont)
+
+ for _, bagFrame in pairs(B.BagFrames) do
+ for _, bagID in ipairs(bagFrame.BagIDs) do
+ for slotID = 1, GetContainerNumSlots(bagID) do
+ local slot = bagFrame.Bags[bagID][slotID]
+ if slot and slot.itemLevel then
+ slot.itemLevel:FontTemplate(font, E.db.bags.itemLevelFontSize, E.db.bags.itemLevelFontOutline)
+ end
+ end
+ end
+
+ B:UpdateAllSlots(bagFrame)
+ end
+end
+
+function B:UpdateCountDisplay()
+ if not E.private.bags.enable then return end
+
+ local font = E.Libs.LSM:Fetch("font", E.db.bags.countFont)
+ local color = E.db.bags.countFontColor
+
+ for _, bagFrame in pairs(B.BagFrames) do
+ for _, bagID in ipairs(bagFrame.BagIDs) do
+ for slotID = 1, GetContainerNumSlots(bagID) do
+ local slot = bagFrame.Bags[bagID][slotID]
+ if slot and slot.Count then
+ slot.Count:FontTemplate(font, E.db.bags.countFontSize, E.db.bags.countFontOutline)
+ slot.Count:SetTextColor(color.r, color.g, color.b)
+ end
+ end
+ end
+
+ B:UpdateAllSlots(bagFrame)
+ end
+
+ --Keyring
+ if ElvUIKeyFrameItem1 then
+ for i = 1, GetKeyRingSize() do
+ local slot = _G["ElvUIKeyFrameItem"..i]
+ if slot then
+ slot.Count:FontTemplate(font, E.db.bags.countFontSize, E.db.bags.countFontOutline)
+ slot.Count:SetTextColor(color.r, color.g, color.b)
+ B:UpdateKeySlot(i)
+ end
+ end
+ end
+end
+
+function B:UpdateAllBagSlots()
+ if not E.private.bags.enable then return end
+
+ for _, bagFrame in pairs(B.BagFrames) do
+ B:UpdateAllSlots(bagFrame)
+ end
+end
+
+function B:UpdateSlot(frame, bagID, slotID)
+ if (frame.Bags[bagID] and frame.Bags[bagID].numSlots ~= GetContainerNumSlots(bagID)) or not frame.Bags[bagID] or not frame.Bags[bagID][slotID] then return end
+
+ local slot = frame.Bags[bagID][slotID]
+ local bagType = frame.Bags[bagID].type
+ local texture, count, locked, _, readable = GetContainerItemInfo(bagID, slotID)
+ local clink = GetContainerItemLink(bagID, slotID)
+
+ slot.name, slot.rarity, slot.locked, slot.readable, slot.isJunk, slot.junkDesaturate = nil, nil, locked, readable, nil, nil
+
+ slot:Show()
+ slot.questIcon:Hide()
+ slot.JunkIcon:Hide()
+ slot.itemLevel:SetText("")
+ slot.bindType:SetText("")
+
+ if B.db.showBindType then
+ E.ScanTooltip:SetOwner(UIParent, "ANCHOR_NONE")
+ if slot.GetInventorySlot then -- this fixes bank bagid -1
+ E.ScanTooltip:SetInventoryItem("player", slot:GetInventorySlot())
+ else
+ E.ScanTooltip:SetBagItem(bagID, slotID)
+ end
+ E.ScanTooltip:Show()
+ end
+
+ if B.db.professionBagColors and B.ProfessionColors[bagType] then
+ slot:SetBackdropBorderColor(unpack(B.ProfessionColors[bagType]))
+ slot.ignoreBorderColors = true
+ elseif clink then
+ local iLvl, iType, itemEquipLoc, itemPrice
+ slot.name, _, slot.rarity, iLvl, _, iType, _, _, itemEquipLoc, _, itemPrice = GetItemInfo(clink)
+
+ local isQuestItem, questId, isActiveQuest = GetContainerItemQuestInfo(bagID, slotID)
+ local r, g, b
+
+ if slot.rarity then
+ r, g, b = GetItemQualityColor(slot.rarity)
+ end
+
+ if B.db.showBindType and (slot.rarity and slot.rarity > 1) then
+ local bindTypeLines = GetCVarBool("colorblindmode") and 8 or 7
+ local BoE, BoU
+ for i = 2, bindTypeLines do
+ local line = _G["ElvUI_ScanTooltipTextLeft"..i]:GetText()
+ if (not line or line == "") or (line == ITEM_SOULBOUND or line == ITEM_ACCOUNTBOUND or line == ITEM_BNETACCOUNTBOUND) then break end
+
+ BoE, BoU = line == ITEM_BIND_ON_EQUIP, line == ITEM_BIND_ON_USE
+
+ if not B.db.showBindType and (slot.rarity and slot.rarity > 1) or (BoE or BoU) then break end
+ end
+
+ if BoE or BoU then
+ slot.bindType:SetText(BoE and L["BoE"] or L["BoU"])
+ slot.bindType:SetVertexColor(r, g, b)
+ end
+ end
+
+ -- Item Level
+ if iLvl and B.db.itemLevel and (itemEquipLoc ~= nil and itemEquipLoc ~= "" and itemEquipLoc ~= "INVTYPE_AMMO" and itemEquipLoc ~= "INVTYPE_BAG" and itemEquipLoc ~= "INVTYPE_QUIVER" and itemEquipLoc ~= "INVTYPE_TABARD") and (slot.rarity and slot.rarity > 1) and iLvl >= B.db.itemLevelThreshold then
+ slot.itemLevel:SetText(iLvl)
+ if B.db.itemLevelCustomColorEnable then
+ slot.itemLevel:SetTextColor(B.db.itemLevelCustomColor.r, B.db.itemLevelCustomColor.g, B.db.itemLevelCustomColor.b)
+ else
+ slot.itemLevel:SetTextColor(r, g, b)
+ end
+ end
+
+ slot.isJunk = (slot.rarity and slot.rarity == 0) and (itemPrice and itemPrice > 0) and (iType and iType ~= "Quest")
+ slot.junkDesaturate = slot.isJunk and E.db.bags.junkDesaturate
+
+ -- Junk Icon
+ if slot.JunkIcon then
+ if E.db.bags.junkIcon and slot.isJunk then
+ slot.JunkIcon:Show()
+ end
+ end
+
+ if B.db.questIcon and (questId and not isActiveQuest) then
+ slot.questIcon:Show()
+ end
+
+ -- color slot according to item quality
+ if B.db.questItemColors and (questId and not isActiveQuest) then
+ slot:SetBackdropBorderColor(unpack(B.QuestColors.questStarter))
+ slot.ignoreBorderColors = true
+ elseif B.db.questItemColors and (questId or isQuestItem) then
+ slot:SetBackdropBorderColor(unpack(B.QuestColors.questItem))
+ slot.ignoreBorderColors = true
+ elseif B.db.qualityColors and (slot.rarity and slot.rarity > 1) then
+ slot:SetBackdropBorderColor(r, g, b)
+ slot.ignoreBorderColors = true
+ else
+ slot:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ slot.ignoreBorderColors = nil
+ end
+ else
+ slot:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ slot.ignoreBorderColors = nil
+ end
+
+ E.ScanTooltip:Hide()
+
+ if texture then
+ local start, duration, enable = GetContainerItemCooldown(bagID, slotID)
+ CooldownFrame_SetTimer(slot.cooldown, start, duration, enable)
+ if duration > 0 and enable == 0 then
+ SetItemButtonTextureVertexColor(slot, 0.4, 0.4, 0.4)
+ else
+ SetItemButtonTextureVertexColor(slot, 1, 1, 1)
+ end
+ slot.hasItem = 1
+ else
+ slot.cooldown:Hide()
+ slot.hasItem = nil
+ end
+
+ SetItemButtonTexture(slot, texture)
+ SetItemButtonCount(slot, count)
+ SetItemButtonDesaturated(slot, slot.locked or slot.junkDesaturate)
+
+ if GameTooltip:GetOwner() == slot and not slot.hasItem then
+ GameTooltip_Hide()
+ end
+end
+
+function B:UpdateBagSlots(frame, bagID)
+ for slotID = 1, GetContainerNumSlots(bagID) do
+ B:UpdateSlot(frame, bagID, slotID)
+ end
+end
+
+function B:RefreshSearch()
+ B:SetSearch(SEARCH_STRING)
+end
+
+function B:SortingFadeBags(bagFrame, registerUpdate)
+ if not (bagFrame and bagFrame.BagIDs) then return end
+ bagFrame.registerUpdate = registerUpdate
+
+ for _, bagID in ipairs(bagFrame.BagIDs) do
+ for slotID = 1, GetContainerNumSlots(bagID) do
+ local button = bagFrame.Bags[bagID][slotID]
+ SetItemButtonDesaturated(button, 1)
+ button.searchOverlay:Show()
+ button:SetAlpha(0.5)
+ end
+ end
+end
+
+function B:UpdateCooldowns(frame)
+ if not (frame and frame.BagIDs) then return end
+
+ for _, bagID in ipairs(frame.BagIDs) do
+ for slotID = 1, GetContainerNumSlots(bagID) do
+ local start, duration, enable = GetContainerItemCooldown(bagID, slotID)
+ CooldownFrame_SetTimer(frame.Bags[bagID][slotID].cooldown, start, duration, enable)
+ end
+ end
+end
+
+function B:UpdateAllSlots(frame)
+ if not (frame and frame.BagIDs) then return end
+
+ for _, bagID in ipairs(frame.BagIDs) do
+ local bag = frame.Bags[bagID]
+ if bag then B:UpdateBagSlots(frame, bagID) end
+ end
+
+ -- Refresh search in case we moved items around
+ if not frame.registerUpdate and B:IsSearching() then
+ B:RefreshSearch()
+ end
+end
+
+function B:SetSlotAlphaForBag(f)
+ for _, bagID in ipairs(f.BagIDs) do
+ if f.Bags[bagID] then
+ for slotID = 1, GetContainerNumSlots(bagID) do
+ if f.Bags[bagID][slotID] then
+ if bagID == self.id then
+ f.Bags[bagID][slotID]:SetAlpha(1)
+ else
+ f.Bags[bagID][slotID]:SetAlpha(0.1)
+ end
+ end
+ end
+ end
+ end
+end
+
+function B:ResetSlotAlphaForBags(f)
+ for _, bagID in ipairs(f.BagIDs) do
+ if f.Bags[bagID] then
+ for slotID = 1, GetContainerNumSlots(bagID) do
+ if f.Bags[bagID][slotID] then
+ f.Bags[bagID][slotID]:SetAlpha(1)
+ end
+ end
+ end
+ end
+end
+
+function B:Layout(isBank)
+ if not E.private.bags.enable then return end
+
+ local f = B:GetContainerFrame(isBank)
+ if not f then return end
+
+ local buttonSize = isBank and B.db.bankSize or B.db.bagSize
+ local buttonSpacing = E.Border*2
+ local containerWidth = ((isBank and B.db.bankWidth) or B.db.bagWidth)
+ local numContainerColumns = floor(containerWidth / (buttonSize + buttonSpacing))
+ local holderWidth = ((buttonSize + buttonSpacing) * numContainerColumns) - buttonSpacing
+ local numContainerRows = 0
+ local numBags = 0
+ local numBagSlots = 0
+ local bagSpacing = B.db.split.bagSpacing
+ local countColor = E.db.bags.countFontColor
+ local isSplit = B.db.split[isBank and "bank" or "player"]
+
+ f.holderFrame:Width(holderWidth)
+
+ f.totalSlots = 0
+ local lastButton
+ local lastRowButton
+ local lastContainerButton
+ local numContainerSlots = GetNumBankSlots()
+ local newBag
+
+ for i, bagID in ipairs(f.BagIDs) do
+ if isSplit then
+ newBag = (bagID ~= -1 or bagID ~= 0) and B.db.split["bag"..bagID] or false
+ end
+
+ --Bag Containers
+ if (not isBank) or (isBank and bagID ~= -1 and numContainerSlots >= 1 and (i - 1 <= numContainerSlots)) then
+ if not f.ContainerHolder[i] then
+ if isBank then
+ f.ContainerHolder[i] = CreateFrame("CheckButton", "ElvUIBankBag"..bagID - 4, f.ContainerHolder, "BankItemButtonBagTemplate")
+ f.ContainerHolder[i]:SetScript("OnClick", function(holder)
+ local inventoryID = holder:GetInventorySlot()
+ PutItemInBag(inventoryID)
+ end)
+ else
+ if bagID == 0 then
+ f.ContainerHolder[i] = CreateFrame("CheckButton", "ElvUIMainBagBackpack", f.ContainerHolder, "ItemButtonTemplate")
+
+ f.ContainerHolder[i].model = CreateFrame("Model", "$parentItemAnim", f.ContainerHolder[i], "ItemAnimTemplate")
+ f.ContainerHolder[i].model:SetPoint("BOTTOMRIGHT", -10, 0)
+
+ f.ContainerHolder[i]:SetScript("OnClick", function()
+ PutItemInBackpack()
+ end)
+ f.ContainerHolder[i]:SetScript("OnReceiveDrag", function()
+ PutItemInBackpack()
+ end)
+ f.ContainerHolder[i]:SetScript("OnEnter", function(holder)
+ GameTooltip:SetOwner(holder, "ANCHOR_LEFT")
+ GameTooltip:SetText(BACKPACK_TOOLTIP, 1, 1, 1)
+ GameTooltip:Show()
+ end)
+ f.ContainerHolder[i]:SetScript("OnLeave", GameTooltip_Hide)
+ else
+ f.ContainerHolder[i] = CreateFrame("CheckButton", "ElvUIMainBag"..(bagID - 1).."Slot", f.ContainerHolder, "BagSlotButtonTemplate")
+ f.ContainerHolder[i]:SetScript("OnClick", function(holder)
+ local id = holder:GetID()
+ PutItemInBag(id)
+ end)
+ end
+ end
+
+ f.ContainerHolder[i]:SetTemplate(E.db.bags.transparent and "Transparent", true)
+ f.ContainerHolder[i]:StyleButton()
+ f.ContainerHolder[i]:SetNormalTexture("")
+ f.ContainerHolder[i]:SetCheckedTexture(nil)
+ f.ContainerHolder[i]:SetPushedTexture("")
+ f.ContainerHolder[i].id = bagID
+ f.ContainerHolder[i]:HookScript("OnEnter", function(ch) B.SetSlotAlphaForBag(ch, f) end)
+ f.ContainerHolder[i]:HookScript("OnLeave", function(ch) B.ResetSlotAlphaForBags(ch, f) end)
+
+ if isBank then
+ f.ContainerHolder[i]:SetID(bagID)
+ if not f.ContainerHolder[i].tooltipText then
+ f.ContainerHolder[i].tooltipText = ""
+ end
+ end
+
+ f.ContainerHolder[i].iconTexture = _G[f.ContainerHolder[i]:GetName().."IconTexture"]
+ if bagID == 0 then
+ f.ContainerHolder[i].iconTexture:SetTexture("Interface\\Buttons\\Button-Backpack-Up")
+ end
+ f.ContainerHolder[i].iconTexture:SetInside()
+ f.ContainerHolder[i].iconTexture:SetTexCoord(unpack(E.TexCoords))
+ end
+
+ f.ContainerHolder:Size(((buttonSize + buttonSpacing) * (isBank and i - 1 or i)) + buttonSpacing, buttonSize + (buttonSpacing * 2))
+
+ if isBank then
+ BankFrameItemButton_Update(f.ContainerHolder[i])
+ BankFrameItemButton_UpdateLocked(f.ContainerHolder[i])
+ end
+
+ f.ContainerHolder[i]:Size(buttonSize)
+ f.ContainerHolder[i]:ClearAllPoints()
+ if (isBank and i == 2) or (not isBank and i == 1) then
+ f.ContainerHolder[i]:Point("BOTTOMLEFT", f.ContainerHolder, "BOTTOMLEFT", buttonSpacing, buttonSpacing)
+ else
+ f.ContainerHolder[i]:Point("LEFT", lastContainerButton, "RIGHT", buttonSpacing, 0)
+ end
+
+ lastContainerButton = f.ContainerHolder[i]
+ end
+
+ --Bag Slots
+ local numSlots = GetContainerNumSlots(bagID)
+ if numSlots > 0 then
+ if not f.Bags[bagID] then
+ f.Bags[bagID] = CreateFrame("Frame", f:GetName().."Bag"..bagID, f.holderFrame)
+ f.Bags[bagID]:SetID(bagID)
+ end
+
+ f.Bags[bagID].numSlots = numSlots
+ f.Bags[bagID].type = select(2, GetContainerNumFreeSlots(bagID))
+
+ --Hide unused slots
+ for y = 1, MAX_CONTAINER_ITEMS do
+ if f.Bags[bagID][y] then
+ f.Bags[bagID][y]:Hide()
+ end
+ end
+
+ for slotID = 1, numSlots do
+ f.totalSlots = f.totalSlots + 1
+ if not f.Bags[bagID][slotID] then
+ f.Bags[bagID][slotID] = CreateFrame("CheckButton", f.Bags[bagID]:GetName().."Slot"..slotID, f.Bags[bagID], bagID == -1 and "BankItemButtonGenericTemplate" or "ContainerFrameItemButtonTemplate")
+ f.Bags[bagID][slotID]:StyleButton()
+ f.Bags[bagID][slotID]:SetTemplate(E.db.bags.transparent and "Transparent", true)
+ f.Bags[bagID][slotID]:SetNormalTexture(nil)
+ f.Bags[bagID][slotID]:SetCheckedTexture(nil)
+
+ f.Bags[bagID][slotID].Count = _G[f.Bags[bagID][slotID]:GetName().."Count"]
+ f.Bags[bagID][slotID].Count:ClearAllPoints()
+ f.Bags[bagID][slotID].Count:Point("BOTTOMRIGHT", -1, 3)
+ f.Bags[bagID][slotID].Count:FontTemplate(E.Libs.LSM:Fetch("font", E.db.bags.countFont), E.db.bags.countFontSize, E.db.bags.countFontOutline)
+ f.Bags[bagID][slotID].Count:SetTextColor(countColor.r, countColor.g, countColor.b)
+
+ if not f.Bags[bagID][slotID].questIcon then
+ f.Bags[bagID][slotID].questIcon = _G[f.Bags[bagID][slotID]:GetName().."IconQuestTexture"] or _G[f.Bags[bagID][slotID]:GetName()].IconQuestTexture
+ f.Bags[bagID][slotID].questIcon:SetTexture(E.Media.Textures.BagQuestIcon)
+ f.Bags[bagID][slotID].questIcon:SetTexCoord(0, 1, 0, 1)
+ f.Bags[bagID][slotID].questIcon:SetInside()
+ f.Bags[bagID][slotID].questIcon:Hide()
+ end
+
+ if not f.Bags[bagID][slotID].JunkIcon then
+ local JunkIcon = f.Bags[bagID][slotID]:CreateTexture(nil, "OVERLAY")
+ JunkIcon:SetTexture(E.Media.Textures.BagJunkIcon)
+ JunkIcon:Point("TOPLEFT", 1, 0)
+ JunkIcon:Hide()
+ f.Bags[bagID][slotID].JunkIcon = JunkIcon
+ end
+
+ f.Bags[bagID][slotID].iconTexture = _G[f.Bags[bagID][slotID]:GetName().."IconTexture"]
+ f.Bags[bagID][slotID].iconTexture:SetInside(f.Bags[bagID][slotID])
+ f.Bags[bagID][slotID].iconTexture:SetTexCoord(unpack(E.TexCoords))
+
+ if not f.Bags[bagID][slotID].searchOverlay then
+ local searchOverlay = f.Bags[bagID][slotID]:CreateTexture(nil, "ARTWORK")
+ searchOverlay:SetTexture(E.media.blankTex)
+ searchOverlay:SetVertexColor(0, 0, 0)
+ searchOverlay:SetAllPoints()
+ searchOverlay:Hide()
+ f.Bags[bagID][slotID].searchOverlay = searchOverlay
+ end
+
+ f.Bags[bagID][slotID].cooldown = _G[f.Bags[bagID][slotID]:GetName().."Cooldown"]
+ f.Bags[bagID][slotID].cooldown.CooldownOverride = "bags"
+ E:RegisterCooldown(f.Bags[bagID][slotID].cooldown)
+ f.Bags[bagID][slotID].bagID = bagID
+ f.Bags[bagID][slotID].slotID = slotID
+
+ f.Bags[bagID][slotID].itemLevel = f.Bags[bagID][slotID]:CreateFontString(nil, "OVERLAY")
+ f.Bags[bagID][slotID].itemLevel:Point("BOTTOMRIGHT", -1, 3)
+ f.Bags[bagID][slotID].itemLevel:FontTemplate(E.Libs.LSM:Fetch("font", E.db.bags.itemLevelFont), E.db.bags.itemLevelFontSize, E.db.bags.itemLevelFontOutline)
+
+ f.Bags[bagID][slotID].bindType = f.Bags[bagID][slotID]:CreateFontString(nil, "OVERLAY")
+ f.Bags[bagID][slotID].bindType:Point("TOP", 0, -2)
+ f.Bags[bagID][slotID].bindType:FontTemplate(E.Libs.LSM:Fetch("font", E.db.bags.itemLevelFont), E.db.bags.itemLevelFontSize, E.db.bags.itemLevelFontOutline)
+ end
+
+ f.Bags[bagID][slotID]:SetID(slotID)
+ f.Bags[bagID][slotID]:Size(buttonSize)
+
+ if f.Bags[bagID][slotID].JunkIcon then
+ f.Bags[bagID][slotID].JunkIcon:Size(buttonSize/2)
+ end
+
+ B:UpdateSlot(f, bagID, slotID)
+
+ if f.Bags[bagID][slotID]:GetPoint() then
+ f.Bags[bagID][slotID]:ClearAllPoints()
+ end
+
+ if lastButton then
+ local anchorPoint, relativePoint = (B.db.reverseSlots and "BOTTOM" or "TOP"), (B.db.reverseSlots and "TOP" or "BOTTOM")
+ if isSplit and newBag and slotID == 1 then
+ f.Bags[bagID][slotID]:Point(anchorPoint, lastRowButton, relativePoint, 0, B.db.reverseSlots and (buttonSpacing + bagSpacing) or -(buttonSpacing + bagSpacing))
+ lastRowButton = f.Bags[bagID][slotID]
+ numContainerRows = numContainerRows + 1
+ numBags = numBags + 1
+ numBagSlots = 0
+ elseif isSplit and numBagSlots % numContainerColumns == 0 then
+ f.Bags[bagID][slotID]:Point(anchorPoint, lastRowButton, relativePoint, 0, B.db.reverseSlots and buttonSpacing or -buttonSpacing)
+ lastRowButton = f.Bags[bagID][slotID]
+ numContainerRows = numContainerRows + 1
+ elseif (not isSplit) and (f.totalSlots - 1) % numContainerColumns == 0 then
+ f.Bags[bagID][slotID]:Point(anchorPoint, lastRowButton, relativePoint, 0, B.db.reverseSlots and buttonSpacing or -buttonSpacing)
+ lastRowButton = f.Bags[bagID][slotID]
+ numContainerRows = numContainerRows + 1
+ else
+ anchorPoint, relativePoint = (B.db.reverseSlots and "RIGHT" or "LEFT"), (B.db.reverseSlots and "LEFT" or "RIGHT")
+ f.Bags[bagID][slotID]:Point(anchorPoint, lastButton, relativePoint, B.db.reverseSlots and -buttonSpacing or buttonSpacing, 0)
+ end
+ else
+ local anchorPoint = B.db.reverseSlots and "BOTTOMRIGHT" or "TOPLEFT"
+ f.Bags[bagID][slotID]:Point(anchorPoint, f.holderFrame, anchorPoint, 0, B.db.reverseSlots and f.bottomOffset - 8 or 0)
+ lastRowButton = f.Bags[bagID][slotID]
+ numContainerRows = numContainerRows + 1
+ end
+
+ lastButton = f.Bags[bagID][slotID]
+ numBagSlots = numBagSlots + 1
+ end
+ else
+ --Hide unused slots
+ for y = 1, MAX_CONTAINER_ITEMS do
+ if f.Bags[bagID] and f.Bags[bagID][y] then
+ f.Bags[bagID][y]:Hide()
+ end
+ end
+
+ if f.Bags[bagID] then
+ f.Bags[bagID].numSlots = numSlots
+ end
+
+ local container = isBank and f.ContainerHolder[i]
+ if container then
+ BankFrameItemButton_Update(container)
+ BankFrameItemButton_UpdateLocked(container)
+ end
+ end
+ end
+
+ local numKey = GetKeyRingSize()
+ local numKeyColumns = 6
+ if not isBank then
+ local totalSlots, numKeyRows, lastRowKey = 0, 1
+
+ for i = 1, numKey do
+ totalSlots = totalSlots + 1
+
+ if not f.keyFrame.slots[i] then
+ f.keyFrame.slots[i] = CreateFrame("CheckButton", "ElvUIKeyFrameItem"..i, f.keyFrame, "ContainerFrameItemButtonTemplate")
+ f.keyFrame.slots[i]:StyleButton(nil, nil, true)
+ f.keyFrame.slots[i]:SetTemplate("Default", true)
+ f.keyFrame.slots[i]:SetNormalTexture(nil)
+ f.keyFrame.slots[i]:SetID(i)
+
+ f.keyFrame.slots[i].Count = _G[f.keyFrame.slots[i]:GetName().."Count"]
+ f.keyFrame.slots[i].Count:ClearAllPoints()
+ f.keyFrame.slots[i].Count:Point("BOTTOMRIGHT", 0, 2)
+ f.keyFrame.slots[i].Count:FontTemplate(E.Libs.LSM:Fetch("font", E.db.bags.countFont), E.db.bags.countFontSize, E.db.bags.countFontOutline)
+ f.keyFrame.slots[i].Count:SetTextColor(countColor.r, countColor.g, countColor.b)
+
+ f.keyFrame.slots[i].cooldown = _G[f.keyFrame.slots[i]:GetName().."Cooldown"]
+ f.keyFrame.slots[i].cooldown.CooldownOverride = "bags"
+ E:RegisterCooldown(f.keyFrame.slots[i].cooldown)
+
+ if not f.keyFrame.slots[i].questIcon then
+ f.keyFrame.slots[i].questIcon = _G[f.keyFrame.slots[i]:GetName().."IconQuestTexture"] or _G[f.keyFrame.slots[i]:GetName()].IconQuestTexture
+ f.keyFrame.slots[i].questIcon:SetTexture(E.Media.Textures.BagQuestIcon)
+ f.keyFrame.slots[i].questIcon:SetTexCoord(0, 1, 0, 1)
+ f.keyFrame.slots[i].questIcon:SetInside()
+ f.keyFrame.slots[i].questIcon:Hide()
+ end
+
+ f.keyFrame.slots[i].iconTexture = _G[f.keyFrame.slots[i]:GetName().."IconTexture"]
+ f.keyFrame.slots[i].iconTexture:SetInside(f.keyFrame.slots[i])
+ f.keyFrame.slots[i].iconTexture:SetTexCoord(unpack(E.TexCoords))
+
+ if not f.keyFrame.slots[i].searchOverlay then
+ local searchOverlay = f.keyFrame.slots[i]:CreateTexture(nil, "ARTWORK")
+ searchOverlay:SetTexture(E.media.blankTex)
+ searchOverlay:SetVertexColor(0, 0, 0)
+ searchOverlay:SetAllPoints()
+ searchOverlay:Hide()
+ f.keyFrame.slots[i].searchOverlay = searchOverlay
+ end
+ end
+
+ f.keyFrame.slots[i]:ClearAllPoints()
+ f.keyFrame.slots[i]:Size(buttonSize)
+ if f.keyFrame.slots[i - 1] then
+ if (totalSlots - 1) % numKeyColumns == 0 then
+ f.keyFrame.slots[i]:Point("TOP", lastRowKey, "BOTTOM", 0, -buttonSpacing)
+ lastRowKey = f.keyFrame.slots[i]
+ numKeyRows = numKeyRows + 1
+ else
+ f.keyFrame.slots[i]:Point("RIGHT", f.keyFrame.slots[i - 1], "LEFT", -buttonSpacing, 0)
+ end
+ else
+ f.keyFrame.slots[i]:Point("TOPRIGHT", f.keyFrame, "TOPRIGHT", -buttonSpacing, -buttonSpacing)
+ lastRowKey = f.keyFrame.slots[i]
+ end
+
+ B:UpdateKeySlot(i)
+ end
+
+ if numKey < numKeyColumns then
+ numKeyColumns = numKey
+ end
+ f.keyFrame:Size(((buttonSize + buttonSpacing) * numKeyColumns) + buttonSpacing, ((buttonSize + buttonSpacing) * numKeyRows) + buttonSpacing)
+ end
+
+ f:Size(containerWidth, (((buttonSize + buttonSpacing) * numContainerRows) - buttonSpacing) + (isSplit and (numBags * bagSpacing) or 0) + f.topOffset + f.bottomOffset) -- 8 is the cussion of the f.holderFrame
+end
+
+function B:UpdateKeySlot(slotID)
+ assert(slotID)
+ local bagID = KEYRING_CONTAINER
+ local texture, count, locked = GetContainerItemInfo(bagID, slotID)
+ local clink = GetContainerItemLink(bagID, slotID)
+ local slot = _G["ElvUIKeyFrameItem"..slotID]
+ if not slot then return end
+
+ slot:Show()
+ slot.questIcon:Hide()
+
+ slot.name, slot.rarity, slot.locked = nil, nil, locked
+
+ if clink then
+ local name, _, rarity = GetItemInfo(clink)
+ local isQuestItem, questId, isActiveQuest = GetContainerItemQuestInfo(bagID, slotID)
+
+ slot.name, slot.rarity = name, rarity
+
+ if B.db.questIcon and (questId and not isActiveQuest) then
+ slot.questIcon:Show()
+ end
+
+ -- color slot according to item quality
+ if B.db.questItemColors and (questId and not isActiveQuest) then
+ slot:SetBackdropBorderColor(unpack(B.QuestColors.questStarter))
+ slot.ignoreBorderColors = true
+ elseif B.db.questItemColors and (questId or isQuestItem) then
+ slot:SetBackdropBorderColor(unpack(B.QuestColors.questItem))
+ slot.ignoreBorderColors = true
+ elseif B.db.qualityColors and (slot.rarity and slot.rarity > 1) then
+ slot:SetBackdropBorderColor(GetItemQualityColor(slot.rarity))
+ slot.ignoreBorderColors = true
+ else
+ slot:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ slot.ignoreBorderColors = nil
+ end
+ else
+ slot:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ slot.ignoreBorderColors = nil
+ end
+
+ if texture then
+ local start, duration, enable = GetContainerItemCooldown(bagID, slotID)
+ CooldownFrame_SetTimer(slot.cooldown, start, duration, enable)
+ if duration > 0 and enable == 0 then
+ SetItemButtonTextureVertexColor(slot, 0.4, 0.4, 0.4)
+ else
+ SetItemButtonTextureVertexColor(slot, 1, 1, 1)
+ end
+ else
+ slot.cooldown:Hide()
+ end
+
+ SetItemButtonTexture(slot, texture)
+ SetItemButtonCount(slot, count)
+ SetItemButtonDesaturated(slot, slot.locked)
+end
+
+function B:UpdateAll()
+ if B.BagFrame then B:Layout() end
+ if B.BankFrame then B:Layout(true) end
+end
+
+function B:OnEvent(event, ...)
+ if event == "ITEM_LOCK_CHANGED" or event == "ITEM_UNLOCKED" then
+ local bag, slot = ...
+ if bag == KEYRING_CONTAINER then
+ B:UpdateKeySlot(slot)
+ else
+ B:UpdateSlot(self, bag, slot)
+ end
+ elseif event == "BAG_UPDATE" then
+ local bag = ...
+ if bag == KEYRING_CONTAINER then
+ for slotID = 1, GetKeyRingSize() do
+ B:UpdateKeySlot(slotID)
+ end
+ end
+
+ for _, bagID in ipairs(self.BagIDs) do
+ local numSlots = GetContainerNumSlots(bagID)
+ if (not self.Bags[bagID] and numSlots ~= 0) or (self.Bags[bagID] and numSlots ~= self.Bags[bagID].numSlots) then
+ B:Layout(self.isBank)
+ return
+ end
+ end
+
+ B:UpdateBagSlots(self, ...)
+
+ --Refresh search in case we moved items around
+ if B:IsSearching() then B:RefreshSearch() end
+ elseif event == "BAG_UPDATE_COOLDOWN" then
+ if not self:IsShown() then return end
+ B:UpdateCooldowns(self)
+ elseif event == "PLAYERBANKSLOTS_CHANGED" then
+ B:UpdateBagSlots(self, -1)
+ elseif (event == "QUEST_ACCEPTED" or event == "QUEST_REMOVED" or event == "QUEST_LOG_UPDATE") and self:IsShown() then
+ B:UpdateAllSlots(self)
+ for slotID = 1, GetKeyRingSize() do
+ B:UpdateKeySlot(slotID)
+ end
+ end
+end
+
+function B:UpdateTokens()
+ local f = B.BagFrame
+ local numTokens = 0
+ for i = 1, MAX_WATCHED_TOKENS do
+ local name, count, cType, icon, itemID = GetBackpackCurrencyInfo(i)
+ local button = f.currencyButton[i]
+
+ if cType == 1 then
+ icon = "Interface\\PVPFrame\\PVP-ArenaPoints-Icon"
+ elseif cType == 2 then
+ icon = "Interface\\PVPFrame\\PVP-Currency-"..E.myfaction
+ end
+
+ button:ClearAllPoints()
+ if name then
+ button.icon:SetTexture(icon)
+
+ if B.db.currencyFormat == "ICON_TEXT" then
+ button.text:SetText(name..": "..count)
+ elseif B.db.currencyFormat == "ICON_TEXT_ABBR" then
+ button.text:SetText(E:AbbreviateString(name)..": "..count)
+ elseif B.db.currencyFormat == "ICON" then
+ button.text:SetText(count)
+ end
+
+ button.itemID = itemID
+ button:Show()
+ numTokens = numTokens + 1
+ else
+ button:Hide()
+ end
+ end
+
+ if numTokens == 0 then
+ f.bottomOffset = 8
+
+ if f.currencyButton:IsShown() then
+ f.currencyButton:Hide()
+ B:Layout()
+ end
+
+ return
+ elseif not f.currencyButton:IsShown() then
+ f.bottomOffset = 28
+ f.currencyButton:Show()
+ B:Layout()
+ end
+
+ f.bottomOffset = 28
+
+ if numTokens == 1 then
+ f.currencyButton[1]:Point("BOTTOM", f.currencyButton, "BOTTOM", -(f.currencyButton[1].text:GetWidth() / 2), 3)
+ elseif numTokens == 2 then
+ f.currencyButton[1]:Point("BOTTOM", f.currencyButton, "BOTTOM", -(f.currencyButton[1].text:GetWidth()) - (f.currencyButton[1]:GetWidth() / 2), 3)
+ f.currencyButton[2]:Point("BOTTOMLEFT", f.currencyButton, "BOTTOM", f.currencyButton[2]:GetWidth() / 2, 3)
+ else
+ f.currencyButton[1]:Point("BOTTOMLEFT", f.currencyButton, "BOTTOMLEFT", 3, 3)
+ f.currencyButton[2]:Point("BOTTOM", f.currencyButton, "BOTTOM", -(f.currencyButton[2].text:GetWidth() / 3), 3)
+ f.currencyButton[3]:Point("BOTTOMRIGHT", f.currencyButton, "BOTTOMRIGHT", -(f.currencyButton[3].text:GetWidth()) - (f.currencyButton[3]:GetWidth() / 2), 3)
+ end
+end
+
+function B:Token_OnEnter()
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
+ GameTooltip:SetBackpackToken(self:GetID())
+end
+
+function B:Token_OnClick()
+ if IsModifiedClick("CHATLINK") then
+ ChatEdit_InsertLink(select(2, GetItemInfo(self.itemID)))
+ end
+end
+
+function B:UpdateGoldText()
+ B.BagFrame.goldText:SetText(E:FormatMoney(GetMoney(), E.db.bags.moneyFormat, not E.db.bags.moneyCoins))
+end
+
+function B:FormatMoney(amount)
+ local str, coppername, silvername, goldname = "", "|cffeda55fc|r", "|cffc7c7cfs|r", "|cffffd700g|r"
+
+ local value = abs(amount)
+ local gold = floor(value / 10000)
+ local silver = floor((value / 100) % 100)
+ local copper = floor(value % 100)
+
+ if gold > 0 then
+ str = format("%d%s%s", gold, goldname, (silver > 0 or copper > 0) and " " or "")
+ end
+ if silver > 0 then
+ str = format("%s%d%s%s", str, silver, silvername, copper > 0 and " " or "")
+ end
+ if copper > 0 or value == 0 then
+ str = format("%s%d%s", str, copper, coppername)
+ end
+
+ return str
+end
+
+function B:GetGraysInfo()
+ if #self.SellFrame.Info.itemList > 0 then
+ twipe(self.SellFrame.Info.itemList)
+ end
+
+ local itemList = self.SellFrame.Info.itemList
+ local value = 0
+
+ for bag = 0, 4 do
+ for slot = 1, GetContainerNumSlots(bag) do
+ local itemID = GetContainerItemID(bag, slot)
+
+ if itemID then
+ local _, link, rarity, _, _, iType, _, _, _, _, itemPrice = GetItemInfo(itemID)
+
+ if (rarity and rarity == 0) and (iType and iType ~= "Quest") and (itemPrice and itemPrice > 0) then
+ local stackCount = select(2, GetContainerItemInfo(bag, slot)) or 1
+ itemPrice = itemPrice * stackCount
+
+ value = value + itemPrice
+ tinsert(itemList, {bag, slot, link, itemPrice, stackCount})
+ end
+ end
+ end
+ end
+
+ return #itemList, value
+end
+
+function B:VendorGrays(delete)
+ if self.SellFrame:IsShown() then return end
+
+ local itemCount = #self.SellFrame.Info.itemList
+ if itemCount == 0 then return end
+
+ local info = self.SellFrame.Info
+
+ info.delete = delete or false
+ info.SellTimer = 0
+ info.ProgressMax = itemCount
+ info.ProgressTimer = (itemCount - 1) * info.SellInterval
+ info.UpdateTimer = 0
+ info.goldGained = 0
+ info.itemsSold = 0
+
+ self.SellFrame.statusbar:SetValue(0)
+ self.SellFrame.statusbar:SetMinMaxValues(0, itemCount)
+ self.SellFrame.statusbar.ValueText:SetFormattedText("0 / %d", itemCount)
+
+ self.SellFrame:Show()
+end
+
+function B:VendorGrayCheck()
+ local itemCount, value = B:GetGraysInfo()
+
+ if itemCount == 0 then
+ E:Print(L["No gray items to delete."])
+ elseif not MerchantFrame:IsShown() then
+ E.PopupDialogs.DELETE_GRAYS.Money = value
+ E:StaticPopup_Show("DELETE_GRAYS")
+ else
+ B:VendorGrays()
+ end
+end
+
+function B:ContructContainerFrame(name, isBank)
+ local strata = E.db.bags.strata or "DIALOG"
+
+ local f = CreateFrame("Button", name, E.UIParent)
+ f:SetTemplate("Transparent")
+ f:SetFrameStrata(strata)
+ f:RegisterEvent("BAG_UPDATE") -- Has to be on both frames
+ f:RegisterEvent("BAG_UPDATE_COOLDOWN") -- Has to be on both frames
+ f.events = isBank and {"PLAYERBANKSLOTS_CHANGED"} or {"ITEM_LOCK_CHANGED", "ITEM_UNLOCKED", "QUEST_ACCEPTED", "QUEST_REMOVED", "QUEST_LOG_UPDATE"}
+
+ for _, event in ipairs(f.events) do
+ f:RegisterEvent(event)
+ end
+
+ f:SetScript("OnEvent", B.OnEvent)
+ f:Hide()
+
+ f.isBank = isBank
+ f.bottomOffset = isBank and 8 or 28
+ f.topOffset = 50
+ f.BagIDs = isBank and {-1, 5, 6, 7, 8, 9, 10, 11} or {0, 1, 2, 3, 4}
+ f.Bags = {}
+
+ local mover = (isBank and ElvUIBankMover) or ElvUIBagMover
+ if mover then
+ f:Point(mover.POINT, mover)
+ f.mover = mover
+ end
+
+ --Allow dragging the frame around
+ f:SetMovable(true)
+ f:RegisterForDrag("LeftButton", "RightButton")
+ f:RegisterForClicks("AnyUp")
+ f:SetScript("OnDragStart", function(frame) if IsShiftKeyDown() then frame:StartMoving() end end)
+ f:SetScript("OnDragStop", function(frame) frame:StopMovingOrSizing() end)
+ f:SetScript("OnClick", function(frame) if IsControlKeyDown() then B.PostBagMove(frame.mover) end end)
+ f:SetScript("OnLeave", GameTooltip_Hide)
+ f:SetScript("OnEnter", function(frame)
+ GameTooltip:SetOwner(frame, "ANCHOR_TOPLEFT", 0, 4)
+ GameTooltip:ClearLines()
+ GameTooltip:AddDoubleLine(L["Hold Shift + Drag:"], L["Temporary Move"], 1, 1, 1)
+ GameTooltip:AddDoubleLine(L["Hold Control + Right Click:"], L["Reset Position"], 1, 1, 1)
+ GameTooltip:Show()
+ end)
+
+ f.closeButton = CreateFrame("Button", name.."CloseButton", f, "UIPanelCloseButton")
+ f.closeButton:Point("TOPRIGHT", 0, 2)
+
+ Skins:HandleCloseButton(f.closeButton)
+
+ f.holderFrame = CreateFrame("Frame", nil, f)
+ f.holderFrame:Point("TOP", f, "TOP", 0, -f.topOffset)
+ f.holderFrame:Point("BOTTOM", f, "BOTTOM", 0, 8)
+
+ f.ContainerHolder = CreateFrame("Button", name.."ContainerHolder", f)
+ f.ContainerHolder:Point("BOTTOMLEFT", f, "TOPLEFT", 0, 1)
+ f.ContainerHolder:SetTemplate("Transparent")
+ f.ContainerHolder:Hide()
+
+ if isBank then
+ --Bag Text
+ f.bagText = f:CreateFontString(nil, "OVERLAY")
+ f.bagText:FontTemplate()
+ f.bagText:Point("BOTTOMRIGHT", f.holderFrame, "TOPRIGHT", -2, 4)
+ f.bagText:SetJustifyH("RIGHT")
+ f.bagText:SetText(L["Bank"])
+
+ --Sort Button
+ f.sortButton = CreateFrame("Button", name.."SortButton", f)
+ f.sortButton:Size(16 + E.Border)
+ f.sortButton:SetTemplate()
+ f.sortButton:Point("RIGHT", f.bagText, "LEFT", -5, E.Border * 2)
+ f.sortButton:SetNormalTexture(E.Media.Textures.Broom)
+ f.sortButton:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+ f.sortButton:GetNormalTexture():SetInside()
+ f.sortButton:SetPushedTexture(E.Media.Textures.Broom)
+ f.sortButton:GetPushedTexture():SetTexCoord(unpack(E.TexCoords))
+ f.sortButton:GetPushedTexture():SetInside()
+ f.sortButton:SetDisabledTexture(E.Media.Textures.Broom)
+ f.sortButton:GetDisabledTexture():SetTexCoord(unpack(E.TexCoords))
+ f.sortButton:GetDisabledTexture():SetInside()
+ f.sortButton:GetDisabledTexture():SetDesaturated(true)
+ f.sortButton:StyleButton(nil, true)
+ f.sortButton.ttText = L["Sort Bags"]
+ f.sortButton:SetScript("OnEnter", self.Tooltip_Show)
+ f.sortButton:SetScript("OnLeave", GameTooltip_Hide)
+ f.sortButton:SetScript("OnClick", function()
+ f:UnregisterAllEvents() --Unregister to prevent unnecessary updates
+ if not f.registerUpdate then
+ B:SortingFadeBags(f, true)
+ end
+ B:CommandDecorator(B.SortBags, "bank")()
+ end)
+ if E.db.bags.disableBankSort then
+ f.sortButton:Disable()
+ end
+
+ --Toggle Bags Button
+ f.bagsButton = CreateFrame("Button", name.."BagsButton", f.holderFrame)
+ f.bagsButton:Size(16 + E.Border)
+ f.bagsButton:SetTemplate()
+ f.bagsButton:Point("RIGHT", f.sortButton, "LEFT", -5, 0)
+ f.bagsButton:SetNormalTexture("Interface\\Buttons\\Button-Backpack-Up")
+ f.bagsButton:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+ f.bagsButton:GetNormalTexture():SetInside()
+ f.bagsButton:SetPushedTexture("Interface\\Buttons\\Button-Backpack-Up")
+ f.bagsButton:GetPushedTexture():SetTexCoord(unpack(E.TexCoords))
+ f.bagsButton:GetPushedTexture():SetInside()
+ f.bagsButton:StyleButton(nil, true)
+ f.bagsButton.ttText = L["Toggle Bags"]
+ f.bagsButton:SetScript("OnEnter", B.Tooltip_Show)
+ f.bagsButton:SetScript("OnLeave", GameTooltip_Hide)
+ f.bagsButton:SetScript("OnClick", function()
+ local numSlots = GetNumBankSlots()
+ PlaySound("igMainMenuOption")
+ if numSlots >= 1 then
+ ToggleFrame(f.ContainerHolder)
+ else
+ E:StaticPopup_Show("NO_BANK_BAGS")
+ end
+ end)
+
+ --Purchase Bags Button
+ f.purchaseBagButton = CreateFrame("Button", nil, f.holderFrame)
+ f.purchaseBagButton:Size(16 + E.Border)
+ f.purchaseBagButton:SetTemplate()
+ f.purchaseBagButton:Point("RIGHT", f.bagsButton, "LEFT", -5, 0)
+ f.purchaseBagButton:SetNormalTexture("Interface\\ICONS\\INV_Misc_Coin_01")
+ f.purchaseBagButton:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+ f.purchaseBagButton:GetNormalTexture():SetInside()
+ f.purchaseBagButton:SetPushedTexture("Interface\\ICONS\\INV_Misc_Coin_01")
+ f.purchaseBagButton:GetPushedTexture():SetTexCoord(unpack(E.TexCoords))
+ f.purchaseBagButton:GetPushedTexture():SetInside()
+ f.purchaseBagButton:StyleButton(nil, true)
+ f.purchaseBagButton.ttText = L["Purchase Bags"]
+ f.purchaseBagButton:SetScript("OnEnter", B.Tooltip_Show)
+ f.purchaseBagButton:SetScript("OnLeave", GameTooltip_Hide)
+ f.purchaseBagButton:SetScript("OnClick", function()
+ local _, full = GetNumBankSlots()
+ if full then
+ E:StaticPopup_Show("CANNOT_BUY_BANK_SLOT")
+ else
+ E:StaticPopup_Show("BUY_BANK_SLOT")
+ end
+ end)
+
+ f:SetScript("OnShow", B.RefreshSearch)
+ f:SetScript("OnHide", function()
+ CloseBankFrame()
+
+ if E.db.bags.clearSearchOnClose then
+ B.ResetAndClear(f.editBox)
+ end
+ end)
+
+ --Search
+ f.editBox = CreateFrame("EditBox", name.."EditBox", f)
+ f.editBox:SetFrameLevel(f.editBox:GetFrameLevel() + 2)
+ f.editBox:CreateBackdrop()
+ f.editBox.backdrop:Point("TOPLEFT", f.editBox, "TOPLEFT", -20, 2)
+ f.editBox:Height(15)
+ f.editBox:Point("BOTTOMLEFT", f.holderFrame, "TOPLEFT", (E.Border * 2) + 18, E.Border * 2 + 2)
+ f.editBox:Point("RIGHT", f.purchaseBagButton, "LEFT", -5, 0)
+ f.editBox:SetAutoFocus(false)
+ f.editBox:SetScript("OnEscapePressed", B.ResetAndClear)
+ f.editBox:SetScript("OnEnterPressed", function(eb) eb:ClearFocus() end)
+ f.editBox:SetScript("OnEditFocusGained", f.editBox.HighlightText)
+ f.editBox:SetScript("OnTextChanged", B.UpdateSearch)
+ f.editBox:SetScript("OnChar", B.UpdateSearch)
+ f.editBox:SetText(SEARCH)
+ f.editBox:FontTemplate()
+
+ f.editBox.searchIcon = f.editBox:CreateTexture(nil, "OVERLAY")
+ f.editBox.searchIcon:SetTexture("Interface\\Common\\UI-Searchbox-Icon")
+ f.editBox.searchIcon:Point("LEFT", f.editBox.backdrop, "LEFT", E.Border + 1, -1)
+ f.editBox.searchIcon:Size(15)
+ else
+ f.keyFrame = CreateFrame("Frame", name.."KeyFrame", f)
+ f.keyFrame:Point("TOPRIGHT", f, "TOPLEFT", -(E.PixelMode and 1 or 3), 0)
+ f.keyFrame:SetTemplate("Transparent")
+ f.keyFrame:SetID(KEYRING_CONTAINER)
+ f.keyFrame.slots = {}
+ f.keyFrame:Hide()
+
+ --Gold Text
+ f.goldText = f:CreateFontString(nil, "OVERLAY")
+ f.goldText:FontTemplate()
+ f.goldText:Point("BOTTOMRIGHT", f.holderFrame, "TOPRIGHT", -2, 4)
+ f.goldText:SetJustifyH("RIGHT")
+
+ --Sort Button
+ f.sortButton = CreateFrame("Button", name.."SortButton", f)
+ f.sortButton:Size(16 + E.Border)
+ f.sortButton:SetTemplate()
+ f.sortButton:Point("RIGHT", f.goldText, "LEFT", -5, E.Border * 2)
+ f.sortButton:SetNormalTexture(E.Media.Textures.Broom)
+ f.sortButton:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+ f.sortButton:GetNormalTexture():SetInside()
+ f.sortButton:SetPushedTexture(E.Media.Textures.Broom)
+ f.sortButton:GetPushedTexture():SetTexCoord(unpack(E.TexCoords))
+ f.sortButton:GetPushedTexture():SetInside()
+ f.sortButton:SetDisabledTexture(E.Media.Textures.Broom)
+ f.sortButton:GetDisabledTexture():SetTexCoord(unpack(E.TexCoords))
+ f.sortButton:GetDisabledTexture():SetInside()
+ f.sortButton:GetDisabledTexture():SetDesaturated(true)
+ f.sortButton:StyleButton(nil, true)
+ f.sortButton.ttText = L["Sort Bags"]
+ f.sortButton:SetScript("OnEnter", self.Tooltip_Show)
+ f.sortButton:SetScript("OnLeave", GameTooltip_Hide)
+ f.sortButton:SetScript("OnClick", function()
+ f:UnregisterAllEvents() --Unregister to prevent unnecessary updates
+ if not f.registerUpdate then
+ B:SortingFadeBags(f, true)
+ end
+ B:CommandDecorator(B.SortBags, "bags")()
+ end)
+ if E.db.bags.disableBagSort then
+ f.sortButton:Disable()
+ end
+
+ --Key Button
+ f.keyButton = CreateFrame("Button", name.."KeyButton", f)
+ f.keyButton:Size(16 + E.Border)
+ f.keyButton:SetTemplate()
+ f.keyButton:Point("RIGHT", f.sortButton, "LEFT", -5, 0)
+ f.keyButton:SetNormalTexture("Interface\\ICONS\\INV_Misc_Key_14")
+ f.keyButton:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+ f.keyButton:GetNormalTexture():SetInside()
+ f.keyButton:SetPushedTexture("Interface\\ICONS\\INV_Misc_Key_14")
+ f.keyButton:GetPushedTexture():SetTexCoord(unpack(E.TexCoords))
+ f.keyButton:GetPushedTexture():SetInside()
+ f.keyButton:StyleButton(nil, true)
+ f.keyButton.ttText = BINDING_NAME_TOGGLEKEYRING
+ f.keyButton:SetScript("OnEnter", self.Tooltip_Show)
+ f.keyButton:SetScript("OnLeave", GameTooltip_Hide)
+ f.keyButton:SetScript("OnClick", function() ToggleFrame(f.keyFrame) end)
+
+ --Bags Button
+ f.bagsButton = CreateFrame("Button", name.."BagsButton", f)
+ f.bagsButton:Size(16 + E.Border)
+ f.bagsButton:SetTemplate()
+ f.bagsButton:Point("RIGHT", f.keyButton, "LEFT", -5, 0)
+ f.bagsButton:SetNormalTexture("Interface\\Buttons\\Button-Backpack-Up")
+ f.bagsButton:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+ f.bagsButton:GetNormalTexture():SetInside()
+ f.bagsButton:SetPushedTexture("Interface\\Buttons\\Button-Backpack-Up")
+ f.bagsButton:GetPushedTexture():SetTexCoord(unpack(E.TexCoords))
+ f.bagsButton:GetPushedTexture():SetInside()
+ f.bagsButton:StyleButton(nil, true)
+ f.bagsButton.ttText = L["Toggle Bags"]
+ f.bagsButton:SetScript("OnEnter", B.Tooltip_Show)
+ f.bagsButton:SetScript("OnLeave", GameTooltip_Hide)
+ f.bagsButton:SetScript("OnClick", function() ToggleFrame(f.ContainerHolder) end)
+
+ --Vendor Grays
+ f.vendorGraysButton = CreateFrame("Button", nil, f.holderFrame)
+ f.vendorGraysButton:Size(16 + E.Border)
+ f.vendorGraysButton:SetTemplate()
+ f.vendorGraysButton:Point("RIGHT", f.bagsButton, "LEFT", -5, 0)
+ f.vendorGraysButton:SetNormalTexture("Interface\\ICONS\\INV_Misc_Coin_01")
+ f.vendorGraysButton:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+ f.vendorGraysButton:GetNormalTexture():SetInside()
+ f.vendorGraysButton:SetPushedTexture("Interface\\ICONS\\INV_Misc_Coin_01")
+ f.vendorGraysButton:GetPushedTexture():SetTexCoord(unpack(E.TexCoords))
+ f.vendorGraysButton:GetPushedTexture():SetInside()
+ f.vendorGraysButton:StyleButton(nil, true)
+ f.vendorGraysButton.ttText = L["Vendor / Delete Grays"]
+ f.vendorGraysButton:SetScript("OnEnter", B.Tooltip_Show)
+ f.vendorGraysButton:SetScript("OnLeave", GameTooltip_Hide)
+ f.vendorGraysButton:SetScript("OnClick", B.VendorGrayCheck)
+
+ --Search
+ f.editBox = CreateFrame("EditBox", name.."EditBox", f)
+ f.editBox:SetFrameLevel(f.editBox:GetFrameLevel() + 2)
+ f.editBox:CreateBackdrop()
+ f.editBox.backdrop:Point("TOPLEFT", f.editBox, "TOPLEFT", -20, 2)
+ f.editBox:Height(15)
+ f.editBox:Point("BOTTOMLEFT", f.holderFrame, "TOPLEFT", (E.Border * 2) + 18, E.Border * 2 + 2)
+ f.editBox:Point("RIGHT", f.vendorGraysButton, "LEFT", -5, 0)
+ f.editBox:SetAutoFocus(false)
+ f.editBox:SetScript("OnEscapePressed", B.ResetAndClear)
+ f.editBox:SetScript("OnEnterPressed", function(eb) eb:ClearFocus() end)
+ f.editBox:SetScript("OnEditFocusGained", f.editBox.HighlightText)
+ f.editBox:SetScript("OnTextChanged", B.UpdateSearch)
+ f.editBox:SetScript("OnChar", B.UpdateSearch)
+ f.editBox:SetText(SEARCH)
+ f.editBox:FontTemplate()
+
+ f.editBox.searchIcon = f.editBox:CreateTexture(nil, "OVERLAY")
+ f.editBox.searchIcon:SetTexture("Interface\\Common\\UI-Searchbox-Icon")
+ f.editBox.searchIcon:Point("LEFT", f.editBox.backdrop, "LEFT", E.Border + 1, -1)
+ f.editBox.searchIcon:Size(15)
+
+ --Currency
+ f.currencyButton = CreateFrame("Frame", nil, f)
+ f.currencyButton:Point("BOTTOM", 0, 4)
+ f.currencyButton:Point("TOPLEFT", f.holderFrame, "BOTTOMLEFT", 0, 18)
+ f.currencyButton:Point("TOPRIGHT", f.holderFrame, "BOTTOMRIGHT", 0, 18)
+ f.currencyButton:Height(22)
+
+ for i = 1, MAX_WATCHED_TOKENS do
+ f.currencyButton[i] = CreateFrame("Button", name.."CurrencyButton"..i, f.currencyButton)
+ f.currencyButton[i]:Size(16)
+ f.currencyButton[i]:SetTemplate()
+ f.currencyButton[i]:SetID(i)
+ f.currencyButton[i].icon = f.currencyButton[i]:CreateTexture(nil, "OVERLAY")
+ f.currencyButton[i].icon:SetInside()
+ f.currencyButton[i].icon:SetTexCoord(unpack(E.TexCoords))
+ f.currencyButton[i].text = f.currencyButton[i]:CreateFontString(nil, "OVERLAY")
+ f.currencyButton[i].text:Point("LEFT", f.currencyButton[i], "RIGHT", 2, 0)
+ f.currencyButton[i].text:FontTemplate()
+
+ f.currencyButton[i]:SetScript("OnEnter", B.Token_OnEnter)
+ f.currencyButton[i]:SetScript("OnLeave", GameTooltip_Hide)
+ f.currencyButton[i]:SetScript("OnClick", B.Token_OnClick)
+ f.currencyButton[i]:Hide()
+ end
+
+ f:SetScript("OnShow", B.RefreshSearch)
+ f:SetScript("OnHide", function()
+ CloseBackpack()
+ for i = 1, NUM_BAG_FRAMES do
+ CloseBag(i)
+ end
+
+ if ElvUIBags and ElvUIBags.buttons then
+ for _, bagButton in pairs(ElvUIBags.buttons) do
+ bagButton:SetChecked(false)
+ end
+ end
+
+ if E.db.bags.clearSearchOnClose then
+ B.ResetAndClear(f.editBox)
+ end
+ end)
+ end
+
+ tinsert(UISpecialFrames, f:GetName())
+ tinsert(B.BagFrames, f)
+ return f
+end
+
+function B:ToggleBags(id)
+ if id and (GetContainerNumSlots(id) == 0) then return end --Closes a bag when inserting a new container..
+
+ if not B.BagFrame:IsShown() then
+ B:OpenBags()
+-- else
+-- B:CloseBags()
+ end
+end
+
+function B:ToggleBackpack()
+ if IsOptionFrameOpen() then return end
+
+ if IsBagOpen(0) then
+ B:OpenBags()
+ PlaySound("igBackPackOpen")
+ else
+ B:CloseBags()
+ PlaySound("igBackPackClose")
+ end
+end
+
+function B:ToggleSortButtonState(isBank)
+ local button, disable
+ if isBank and B.BankFrame then
+ button = B.BankFrame.sortButton
+ disable = E.db.bags.disableBankSort
+ elseif not isBank and B.BagFrame then
+ button = B.BagFrame.sortButton
+ disable = E.db.bags.disableBagSort
+ end
+
+ if button and disable then
+ button:Disable()
+ elseif button and not disable then
+ button:Enable()
+ end
+end
+
+function B:OpenBags()
+ B.BagFrame:Show()
+
+ TT:GameTooltip_SetDefaultAnchor(GameTooltip)
+end
+
+function B:CloseBags()
+ B.BagFrame:Hide()
+
+ if B.BankFrame then
+ B.BankFrame:Hide()
+ end
+
+ TT:GameTooltip_SetDefaultAnchor(GameTooltip)
+end
+
+function B:OpenBank()
+ if not B.BankFrame then
+ B.BankFrame = B:ContructContainerFrame("ElvUI_BankContainerFrame", true)
+ end
+
+ --Call :Layout first so all elements are created before we update
+ B:Layout(true)
+
+ B:OpenBags()
+ B:UpdateTokens()
+
+ B.BankFrame:Show()
+end
+
+function B:PLAYERBANKBAGSLOTS_CHANGED()
+ B:Layout(true)
+end
+
+function B:GUILDBANKBAGSLOTS_CHANGED()
+ B:SetGuildBankSearch(SEARCH_STRING)
+end
+
+function B:CloseBank()
+ if not B.BankFrame then return end -- WHY??? WHO KNOWS!
+
+ B.BankFrame:Hide()
+ B.BagFrame:Hide()
+end
+
+function B:updateContainerFrameAnchors()
+ local xOffset, yOffset, screenHeight, freeScreenHeight, leftMostPoint, column
+ local screenWidth = GetScreenWidth()
+ local containerScale = 1
+ local leftLimit = 0
+
+ if BankFrame:IsShown() then
+ leftLimit = BankFrame:GetRight() - 25
+ end
+
+ while containerScale > CONTAINER_SCALE do
+ screenHeight = GetScreenHeight() / containerScale
+ -- Adjust the start anchor for bags depending on the multibars
+ xOffset = CONTAINER_OFFSET_X / containerScale
+ yOffset = CONTAINER_OFFSET_Y / containerScale
+ -- freeScreenHeight determines when to start a new column of bags
+ freeScreenHeight = screenHeight - yOffset
+ leftMostPoint = screenWidth - xOffset
+ column = 1
+
+ for _, frameName in ipairs(ContainerFrame1.bags) do
+ local frameHeight = _G[frameName]:GetHeight()
+
+ if freeScreenHeight < frameHeight then
+ -- Start a new column
+ column = column + 1
+ leftMostPoint = screenWidth - (column * CONTAINER_WIDTH * containerScale) - xOffset
+ freeScreenHeight = screenHeight - yOffset
+ end
+
+ freeScreenHeight = freeScreenHeight - frameHeight - VISIBLE_CONTAINER_SPACING
+ end
+
+ if leftMostPoint < leftLimit then
+ containerScale = containerScale - 0.01
+ else
+ break
+ end
+ end
+
+ if containerScale < CONTAINER_SCALE then
+ containerScale = CONTAINER_SCALE
+ end
+
+ screenHeight = GetScreenHeight() / containerScale
+ -- Adjust the start anchor for bags depending on the multibars
+ -- xOffset = CONTAINER_OFFSET_X / containerScale
+ yOffset = CONTAINER_OFFSET_Y / containerScale
+ -- freeScreenHeight determines when to start a new column of bags
+ freeScreenHeight = screenHeight - yOffset
+ column = 0
+
+ local bagsPerColumn = 0
+ for index, frameName in ipairs(ContainerFrame1.bags) do
+ local frame = _G[frameName]
+ frame:SetScale(1)
+
+ if index == 1 then
+ -- First bag
+ frame:Point("BOTTOMRIGHT", ElvUIBagMover, "BOTTOMRIGHT", E.Spacing, -E.Border)
+ bagsPerColumn = bagsPerColumn + 1
+ elseif freeScreenHeight < frame:GetHeight() then
+ -- Start a new column
+ column = column + 1
+ freeScreenHeight = screenHeight - yOffset
+ if column > 1 then
+ frame:Point("BOTTOMRIGHT", ContainerFrame1.bags[(index - bagsPerColumn) - 1], "BOTTOMLEFT", -CONTAINER_SPACING, 0)
+ else
+ frame:Point("BOTTOMRIGHT", ContainerFrame1.bags[index - bagsPerColumn], "BOTTOMLEFT", -CONTAINER_SPACING, 0)
+ end
+ bagsPerColumn = 0
+ else
+ -- Anchor to the previous bag
+ frame:Point("BOTTOMRIGHT", ContainerFrame1.bags[index - 1], "TOPRIGHT", 0, CONTAINER_SPACING)
+ bagsPerColumn = bagsPerColumn + 1
+ end
+
+ freeScreenHeight = freeScreenHeight - frame:GetHeight() - VISIBLE_CONTAINER_SPACING
+ end
+end
+
+function B:PostBagMove()
+ if not E.private.bags.enable then return end
+
+ -- self refers to the mover (bag or bank)
+ local x, y = self:GetCenter()
+ local screenHeight = E.UIParent:GetTop()
+ local screenWidth = E.UIParent:GetRight()
+
+ if y > (screenHeight / 2) then
+ self:SetText(self.textGrowDown)
+ self.POINT = ((x > (screenWidth / 2)) and "TOPRIGHT" or "TOPLEFT")
+ else
+ self:SetText(self.textGrowUp)
+ self.POINT = ((x > (screenWidth / 2)) and "BOTTOMRIGHT" or "BOTTOMLEFT")
+ end
+
+ local bagFrame
+ if self.name == "ElvUIBankMover" then
+ bagFrame = B.BankFrame
+ else
+ bagFrame = B.BagFrame
+ end
+
+ if bagFrame then
+ bagFrame:ClearAllPoints()
+ bagFrame:Point(self.POINT, self)
+ end
+end
+
+function B:MERCHANT_CLOSED()
+ B.SellFrame:Hide()
+end
+
+function B:ProgressQuickVendor()
+ local info = B.SellFrame.Info
+ local bag, slot, link, itemPrice, stackCount = unpack(info.itemList[1])
+
+ if info.delete then
+ itemPrice = 0
+ PickupContainerItem(bag, slot)
+ DeleteCursorItem()
+ else
+ UseContainerItem(bag, slot)
+
+ if link and info.details then
+ E:Print(format("%s|cFF00DDDDx%d|r %s", link, stackCount, B:FormatMoney(itemPrice)))
+ end
+
+ E.callbacks:Fire("VendorGreys_ItemSold", itemPrice)
+ end
+
+ tremove(info.itemList, 1)
+
+ return itemPrice, #info.itemList == 0
+end
+
+function B.VendorGreys_OnUpdate(self, elapsed)
+ local info = self.Info
+ info.SellTimer = info.SellTimer - elapsed
+
+ if info.SellTimer <= 0 then
+ info.SellTimer = info.SellInterval
+
+ local goldGained, lastItem = B:ProgressQuickVendor()
+ info.goldGained = info.goldGained + goldGained
+
+ if lastItem then
+ self:Hide()
+
+ if info.goldGained > 0 then
+ E:Print(format(L["Vendored gray items for: %s"], B:FormatMoney(info.goldGained)))
+ end
+
+ return
+ else
+ info.itemsSold = info.itemsSold + 1
+
+ self.statusbar:SetValue(info.itemsSold)
+ end
+ end
+
+ info.UpdateTimer = info.UpdateTimer + elapsed
+
+ if info.UpdateTimer >= 0.033 then
+ info.ProgressTimer = info.ProgressTimer - info.UpdateTimer
+ info.UpdateTimer = 0
+
+ self.statusbar.ValueText:SetFormattedText("%d / %d ( %.1fs )", info.itemsSold, info.ProgressMax, info.ProgressTimer + 0.05)
+ end
+end
+
+function B:CreateSellFrame()
+ B.SellFrame = CreateFrame("Frame", "ElvUIVendorGraysFrame", E.UIParent)
+ B.SellFrame:Size(200, 40)
+ B.SellFrame:Point("CENTER", E.UIParent)
+ B.SellFrame:CreateBackdrop("Transparent")
+ B.SellFrame:SetAlpha(E.db.bags.vendorGrays.progressBar and 1 or 0)
+ B.SellFrame:Hide()
+
+ B.SellFrame.title = B.SellFrame:CreateFontString(nil, "OVERLAY")
+ B.SellFrame.title:FontTemplate(nil, 12, "OUTLINE")
+ B.SellFrame.title:Point("TOP", B.SellFrame, "TOP", 0, -2)
+ B.SellFrame.title:SetText(L["Vendoring Grays"])
+
+ B.SellFrame.statusbar = CreateFrame("StatusBar", "ElvUIVendorGraysFrameStatusbar", B.SellFrame)
+ B.SellFrame.statusbar:Size(180, 16)
+ B.SellFrame.statusbar:Point("BOTTOM", B.SellFrame, "BOTTOM", 0, 4)
+ B.SellFrame.statusbar:SetStatusBarTexture(E.media.normTex)
+ B.SellFrame.statusbar:SetStatusBarColor(1, 0, 0)
+ B.SellFrame.statusbar:CreateBackdrop("Transparent")
+
+ B.SellFrame.statusbar.ValueText = B.SellFrame.statusbar:CreateFontString(nil, "OVERLAY")
+ B.SellFrame.statusbar.ValueText:FontTemplate(nil, 12, "OUTLINE")
+ B.SellFrame.statusbar.ValueText:Point("CENTER", B.SellFrame.statusbar)
+ B.SellFrame.statusbar.ValueText:SetText("0 / 0 ( 0s )")
+
+ B.SellFrame.Info = {
+ SellInterval = E.db.bags.vendorGrays.interval,
+ details = E.db.bags.vendorGrays.details,
+ itemList = {}
+ }
+
+ B.SellFrame:SetScript("OnUpdate", B.VendorGreys_OnUpdate)
+end
+
+function B:UpdateSellFrameSettings()
+ if not B.SellFrame then return end
+
+ B.SellFrame.Info.SellInterval = E.db.bags.vendorGrays.interval
+ B.SellFrame.Info.details = E.db.bags.vendorGrays.details
+
+ B.SellFrame:SetAlpha(E.db.bags.vendorGrays.progressBar and 1 or 0)
+end
+
+B.BagIndice = {
+ quiver = 0x0001,
+ ammoPouch = 0x0002,
+ soulBag = 0x0004,
+ leatherworking = 0x0008,
+ inscription = 0x0010,
+ herbs = 0x0020,
+ enchanting = 0x0040,
+ engineering = 0x0080,
+ gems = 0x0200,
+ mining = 0x0400,
+}
+
+B.QuestKeys = {
+ questStarter = "questStarter",
+ questItem = "questItem",
+}
+
+function B:UpdateBagColors(table, indice, r, g, b)
+ B[table][B.BagIndice[indice]] = {r, g, b}
+end
+
+function B:UpdateQuestColors(table, indice, r, g, b)
+ B[table][B.QuestKeys[indice]] = {r, g, b}
+end
+
+function B:Initialize()
+ B:LoadBagBar()
+
+ --Creating vendor grays frame
+ B:CreateSellFrame()
+ B:RegisterEvent("MERCHANT_CLOSED")
+
+ --Bag Mover (We want it created even if Bags module is disabled, so we can use it for default bags too)
+ local BagFrameHolder = CreateFrame("Frame", nil, E.UIParent)
+ BagFrameHolder:Width(200)
+ BagFrameHolder:Height(22)
+ BagFrameHolder:SetFrameLevel(BagFrameHolder:GetFrameLevel() + 400)
+
+ if not E.private.bags.enable then
+ -- Set a different default anchor
+ BagFrameHolder:Point("BOTTOMRIGHT", RightChatPanel, "BOTTOMRIGHT", E.PixelMode and 1 or -E.Border, 22 + E.Border*4 - E.Spacing*2)
+ E:CreateMover(BagFrameHolder, "ElvUIBagMover", L["Bag Mover"], nil, nil, B.PostBagMove, nil, nil, "bags,general")
+
+ B:SecureHook("updateContainerFrameAnchors")
+
+ return
+ end
+
+ B.Initialized = true
+ B.db = E.db.bags
+ B.BagFrames = {}
+ B.ProfessionColors = {
+ [0x0001] = {B.db.colors.profession.quiver.r, B.db.colors.profession.quiver.g, B.db.colors.profession.quiver.b},
+ [0x0002] = {B.db.colors.profession.ammoPouch.r, B.db.colors.profession.ammoPouch.g, B.db.colors.profession.ammoPouch.b},
+ [0x0004] = {B.db.colors.profession.soulBag.r, B.db.colors.profession.soulBag.g, B.db.colors.profession.soulBag.b},
+ [0x0008] = {B.db.colors.profession.leatherworking.r, B.db.colors.profession.leatherworking.g, B.db.colors.profession.leatherworking.b},
+ [0x0010] = {B.db.colors.profession.inscription.r, B.db.colors.profession.inscription.g, B.db.colors.profession.inscription.b},
+ [0x0020] = {B.db.colors.profession.herbs.r, B.db.colors.profession.herbs.g, B.db.colors.profession.herbs.b},
+ [0x0040] = {B.db.colors.profession.enchanting.r, B.db.colors.profession.enchanting.g, B.db.colors.profession.enchanting.b},
+ [0x0080] = {B.db.colors.profession.engineering.r, B.db.colors.profession.engineering.g, B.db.colors.profession.engineering.b},
+ [0x0200] = {B.db.colors.profession.gems.r, B.db.colors.profession.gems.g, B.db.colors.profession.gems.b},
+ [0x0400] = {B.db.colors.profession.mining.r, B.db.colors.profession.mining.g, B.db.colors.profession.mining.b},
+ }
+
+ B.QuestColors = {
+ ["questStarter"] = {B.db.colors.items.questStarter.r, B.db.colors.items.questStarter.g, B.db.colors.items.questStarter.b},
+ ["questItem"] = {B.db.colors.items.questItem.r, B.db.colors.items.questItem.g, B.db.colors.items.questItem.b},
+ }
+
+ --Bag Mover: Set default anchor point and create mover
+ BagFrameHolder:Point("BOTTOMRIGHT", RightChatPanel, "BOTTOMRIGHT", 0, 22 + E.Border*4 - E.Spacing*2)
+ E:CreateMover(BagFrameHolder, "ElvUIBagMover", L["Bag Mover (Grow Up)"], nil, nil, B.PostBagMove, nil, nil, "bags,general")
+
+ --Bank Mover
+ local BankFrameHolder = CreateFrame("Frame", nil, E.UIParent)
+ BankFrameHolder:Width(200)
+ BankFrameHolder:Height(22)
+ BankFrameHolder:Point("BOTTOMLEFT", LeftChatPanel, "BOTTOMLEFT", 0, 22 + E.Border*4 - E.Spacing*2)
+ BankFrameHolder:SetFrameLevel(BankFrameHolder:GetFrameLevel() + 400)
+ E:CreateMover(BankFrameHolder, "ElvUIBankMover", L["Bank Mover (Grow Up)"], nil, nil, B.PostBagMove, nil, nil, "bags,general")
+
+ --Set some variables on movers
+ ElvUIBagMover.textGrowUp = L["Bag Mover (Grow Up)"]
+ ElvUIBagMover.textGrowDown = L["Bag Mover (Grow Down)"]
+ ElvUIBagMover.POINT = "BOTTOM"
+ ElvUIBankMover.textGrowUp = L["Bank Mover (Grow Up)"]
+ ElvUIBankMover.textGrowDown = L["Bank Mover (Grow Down)"]
+ ElvUIBankMover.POINT = "BOTTOM"
+
+ --Create Bag Frame
+ B.BagFrame = B:ContructContainerFrame("ElvUI_ContainerFrame")
+
+ --Hook onto Blizzard Functions
+ B:SecureHook("OpenAllBags", "ToggleBackpack")
+ B:SecureHook("CloseAllBags", "CloseBags")
+ B:SecureHook("ToggleBag", "ToggleBags")
+ B:SecureHook("OpenBackpack", "OpenBags")
+ B:SecureHook("CloseBackpack", "CloseBags")
+ B:SecureHook("ToggleBackpack")
+ B:SecureHook("BackpackTokenFrame_Update", "UpdateTokens")
+ B:Layout()
+
+ B:DisableBlizzard()
+ B:RegisterEvent("PLAYER_ENTERING_WORLD", "UpdateGoldText")
+ B:RegisterEvent("PLAYER_MONEY", "UpdateGoldText")
+ B:RegisterEvent("PLAYER_TRADE_MONEY", "UpdateGoldText")
+ B:RegisterEvent("TRADE_MONEY_CHANGED", "UpdateGoldText")
+ B:RegisterEvent("BANKFRAME_OPENED", "OpenBank")
+ B:RegisterEvent("BANKFRAME_CLOSED", "CloseBank")
+ B:RegisterEvent("PLAYERBANKBAGSLOTS_CHANGED")
+ B:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED")
+end
+
+local function InitializeCallback()
+ B:Initialize()
+end
+
+E:RegisterModule(B:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Bags/Load_Bags.xml b/ElvUI/Modules/Bags/Load_Bags.xml
new file mode 100644
index 0000000..3213cc4
--- /dev/null
+++ b/ElvUI/Modules/Bags/Load_Bags.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/Bags/Sort.lua b/ElvUI/Modules/Bags/Sort.lua
new file mode 100644
index 0000000..822d48a
--- /dev/null
+++ b/ElvUI/Modules/Bags/Sort.lua
@@ -0,0 +1,906 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local B = E:GetModule("Bags")
+local Search = E.Libs.ItemSearch
+
+--Lua functions
+local ipairs, pairs, select, unpack, pcall = ipairs, pairs, select, unpack, pcall
+local strmatch, gmatch, strfind = strmatch, string.gmatch, strfind
+local tinsert, tremove, sort, wipe = tinsert, tremove, sort, wipe
+local tonumber, floor, band = tonumber, floor, bit.band
+--WoW API / Variables
+local ContainerIDToInventoryID = ContainerIDToInventoryID
+local GetAuctionItemClasses = GetAuctionItemClasses
+local GetAuctionItemSubClasses = GetAuctionItemSubClasses
+local GetContainerItemID = GetContainerItemID
+local GetContainerItemInfo = GetContainerItemInfo
+local GetContainerItemLink = GetContainerItemLink
+local GetContainerNumFreeSlots = GetContainerNumFreeSlots
+local GetContainerNumSlots = GetContainerNumSlots
+local GetCurrentGuildBankTab = GetCurrentGuildBankTab
+local GetCursorInfo = GetCursorInfo
+local GetGuildBankItemInfo = GetGuildBankItemInfo
+local GetGuildBankItemLink = GetGuildBankItemLink
+local GetGuildBankTabInfo = GetGuildBankTabInfo
+local GetInventoryItemLink = GetInventoryItemLink
+local GetItemFamily = GetItemFamily
+local GetItemInfo = GetItemInfo
+local GetTime = GetTime
+local InCombatLockdown = InCombatLockdown
+local PickupContainerItem = PickupContainerItem
+local PickupGuildBankItem = PickupGuildBankItem
+local QueryGuildBankTab = QueryGuildBankTab
+local SplitContainerItem = SplitContainerItem
+local SplitGuildBankItem = SplitGuildBankItem
+local ARMOR, ENCHSLOT_WEAPON = ARMOR, ENCHSLOT_WEAPON
+
+local MAX_MOVE_TIME = 1.25
+local guildBags = {51, 52, 53, 54, 55, 56, 57, 58}
+
+local bankBags = {BANK_CONTAINER}
+for i = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do
+ tinsert(bankBags, i)
+end
+
+local playerBags = {}
+for i = 0, NUM_BAG_SLOTS do
+ tinsert(playerBags, i)
+end
+
+local allBags = {}
+for _, i in ipairs(playerBags) do
+ tinsert(allBags, i)
+end
+for _, i in ipairs(bankBags) do
+ tinsert(allBags, i)
+end
+for _, i in ipairs(guildBags) do
+ tinsert(allBags, i)
+end
+
+local coreGroups = {
+ guild = guildBags,
+ bank = bankBags,
+ bags = playerBags,
+ all = allBags,
+}
+
+local bagCache = {}
+local bagIDs = {}
+local bagQualities = {}
+local bagStacks = {}
+local bagMaxStacks = {}
+local bagGroups = {}
+local initialOrder = {}
+local itemTypes, itemSubTypes = {}, {}
+local bagSorted, bagLocked = {}, {}
+local bagRole
+local moves = {}
+local targetItems = {}
+local sourceUsed = {}
+local targetSlots = {}
+local specialtyBags = {}
+local emptySlots = {}
+
+local moveRetries = 0
+local moveTracker = {}
+local lastItemID, lockStop, lastDestination, lastMove
+
+local inventorySlots = {
+ INVTYPE_AMMO = 0,
+ INVTYPE_HEAD = 1,
+ INVTYPE_NECK = 2,
+ INVTYPE_SHOULDER = 3,
+ INVTYPE_BODY = 4,
+ INVTYPE_CHEST = 5,
+ INVTYPE_ROBE = 5,
+ INVTYPE_WAIST = 6,
+ INVTYPE_LEGS = 7,
+ INVTYPE_FEET = 8,
+ INVTYPE_WRIST = 9,
+ INVTYPE_HAND = 10,
+ INVTYPE_FINGER = 11,
+ INVTYPE_TRINKET = 12,
+ INVTYPE_CLOAK = 13,
+ INVTYPE_WEAPON = 14,
+ INVTYPE_SHIELD = 15,
+ INVTYPE_2HWEAPON = 16,
+ INVTYPE_WEAPONMAINHAND = 18,
+ INVTYPE_WEAPONOFFHAND = 19,
+ INVTYPE_HOLDABLE = 20,
+ INVTYPE_RANGED = 21,
+ INVTYPE_THROWN = 22,
+ INVTYPE_RANGEDRIGHT = 23,
+ INVTYPE_RELIC = 24,
+ INVTYPE_TABARD = 25,
+}
+
+local safe = {
+ [BANK_CONTAINER] = true,
+ [0] = true
+}
+
+local WAIT_TIME = 0.05
+do
+ local t = 0
+ local frame = CreateFrame("Frame")
+ frame:SetScript("OnUpdate", function(_, elapsed)
+ t = t + (elapsed or 0.01)
+ if t > WAIT_TIME then
+ t = 0
+ B:DoMoves()
+ end
+ end)
+ frame:Hide()
+ B.SortUpdateTimer = frame
+end
+
+local function IsGuildBankBag(bagid)
+ return bagid > 50 and bagid <= 58
+end
+
+local function BuildSortOrder()
+ for i, iType in ipairs({GetAuctionItemClasses()}) do
+ itemTypes[iType] = i
+ itemSubTypes[iType] = {}
+ for ii, isType in ipairs({GetAuctionItemSubClasses(i)}) do
+ itemSubTypes[iType][isType] = ii
+ end
+ end
+end
+
+local function UpdateLocation(from, to)
+ if (bagIDs[from] == bagIDs[to]) and (bagStacks[to] < bagMaxStacks[to]) then
+ local stackSize = bagMaxStacks[to]
+ if (bagStacks[to] + bagStacks[from]) > stackSize then
+ bagStacks[from] = bagStacks[from] - (stackSize - bagStacks[to])
+ bagStacks[to] = stackSize
+ else
+ bagStacks[to] = bagStacks[to] + bagStacks[from]
+ bagStacks[from] = nil
+ bagIDs[from] = nil
+ bagQualities[from] = nil
+ bagMaxStacks[from] = nil
+ end
+ else
+ bagIDs[from], bagIDs[to] = bagIDs[to], bagIDs[from]
+ bagQualities[from], bagQualities[to] = bagQualities[to], bagQualities[from]
+ bagStacks[from], bagStacks[to] = bagStacks[to], bagStacks[from]
+ bagMaxStacks[from], bagMaxStacks[to] = bagMaxStacks[to], bagMaxStacks[from]
+ end
+end
+
+local function PrimarySort(a, b)
+ local aName, _, _, aLvl, _, _, _, _, _, _, aPrice = GetItemInfo(bagIDs[a])
+ local bName, _, _, bLvl, _, _, _, _, _, _, bPrice = GetItemInfo(bagIDs[b])
+
+ if aLvl ~= bLvl and aLvl and bLvl then
+ return aLvl > bLvl
+ end
+ if aPrice ~= bPrice and aPrice and bPrice then
+ return aPrice > bPrice
+ end
+
+ if aName and bName then
+ return aName < bName
+ end
+end
+
+local function DefaultSort(a, b)
+ local aID = bagIDs[a]
+ local bID = bagIDs[b]
+
+ if (not aID) or (not bID) then return aID end
+
+ local aOrder, bOrder = initialOrder[a], initialOrder[b]
+
+ if aID == bID then
+ local aCount = bagStacks[a]
+ local bCount = bagStacks[b]
+ if aCount and bCount and aCount == bCount then
+ return aOrder < bOrder
+ elseif aCount and bCount then
+ return aCount < bCount
+ end
+ end
+
+ local _, _, _, _, _, aType, aSubType, _, aEquipLoc = GetItemInfo(aID)
+ local _, _, _, _, _, bType, bSubType, _, bEquipLoc = GetItemInfo(bID)
+
+ local aRarity, bRarity = bagQualities[a], bagQualities[b]
+
+ if aRarity ~= bRarity and aRarity and bRarity then
+ return aRarity > bRarity
+ end
+
+ if itemTypes[aType] ~= itemTypes[bType] then
+ return (itemTypes[aType] or 99) < (itemTypes[bType] or 99)
+ end
+
+ local aItemClassId, aItemSubClassId = itemTypes[aType] or 99, itemSubTypes[aType] and itemSubTypes[aType][aSubType] or 99
+ local bItemClassId, bItemSubClassId = itemTypes[bType] or 99, itemSubTypes[bType] and itemSubTypes[bType][bSubType] or 99
+
+ if aItemClassId ~= bItemClassId then
+ return aItemClassId < bItemClassId
+ end
+
+ if aItemClassId == ARMOR or aItemClassId == ENCHSLOT_WEAPON then
+ aEquipLoc = inventorySlots[aEquipLoc] or -1
+ bEquipLoc = inventorySlots[bEquipLoc] or -1
+ if aEquipLoc == bEquipLoc then
+ return PrimarySort(a, b)
+ end
+
+ if aEquipLoc and bEquipLoc then
+ return aEquipLoc < bEquipLoc
+ end
+ end
+ if (aItemClassId == bItemClassId) and (aItemSubClassId == bItemSubClassId) then
+ return PrimarySort(a, b)
+ end
+
+ return (aItemSubClassId or 99) < (bItemSubClassId or 99)
+end
+
+local function ReverseSort(a, b)
+ return DefaultSort(b, a)
+end
+
+local function UpdateSorted(source, destination)
+ for i, bs in pairs(bagSorted) do
+ if bs == source then
+ bagSorted[i] = destination
+ elseif bs == destination then
+ bagSorted[i] = source
+ end
+ end
+end
+
+local function ShouldMove(source, destination)
+ if destination == source then return end
+
+ if not bagIDs[source] then return end
+ if bagIDs[source] == bagIDs[destination] and bagStacks[source] == bagStacks[destination] then return end
+
+ return true
+end
+
+local function IterateForwards(bagList, i)
+ i = i + 1
+ local step = 1
+ for _, bag in ipairs(bagList) do
+ local slots = B:GetNumSlots(bag, bagRole)
+ if i > slots + step then
+ step = step + slots
+ else
+ for slot = 1, slots do
+ if step == i then
+ return i, bag, slot
+ end
+ step = step + 1
+ end
+ end
+ end
+ bagRole = nil
+end
+
+local function IterateBackwards(bagList, i)
+ i = i + 1
+ local step = 1
+ for ii = #bagList, 1, -1 do
+ local bag = bagList[ii]
+ local slots = B:GetNumSlots(bag, bagRole)
+ if i > slots + step then
+ step = step + slots
+ else
+ for slot=slots, 1, -1 do
+ if step == i then
+ return i, bag, slot
+ end
+ step = step + 1
+ end
+ end
+ end
+ bagRole = nil
+end
+
+function B:IterateBags(bagList, reverse, role)
+ bagRole = role
+ return (reverse and IterateBackwards or IterateForwards), bagList, 0
+end
+
+function B:GetItemLink(bag, slot)
+ if IsGuildBankBag(bag) then
+ return GetGuildBankItemLink(bag - 50, slot)
+ else
+ return GetContainerItemLink(bag, slot)
+ end
+end
+
+function B:GetItemID(bag, slot)
+ if IsGuildBankBag(bag) then
+ local link = B:GetItemLink(bag, slot)
+ return link and tonumber(strmatch(link, "item:(%d+)"))
+ else
+ return GetContainerItemID(bag, slot)
+ end
+end
+
+function B:GetItemInfo(bag, slot)
+ if IsGuildBankBag(bag) then
+ return GetGuildBankItemInfo(bag - 50, slot)
+ else
+ return GetContainerItemInfo(bag, slot)
+ end
+end
+
+function B:PickupItem(bag, slot)
+ if IsGuildBankBag(bag) then
+ return PickupGuildBankItem(bag - 50, slot)
+ else
+ return PickupContainerItem(bag, slot)
+ end
+end
+
+function B:SplitItem(bag, slot, amount)
+ if IsGuildBankBag(bag) then
+ return SplitGuildBankItem(bag - 50, slot, amount)
+ else
+ return SplitContainerItem(bag, slot, amount)
+ end
+end
+
+function B:GetNumSlots(bag)
+ if IsGuildBankBag(bag) then
+ local name, _, canView = GetGuildBankTabInfo(bag - 50)
+ if name and canView then
+ return 98
+ end
+ else
+ return GetContainerNumSlots(bag)
+ end
+
+ return 0
+end
+
+function B:ConvertLinkToID(link)
+ if not link then return end
+
+ local item = strmatch(link, "item:(%d+)")
+ if item then return tonumber(item) end
+end
+
+local function DefaultCanMove()
+ return true
+end
+
+function B:Encode_BagSlot(bag, slot)
+ return (bag * 100) + slot
+end
+
+function B:Decode_BagSlot(int)
+ return floor(int / 100), int % 100
+end
+
+function B:IsPartial(bag, slot)
+ local bagSlot = B:Encode_BagSlot(bag, slot)
+ return ((bagMaxStacks[bagSlot] or 0) - (bagStacks[bagSlot] or 0)) > 0
+end
+
+function B:EncodeMove(source, target)
+ return (source * 10000) + target
+end
+
+function B:DecodeMove(move)
+ local s = floor(move/10000)
+ local t = move%10000
+ s = (t > 9000) and (s + 1) or s
+ t = (t > 9000) and (t - 10000) or t
+ return s, t
+end
+
+function B:AddMove(source, destination)
+ UpdateLocation(source, destination)
+ tinsert(moves, 1, B:EncodeMove(source, destination))
+end
+
+function B:ScanBags()
+ for _, bag, slot in B:IterateBags(allBags) do
+ local bagSlot = B:Encode_BagSlot(bag, slot)
+ local itemLink = B:GetItemLink(bag, slot)
+ local itemID = B:ConvertLinkToID(itemLink)
+ if itemID then
+ bagMaxStacks[bagSlot] = select(8, GetItemInfo(itemID))
+ bagIDs[bagSlot] = itemID
+ bagQualities[bagSlot] = select(3, GetItemInfo(itemLink))
+ bagStacks[bagSlot] = select(2, B:GetItemInfo(bag, slot))
+ end
+ end
+end
+
+function B:IsSpecialtyBag(bagID)
+ if safe[bagID] or IsGuildBankBag(bagID) then return false end
+
+ local inventorySlot = ContainerIDToInventoryID(bagID)
+ if not inventorySlot then return false end
+
+ local bag = GetInventoryItemLink("player", inventorySlot)
+ if not bag then return false end
+
+ local family = GetItemFamily(bag)
+ if family == 0 or family == nil then return false end
+
+ return family
+end
+
+function B:CanItemGoInBag(bag, slot, targetBag)
+ if IsGuildBankBag(targetBag) then return true end
+
+ local item = bagIDs[B:Encode_BagSlot(bag, slot)]
+ local itemFamily = GetItemFamily(item)
+ if itemFamily and itemFamily > 0 then
+ local equipSlot = select(9, GetItemInfo(item))
+ if equipSlot == "INVTYPE_QUIVER" then
+ itemFamily = 1
+ end
+ end
+ local bagFamily = select(2, GetContainerNumFreeSlots(targetBag))
+ if itemFamily then
+ return (bagFamily == 0) or band(itemFamily, bagFamily) > 0
+ else
+ return false
+ end
+end
+
+function B.Compress(...)
+ for i = 1, select("#", ...) do
+ local bags = select(i, ...)
+ B.Stack(bags, bags, B.IsPartial)
+ end
+end
+
+function B.Stack(sourceBags, targetBags, canMove)
+ if not canMove then canMove = DefaultCanMove end
+ for _, bag, slot in B:IterateBags(targetBags, nil, "deposit") do
+ local bagSlot = B:Encode_BagSlot(bag, slot)
+ local itemID = bagIDs[bagSlot]
+
+ if itemID and (bagStacks[bagSlot] ~= bagMaxStacks[bagSlot]) then
+ targetItems[itemID] = (targetItems[itemID] or 0) + 1
+ tinsert(targetSlots, bagSlot)
+ end
+ end
+
+ for _, bag, slot in B:IterateBags(sourceBags, true, "withdraw") do
+ local sourceSlot = B:Encode_BagSlot(bag, slot)
+ local itemID = bagIDs[sourceSlot]
+ if itemID and targetItems[itemID] and canMove(itemID, bag, slot) then
+ for i = #targetSlots, 1, -1 do
+ local targetedSlot = targetSlots[i]
+ if bagIDs[sourceSlot] and bagIDs[targetedSlot] == itemID and targetedSlot ~= sourceSlot and (bagStacks[targetedSlot] ~= bagMaxStacks[targetedSlot]) and not sourceUsed[targetedSlot] then
+ B:AddMove(sourceSlot, targetedSlot)
+ sourceUsed[sourceSlot] = true
+
+ if bagStacks[targetedSlot] == bagMaxStacks[targetedSlot] then
+ targetItems[itemID] = (targetItems[itemID] > 1) and (targetItems[itemID] - 1) or nil
+ end
+ if bagStacks[sourceSlot] == 0 then
+ targetItems[itemID] = (targetItems[itemID] > 1) and (targetItems[itemID] - 1) or nil
+ break
+ end
+ if not targetItems[itemID] then break end
+ end
+ end
+ end
+ end
+
+ wipe(targetItems)
+ wipe(targetSlots)
+ wipe(sourceUsed)
+end
+
+local blackListedSlots = {}
+local blackList = {}
+local blackListQueries = {}
+function B:BuildBlacklist(...)
+ for entry in pairs(...) do
+ local itemName = GetItemInfo(entry)
+
+ if itemName then
+ blackList[itemName] = true
+ elseif entry ~= "" then
+ if strfind(entry, "%[") and strfind(entry, "%]") then
+ --For some reason the entry was not treated as a valid item. Extract the item name.
+ entry = strmatch(entry, "%[(.*)%]")
+ end
+ blackListQueries[#blackListQueries+1] = entry
+ end
+ end
+end
+
+function B.Sort(bags, sorter, invertDirection)
+ if not sorter then sorter = invertDirection and ReverseSort or DefaultSort end
+ if not itemTypes then BuildSortOrder() end
+
+ --Wipe tables before we begin
+ wipe(blackList)
+ wipe(blackListQueries)
+ wipe(blackListedSlots)
+
+ --Build blacklist of items based on the profile and global list
+ B:BuildBlacklist(B.db.ignoredItems)
+ B:BuildBlacklist(E.global.bags.ignoredItems)
+
+ for i, bag, slot in B:IterateBags(bags, nil, "both") do
+ local bagSlot = B:Encode_BagSlot(bag, slot)
+ local link = B:GetItemLink(bag, slot)
+
+ if link then
+ if blackList[GetItemInfo(link)] then
+ blackListedSlots[bagSlot] = true
+ end
+
+ if not blackListedSlots[bagSlot] then
+ for _,itemsearchquery in pairs(blackListQueries) do
+ local success, result = pcall(Search.Matches, Search, link, itemsearchquery)
+ if success and result then
+ blackListedSlots[bagSlot] = result
+ break
+ end
+ end
+ end
+ end
+
+ if not blackListedSlots[bagSlot] then
+ initialOrder[bagSlot] = i
+ tinsert(bagSorted, bagSlot)
+ end
+ end
+
+ sort(bagSorted, sorter)
+
+ local passNeeded = true
+ while passNeeded do
+ passNeeded = false
+ local i = 1
+ for _, bag, slot in B:IterateBags(bags, nil, "both") do
+ local destination = B:Encode_BagSlot(bag, slot)
+ local source = bagSorted[i]
+
+ if not blackListedSlots[destination] then
+ if ShouldMove(source, destination) then
+ if not (bagLocked[source] or bagLocked[destination]) then
+ B:AddMove(source, destination)
+ UpdateSorted(source, destination)
+ bagLocked[source] = true
+ bagLocked[destination] = true
+ else
+ passNeeded = true
+ end
+ end
+ i = i + 1
+ end
+ end
+ wipe(bagLocked)
+ end
+
+ wipe(bagSorted)
+ wipe(initialOrder)
+end
+
+function B.FillBags(from, to)
+ B.Stack(from, to)
+ for _, bag in ipairs(to) do
+ if B:IsSpecialtyBag(bag) then
+ tinsert(specialtyBags, bag)
+ end
+ end
+ if #specialtyBags > 0 then
+ B:Fill(from, specialtyBags)
+ end
+
+ B.Fill(from, to)
+ wipe(specialtyBags)
+end
+
+function B.Fill(sourceBags, targetBags, reverse, canMove)
+ if not canMove then canMove = DefaultCanMove end
+
+ --Wipe tables before we begin
+ wipe(blackList)
+ wipe(blackListedSlots)
+
+ --Build blacklist of items based on the profile and global list
+ B:BuildBlacklist(B.db.ignoredItems)
+ B:BuildBlacklist(E.global.bags.ignoredItems)
+
+ for _, bag, slot in B:IterateBags(targetBags, reverse, "deposit") do
+ local bagSlot = B:Encode_BagSlot(bag, slot)
+ if not bagIDs[bagSlot] then
+ tinsert(emptySlots, bagSlot)
+ end
+ end
+
+ for _, bag, slot in B:IterateBags(sourceBags, not reverse, "withdraw") do
+ if #emptySlots == 0 then break end
+ local bagSlot = B:Encode_BagSlot(bag, slot)
+ local targetBag = B:Decode_BagSlot(emptySlots[1])
+ local link = B:GetItemLink(bag, slot)
+
+ if link and blackList[GetItemInfo(link)] then
+ blackListedSlots[bagSlot] = true
+ end
+
+ if bagIDs[bagSlot] and B:CanItemGoInBag(bag, slot, targetBag) and canMove(bagIDs[bagSlot], bag, slot) and not blackListedSlots[bagSlot] then
+ B:AddMove(bagSlot, tremove(emptySlots, 1))
+ end
+ end
+ wipe(emptySlots)
+end
+
+function B.SortBags(...)
+ for i = 1, select("#", ...) do
+ local bags = select(i, ...)
+ for _, slotNum in ipairs(bags) do
+ local bagType = B:IsSpecialtyBag(slotNum)
+ if bagType == false then bagType = "Normal" end
+ if not bagCache[bagType] then bagCache[bagType] = {} end
+ tinsert(bagCache[bagType], slotNum)
+ end
+
+ for bagType, sortedBags in pairs(bagCache) do
+ if bagType ~= "Normal" then
+ B.Stack(sortedBags, sortedBags, B.IsPartial)
+ B.Stack(bagCache.Normal, sortedBags)
+ B.Fill(bagCache.Normal, sortedBags, B.db.sortInverted)
+ B.Sort(sortedBags, nil, B.db.sortInverted)
+ wipe(sortedBags)
+ end
+ end
+
+ if bagCache.Normal then
+ B.Stack(bagCache.Normal, bagCache.Normal, B.IsPartial)
+ B.Sort(bagCache.Normal, nil, B.db.sortInverted)
+ wipe(bagCache.Normal)
+ end
+ wipe(bagCache)
+ wipe(bagGroups)
+ end
+end
+
+function B:StartStacking()
+ wipe(bagMaxStacks)
+ wipe(bagStacks)
+ wipe(bagIDs)
+ wipe(bagQualities)
+ wipe(moveTracker)
+
+ if #moves > 0 then
+ B.SortUpdateTimer:Show()
+ else
+ B:StopStacking()
+ end
+end
+
+function B:RegisterUpdateDelayed()
+ local shouldUpdateFade
+
+ for _, bagFrame in pairs(B.BagFrames) do
+ if bagFrame.registerUpdate then
+ B:UpdateAllSlots(bagFrame)
+
+ bagFrame:RegisterEvent("BAG_UPDATE")
+ bagFrame:RegisterEvent("BAG_UPDATE_COOLDOWN")
+
+ for _, event in pairs(bagFrame.events) do
+ bagFrame:RegisterEvent(event)
+ end
+
+ bagFrame.registerUpdate = nil
+ shouldUpdateFade = true -- we should refresh the bag search after sorting
+ end
+ end
+
+ if shouldUpdateFade then
+ B:RefreshSearch() -- this will clear the bag lock look during a sort
+ end
+end
+
+function B:StopStacking(message, noUpdate)
+ wipe(moves)
+ wipe(moveTracker)
+ moveRetries, lastItemID, lockStop, lastDestination, lastMove = 0, nil, nil, nil, nil
+
+ B.SortUpdateTimer:Hide()
+
+ if not noUpdate then
+ --Add a delayed update call, as BAG_UPDATE fires slightly delayed
+ -- and we don't want the last few unneeded updates to be catched
+ E:Delay(0.6, B.RegisterUpdateDelayed)
+ end
+
+ if message then
+ E:Print(message)
+ end
+end
+
+function B:DoMove(move)
+ if GetCursorInfo() == "item" then
+ return false, "cursorhasitem"
+ end
+
+ local source, target = B:DecodeMove(move)
+ local sourceBag, sourceSlot = B:Decode_BagSlot(source)
+ local targetBag, targetSlot = B:Decode_BagSlot(target)
+
+ local _, sourceCount, sourceLocked = B:GetItemInfo(sourceBag, sourceSlot)
+ local _, targetCount, targetLocked = B:GetItemInfo(targetBag, targetSlot)
+
+ if sourceLocked or targetLocked then
+ return false, "source/target_locked"
+ end
+
+ local sourceItemID = B:GetItemID(sourceBag, sourceSlot)
+ local targetItemID = B:GetItemID(targetBag, targetSlot)
+
+ if not sourceItemID then
+ if moveTracker[source] then
+ return false, "move incomplete"
+ else
+ return B:StopStacking(L["Confused.. Try Again!"])
+ end
+ end
+
+ local stackSize = select(8, GetItemInfo(sourceItemID))
+ if (sourceItemID == targetItemID) and (targetCount ~= stackSize) and ((targetCount + sourceCount) > stackSize) then
+ B:SplitItem(sourceBag, sourceSlot, stackSize - targetCount)
+ else
+ B:PickupItem(sourceBag, sourceSlot)
+ end
+
+ if GetCursorInfo() == "item" then
+ B:PickupItem(targetBag, targetSlot)
+ end
+
+ local sourceGuild = IsGuildBankBag(sourceBag)
+ local targetGuild = IsGuildBankBag(targetBag)
+
+ if sourceGuild then
+ QueryGuildBankTab(sourceBag - 50)
+ end
+ if targetGuild then
+ QueryGuildBankTab(targetBag - 50)
+ end
+
+ return true, sourceItemID, source, targetItemID, target, sourceGuild or targetGuild
+end
+
+function B:DoMoves()
+ if InCombatLockdown() then
+ return B:StopStacking(L["Confused.. Try Again!"])
+ end
+
+ local cursorType, cursorItemID = GetCursorInfo()
+ if cursorType == "item" and cursorItemID then
+ if lastItemID ~= cursorItemID then
+ return B:StopStacking(L["Confused.. Try Again!"])
+ end
+
+ if moveRetries < 100 then
+ local targetBag, targetSlot = B:Decode_BagSlot(lastDestination)
+ local _, _, targetLocked = B:GetItemInfo(targetBag, targetSlot)
+ if not targetLocked then
+ B:PickupItem(targetBag, targetSlot)
+ WAIT_TIME = 0.1
+ lockStop = GetTime()
+ moveRetries = moveRetries + 1
+ return
+ end
+ end
+ end
+
+ if lockStop then
+ for slot, itemID in pairs(moveTracker) do
+ local actualItemID = B:GetItemID(B:Decode_BagSlot(slot))
+ if actualItemID ~= itemID then
+ WAIT_TIME = 0.1
+ if (GetTime() - lockStop) > MAX_MOVE_TIME then
+ if lastMove and moveRetries < 100 then
+ local success, moveID, moveSource, targetID, moveTarget, wasGuild = B:DoMove(lastMove)
+ WAIT_TIME = wasGuild and 0.5 or 0.1
+
+ if not success then
+ lockStop = GetTime()
+ moveRetries = moveRetries + 1
+ return
+ end
+
+ moveTracker[moveSource] = targetID
+ moveTracker[moveTarget] = moveID
+ lastDestination = moveTarget
+ -- lastMove = moves[i] --Where does "i" come from???
+ lastItemID = moveID
+ -- tremove(moves, i) --Where does "i" come from???
+ return
+ end
+
+ B:StopStacking()
+ return
+ end
+ return --give processing time to happen
+ end
+ moveTracker[slot] = nil
+ end
+ end
+
+ lastItemID, lockStop, lastDestination, lastMove = nil, nil, nil, nil
+ wipe(moveTracker)
+
+ local success, moveID, targetID, moveSource, moveTarget, wasGuild
+ if #moves > 0 then
+ for i = #moves, 1, -1 do
+ success, moveID, moveSource, targetID, moveTarget, wasGuild = B:DoMove(moves[i])
+ if not success then
+ WAIT_TIME = wasGuild and 0.3 or 0.1
+ lockStop = GetTime()
+ return
+ end
+ moveTracker[moveSource] = targetID
+ moveTracker[moveTarget] = moveID
+ lastDestination = moveTarget
+ lastMove = moves[i]
+ lastItemID = moveID
+ tremove(moves, i)
+
+ if moves[i - 1] then
+ WAIT_TIME = wasGuild and 0.3 or 0
+ return
+ end
+ end
+ end
+ B:StopStacking()
+end
+
+function B:GetGroup(id)
+ if strmatch(id, "^[-%d,]+$") then
+ local bags = {}
+ for b in gmatch(id, "-?%d+") do
+ tinsert(bags, tonumber(b))
+ end
+ return bags
+ end
+ return coreGroups[id]
+end
+
+function B:CommandDecorator(func, groupsDefaults)
+ return function(groups)
+ if B.SortUpdateTimer:IsShown() then
+ B:StopStacking(L["Already Running.. Bailing Out!"], true)
+ return
+ end
+
+ wipe(bagGroups)
+ if not groups or #groups == 0 then
+ groups = groupsDefaults
+ end
+ for bags in gmatch((groups or ""), "%S+") do
+ if bags == "guild" then
+ bags = B:GetGroup(bags)
+ if bags then
+ tinsert(bagGroups, {bags[GetCurrentGuildBankTab()]})
+ end
+ else
+ bags = B:GetGroup(bags)
+ if bags then
+ tinsert(bagGroups, bags)
+ end
+ end
+ end
+
+ B:ScanBags()
+ if func(unpack(bagGroups)) == false then
+ return
+ end
+ wipe(bagGroups)
+ B:StartStacking()
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Blizzard/AlertFrame.lua b/ElvUI/Modules/Blizzard/AlertFrame.lua
new file mode 100644
index 0000000..3c36a9c
--- /dev/null
+++ b/ElvUI/Modules/Blizzard/AlertFrame.lua
@@ -0,0 +1,138 @@
+local E, L = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local B = E:GetModule("Blizzard")
+local Misc = E:GetModule("Misc")
+
+--Lua functions
+local _G = _G
+local pairs = pairs
+--WoW API / Variables
+local NUM_GROUP_LOOT_FRAMES = NUM_GROUP_LOOT_FRAMES
+
+local POSITION, ANCHOR_POINT, YOFFSET = "TOP", "BOTTOM", -10
+
+function E:PostAlertMove()
+ local _, y = AlertFrameMover:GetCenter()
+ local screenHeight = E.UIParent:GetTop()
+ if y > (screenHeight / 2) then
+ POSITION = "TOP"
+ ANCHOR_POINT = "BOTTOM"
+ YOFFSET = -10
+ AlertFrameMover:SetText(AlertFrameMover.textString.." [Grow Down]")
+ else
+ POSITION = "BOTTOM"
+ ANCHOR_POINT = "TOP"
+ YOFFSET = 10
+ AlertFrameMover:SetText(AlertFrameMover.textString.." [Grow Up]")
+ end
+
+ if E.private.general.lootRoll then
+ local lastframe, lastShownFrame
+ for i, frame in pairs(Misc.RollBars) do
+ frame:ClearAllPoints()
+ if i ~= 1 then
+ if POSITION == "TOP" then
+ frame:Point("TOP", lastframe, "BOTTOM", 0, -4)
+ else
+ frame:Point("BOTTOM", lastframe, "TOP", 0, 4)
+ end
+ else
+ if POSITION == "TOP" then
+ frame:Point("TOP", AlertFrameHolder, "BOTTOM", 0, -4)
+ else
+ frame:Point("BOTTOM", AlertFrameHolder, "TOP", 0, 4)
+ end
+ end
+ lastframe = frame
+
+ if frame:IsShown() then
+ lastShownFrame = frame
+ end
+ end
+
+ AlertFrame:ClearAllPoints()
+ if lastShownFrame then
+ AlertFrame:SetAllPoints(lastShownFrame)
+ else
+ AlertFrame:SetAllPoints(AlertFrameHolder)
+ end
+ elseif E.private.skins.blizzard.enable and E.private.skins.blizzard.lootRoll then
+ local lastframe, lastShownFrame
+ for i = 1, NUM_GROUP_LOOT_FRAMES do
+ local frame = _G["GroupLootFrame"..i]
+ if frame then
+ frame:ClearAllPoints()
+ if i ~= 1 then
+ if POSITION == "TOP" then
+ frame:Point("TOP", lastframe, "BOTTOM", 0, -4)
+ else
+ frame:Point("BOTTOM", lastframe, "TOP", 0, 4)
+ end
+ else
+ if POSITION == "TOP" then
+ frame:Point("TOP", AlertFrameHolder, "BOTTOM", 0, -4)
+ else
+ frame:Point("BOTTOM", AlertFrameHolder, "TOP", 0, 4)
+ end
+ end
+ lastframe = frame
+
+ if frame:IsShown() then
+ lastShownFrame = frame
+ end
+ end
+ end
+
+ AlertFrame:ClearAllPoints()
+ if lastShownFrame then
+ AlertFrame:SetAllPoints(lastShownFrame)
+ else
+ AlertFrame:SetAllPoints(AlertFrameHolder)
+ end
+ else
+ AlertFrame:ClearAllPoints()
+ AlertFrame:SetAllPoints(AlertFrameHolder)
+ end
+end
+
+function B:AchievementAlertFrame_FixAnchors()
+ local alertAnchor
+ for i = 1, MAX_ACHIEVEMENT_ALERTS do
+ local frame = _G["AchievementAlertFrame"..i]
+ if frame then
+ frame:ClearAllPoints()
+ if alertAnchor and alertAnchor:IsShown() then
+ frame:Point(POSITION, alertAnchor, ANCHOR_POINT, 0, YOFFSET)
+ else
+ frame:Point(POSITION, AlertFrame, ANCHOR_POINT)
+ end
+
+ alertAnchor = frame
+ end
+ end
+end
+
+function B:DungeonCompletionAlertFrame_FixAnchors()
+ for i = MAX_ACHIEVEMENT_ALERTS, 1, -1 do
+ local frame = _G["AchievementAlertFrame"..i]
+ if frame and frame:IsShown() then
+ DungeonCompletionAlertFrame1:ClearAllPoints()
+ DungeonCompletionAlertFrame1:Point(POSITION, frame, ANCHOR_POINT, 0, YOFFSET)
+ return
+ end
+
+ DungeonCompletionAlertFrame1:ClearAllPoints()
+ DungeonCompletionAlertFrame1:Point(POSITION, AlertFrame, ANCHOR_POINT)
+ end
+end
+
+function B:AlertMovers()
+ local AlertFrameHolder = CreateFrame("Frame", "AlertFrameHolder", E.UIParent)
+ AlertFrameHolder:Size(250, 20)
+ AlertFrameHolder:Point("TOP", E.UIParent, "TOP", 0, -18)
+
+ self:SecureHook("AlertFrame_FixAnchors", E.PostAlertMove)
+ self:SecureHook("AchievementAlertFrame_FixAnchors")
+ self:SecureHook("DungeonCompletionAlertFrame_FixAnchors")
+
+ E:CreateMover(AlertFrameHolder, "AlertFrameMover", L["Loot / Alert Frames"], nil, nil, E.PostAlertMove, nil, nil, "general,blizzUIImprovements")
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Blizzard/Blizzard.lua b/ElvUI/Modules/Blizzard/Blizzard.lua
new file mode 100644
index 0000000..385d603
--- /dev/null
+++ b/ElvUI/Modules/Blizzard/Blizzard.lua
@@ -0,0 +1,109 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local B = E:GetModule("Blizzard")
+
+--Lua functions
+--WoW API / Variables
+local ChatEdit_ChooseBoxForSend = ChatEdit_ChooseBoxForSend
+local GetTradeSkillListLink = GetTradeSkillListLink
+local Minimap_SetPing = Minimap_SetPing
+local UnitIsUnit = UnitIsUnit
+local MINIMAPPING_FADE_TIMER = MINIMAPPING_FADE_TIMER
+
+function B:ADDON_LOADED(_, addon)
+ if addon == "Blizzard_TradeSkillUI" then
+ TradeSkillLinkButton:SetScript("OnClick", function()
+ local ChatFrameEditBox = ChatEdit_ChooseBoxForSend()
+ if not ChatFrameEditBox:IsShown() then
+ ChatEdit_ActivateChat(ChatFrameEditBox)
+ end
+
+ ChatFrameEditBox:Insert(GetTradeSkillListLink())
+ end)
+
+ self:UnregisterEvent("ADDON_LOADED")
+ end
+end
+
+function B:Initialize()
+ self.Initialized = true
+
+ self:AlertMovers()
+ self:EnhanceColorPicker()
+ self:KillBlizzard()
+ self:PositionCaptureBar()
+ self:PositionDurabilityFrame()
+ self:PositionGMFrames()
+ self:PositionVehicleFrame()
+ self:MoveWatchFrame()
+
+ self:RegisterEvent("ADDON_LOADED")
+ self:RegisterEvent("ZONE_CHANGED_NEW_AREA", SetMapToCurrentZone)
+
+ KBArticle_BeginLoading = E.noop
+ KBSetup_BeginLoading = E.noop
+ KnowledgeBaseFrame_OnEvent(nil, "KNOWLEDGE_BASE_SETUP_LOAD_FAILURE")
+
+ if GetLocale() == "deDE" then
+ DAY_ONELETTER_ABBR = "%d d"
+ MINUTE_ONELETTER_ABBR = "%d m"
+ end
+
+ CreateFrame("Frame"):SetScript("OnUpdate", function()
+ if LFRBrowseFrame.timeToClear then
+ LFRBrowseFrame.timeToClear = nil
+ end
+ end)
+
+ MinimapPing:HookScript("OnUpdate", function(self)
+ if self.fadeOut or self.timer > MINIMAPPING_FADE_TIMER then
+ Minimap_SetPing(Minimap:GetPingPosition())
+ end
+ end)
+
+ QuestLogFrame:HookScript("OnShow", function()
+ local questFrame = QuestLogFrame:GetFrameLevel()
+ local controlPanel = QuestLogControlPanel:GetFrameLevel()
+ local scrollFrame = QuestLogDetailScrollFrame:GetFrameLevel()
+
+ if questFrame >= controlPanel then
+ QuestLogControlPanel:SetFrameLevel(questFrame + 1)
+ end
+ if questFrame >= scrollFrame then
+ QuestLogDetailScrollFrame:SetFrameLevel(questFrame + 1)
+ end
+ end)
+
+ ReadyCheckFrame:HookScript("OnShow", function(self)
+ if UnitIsUnit("player", self.initiator) then
+ self:Hide()
+ end
+ end)
+
+-- WORLDMAP_POI_FRAMELEVEL = 300
+-- WorldMapFrame:SetToplevel(true)
+
+ do
+ local originalFunc = LFDQueueFrameRandomCooldownFrame_OnEvent
+ local originalScript = LFDQueueFrameCooldownFrame:GetScript("OnEvent")
+
+ LFDQueueFrameRandomCooldownFrame_OnEvent = function(self, event, unit, ...)
+ if event == "UNIT_AURA" and not unit then return end
+ originalFunc(self, event, unit, ...)
+ end
+
+ if originalFunc == originalScript then
+ LFDQueueFrameCooldownFrame:SetScript("OnEvent", LFDQueueFrameRandomCooldownFrame_OnEvent)
+ else
+ LFDQueueFrameCooldownFrame:SetScript("OnEvent", function(self, event, unit, ...)
+ if event == "UNIT_AURA" and not unit then return end
+ originalScript(self, event, unit, ...)
+ end)
+ end
+ end
+end
+
+local function InitializeCallback()
+ B:Initialize()
+end
+
+E:RegisterModule(B:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Blizzard/CaptureBar.lua b/ElvUI/Modules/Blizzard/CaptureBar.lua
new file mode 100644
index 0000000..3250963
--- /dev/null
+++ b/ElvUI/Modules/Blizzard/CaptureBar.lua
@@ -0,0 +1,63 @@
+local E, L = unpack(select(2, ...)); --Import: Engine, Locales
+local B = E:GetModule("Blizzard")
+
+--Lua functions
+local _G = _G
+--WoW API / Variables
+
+local numAlwaysUpFrames = 0
+local pvpHolder = CreateFrame("Frame", "ElvUI_PvPHolder", E.UIParent)
+
+local function styleAlwaysUpFrame(id)
+ local frame = _G["AlwaysUpFrame"..id]
+ local text = _G["AlwaysUpFrame"..id.."Text"]
+ local icon = _G["AlwaysUpFrame"..id.."Icon"]
+ local dynamic = _G["AlwaysUpFrame"..id.."DynamicIconButton"]
+
+ text:ClearAllPoints()
+ text:Point("CENTER", frame, "CENTER", 0, 0)
+
+ icon:ClearAllPoints()
+ icon:Point("CENTER", text, "LEFT", -10, -9)
+
+ dynamic:ClearAllPoints()
+ dynamic:Point("LEFT", text, "RIGHT", 5, 0)
+
+ if id == 1 then
+ frame:ClearAllPoints()
+ frame:Point("CENTER", pvpHolder, "CENTER", 0, 5)
+ frame.SetPoint = E.noop
+ end
+end
+
+local function repositionCaptureBar(id)
+ local bar = _G["WorldStateCaptureBar"..id]
+ bar:ClearAllPoints()
+ bar:Point("TOP", pvpHolder, "BOTTOM", 0, -75)
+ bar.SetPoint = E.noop
+end
+
+function B:WorldStateAlwaysUpFrame_Update()
+ if numAlwaysUpFrames < NUM_ALWAYS_UP_UI_FRAMES then
+ for id = numAlwaysUpFrames + 1, NUM_ALWAYS_UP_UI_FRAMES do
+ styleAlwaysUpFrame(id)
+ numAlwaysUpFrames = id
+ end
+ end
+end
+
+function B:PositionCaptureBar()
+ pvpHolder:Size(30, 70)
+ pvpHolder:Point("TOP", E.UIParent, "TOP", 0, -4)
+
+ hooksecurefunc("WorldStateAlwaysUpFrame_Update", B.WorldStateAlwaysUpFrame_Update)
+ hooksecurefunc(ExtendedUI["CAPTUREPOINT"], "create", repositionCaptureBar)
+
+ if NUM_EXTENDED_UI_FRAMES > 0 then
+ for id = 1, NUM_EXTENDED_UI_FRAMES do
+ repositionCaptureBar(id)
+ end
+ end
+
+ E:CreateMover(pvpHolder, "PvPMover", L["PvP"], nil, nil, nil, "ALL")
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Blizzard/ColorPicker.lua b/ElvUI/Modules/Blizzard/ColorPicker.lua
new file mode 100644
index 0000000..4402513
--- /dev/null
+++ b/ElvUI/Modules/Blizzard/ColorPicker.lua
@@ -0,0 +1,388 @@
+--[[
+ Credit to Jaslm, most of this code is his from the addon ColorPickerPlus
+]]
+
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local B = E:GetModule("Blizzard")
+local S = E:GetModule("Skins")
+
+--Lua functions
+local strlen, strjoin, gsub = strlen, strjoin, gsub
+local tonumber, floor, strsub, wipe = tonumber, floor, strsub, wipe
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local IsAddOnLoaded = IsAddOnLoaded
+local CALENDAR_COPY_EVENT, CALENDAR_PASTE_EVENT = CALENDAR_COPY_EVENT, CALENDAR_PASTE_EVENT
+local CLASS, DEFAULT = CLASS, DEFAULT
+
+local colorBuffer = {}
+local function alphaValue(num)
+ return num and floor(((1 - num) * 100) + .05) or 0
+end
+
+local function UpdateAlphaText(alpha)
+ if not alpha then alpha = alphaValue(OpacitySliderFrame:GetValue()) end
+
+ ColorPPBoxA:SetText(alpha)
+end
+
+local function UpdateAlpha(tbox)
+ local num = tbox:GetNumber()
+ if num > 100 then
+ tbox:SetText(100)
+ num = 100
+ end
+
+ OpacitySliderFrame:SetValue(1 - (num / 100))
+end
+
+local function expandFromThree(r, g, b)
+ return strjoin("",r,r,g,g,b,b)
+end
+
+local function extendToSix(str)
+ for _=1, 6-strlen(str) do str=str..0 end
+ return str
+end
+
+local function GetHexColor(box)
+ local rgb, rgbSize = box:GetText(), box:GetNumLetters()
+ if rgbSize == 3 then
+ rgb = gsub(rgb, "(%x)(%x)(%x)$", expandFromThree)
+ elseif rgbSize < 6 then
+ rgb = gsub(rgb, "(.+)$", extendToSix)
+ end
+
+ local r, g, b = tonumber(strsub(rgb,0,2),16) or 0, tonumber(strsub(rgb,3,4),16) or 0, tonumber(strsub(rgb,5,6),16) or 0
+
+ return r/255, g/255, b/255
+end
+
+local function UpdateColorTexts(r, g, b, box)
+ if not (r and g and b) then
+ r, g, b = ColorPickerFrame:GetColorRGB()
+
+ if box then
+ if box == ColorPPBoxH then
+ r, g, b = GetHexColor(box)
+ else
+ local num = box:GetNumber()
+ if num > 255 then num = 255 end
+ local c = num/255
+ if box == ColorPPBoxR then
+ r = c
+ elseif box == ColorPPBoxG then
+ g = c
+ elseif box == ColorPPBoxB then
+ b = c
+ end
+ end
+ end
+ end
+
+ -- we want those /255 values
+ r, g, b = r*255, g*255, b*255
+
+ ColorPPBoxH:SetText(string.format("%.2x%.2x%.2x", r, g, b))
+ ColorPPBoxR:SetText(r)
+ ColorPPBoxG:SetText(g)
+ ColorPPBoxB:SetText(b)
+end
+
+local function UpdateColor(box)
+ if box:GetID() == 4 and box:GetNumLetters() ~= 6 then return else UpdateColorTexts(nil, nil, nil, box) end
+
+ local r, g, b = GetHexColor(ColorPPBoxH)
+ ColorPickerFrame:SetColorRGB(r, g, b)
+ ColorSwatch:SetTexture(r, g, b)
+end
+
+local function ColorPPBoxA_SetFocus()
+ ColorPPBoxA:SetFocus()
+end
+
+local function ColorPPBoxR_SetFocus()
+ ColorPPBoxR:SetFocus()
+end
+
+local delayWait, delayFunc = 0.15
+local function delayCall()
+ if delayFunc then
+ delayFunc()
+ delayFunc = nil
+ end
+end
+local function onColorSelect(frame, r, g, b)
+ if frame.noColorCallback then return end
+
+ ColorSwatch:SetTexture(r, g, b)
+ UpdateColorTexts(r, g, b)
+
+ if not frame:IsVisible() then
+ delayCall()
+ elseif not delayFunc then
+ delayFunc = ColorPickerFrame.func
+ E:Delay(delayWait, delayCall)
+ end
+end
+
+local function onValueChanged(frame, value)
+ local alpha = alphaValue(value)
+ if frame.lastAlpha ~= alpha then
+ frame.lastAlpha = alpha
+
+ UpdateAlphaText(alpha)
+
+ if not ColorPickerFrame:IsVisible() then
+ delayCall()
+ else
+ local opacityFunc = ColorPickerFrame.opacityFunc
+ if delayFunc and (delayFunc ~= opacityFunc) then
+ delayFunc = opacityFunc
+ elseif not delayFunc then
+ delayFunc = opacityFunc
+ E:Delay(delayWait, delayCall)
+ end
+ end
+ end
+end
+
+function B:EnhanceColorPicker()
+ if IsAddOnLoaded("ColorPickerPlus") then return end
+
+ --Skin the default frame, move default buttons into place
+ ColorPickerFrame:SetClampedToScreen(true)
+ ColorPickerFrame:SetTemplate("Transparent")
+ ColorPickerFrameHeader:SetTexture()
+ ColorPickerFrameHeader:ClearAllPoints()
+ ColorPickerFrameHeader:Point("TOP", ColorPickerFrame, 0, 0)
+ ColorPickerCancelButton:ClearAllPoints()
+ ColorPickerOkayButton:ClearAllPoints()
+ ColorPickerCancelButton:Point("BOTTOMRIGHT", ColorPickerFrame, "BOTTOMRIGHT", -6, 6)
+ ColorPickerCancelButton:Point("BOTTOMLEFT", ColorPickerFrame, "BOTTOM", 0, 6)
+ ColorPickerOkayButton:Point("BOTTOMLEFT", ColorPickerFrame,"BOTTOMLEFT", 6,6)
+ ColorPickerOkayButton:Point("RIGHT", ColorPickerCancelButton,"LEFT", -4,0)
+ S:HandleSliderFrame(OpacitySliderFrame)
+ S:HandleButton(ColorPickerOkayButton)
+ S:HandleButton(ColorPickerCancelButton)
+
+ ColorPickerFrame:HookScript("OnShow", function(frame)
+ -- get color that will be replaced
+ local r, g, b = frame:GetColorRGB()
+ ColorPPOldColorSwatch:SetTexture(r,g,b)
+
+ -- show/hide the alpha box
+ if frame.hasOpacity then
+ ColorPPBoxA:Show()
+ ColorPPBoxLabelA:Show()
+ ColorPPBoxH:SetScript("OnTabPressed", ColorPPBoxA_SetFocus)
+ UpdateAlphaText()
+ UpdateColorTexts()
+ frame:Width(405)
+ else
+ ColorPPBoxA:Hide()
+ ColorPPBoxLabelA:Hide()
+ ColorPPBoxH:SetScript("OnTabPressed", ColorPPBoxR_SetFocus)
+ UpdateColorTexts()
+ frame:Width(345)
+ end
+
+ -- Memory Fix, Colorpicker will call the self.func() 100x per second, causing fps/memory issues,
+ -- We overwrite these two scripts and set a limit on how often we allow a call their update functions
+ OpacitySliderFrame:SetScript("OnValueChanged", onValueChanged)
+ frame:SetScript("OnColorSelect", onColorSelect)
+ end)
+
+ -- make the Color Picker dialog a bit taller, to make room for edit boxes
+ ColorPickerFrame:Height(ColorPickerFrame:GetHeight() + 40)
+
+ -- move the Color Swatch
+ ColorSwatch:ClearAllPoints()
+ ColorSwatch:Point("TOPLEFT", ColorPickerFrame, "TOPLEFT", 215, -45)
+
+ -- add Color Swatch for original color
+ local t = ColorPickerFrame:CreateTexture("ColorPPOldColorSwatch")
+ local w, h = ColorSwatch:GetSize()
+ t:Size(w*0.75,h*0.75)
+ t:SetTexture(0,0,0)
+ -- OldColorSwatch to appear beneath ColorSwatch
+ t:SetDrawLayer("BORDER")
+ t:Point("BOTTOMLEFT", ColorSwatch, "TOPRIGHT", -(w/2), -(h/3))
+
+ -- add Color Swatch for the copied color
+ t = ColorPickerFrame:CreateTexture("ColorPPCopyColorSwatch")
+ t:SetTexture(0,0,0)
+ t:Size(w,h)
+ t:Hide()
+
+ -- add copy button to the ColorPickerFrame
+ local b = CreateFrame("Button", "ColorPPCopy", ColorPickerFrame, "UIPanelButtonTemplate")
+ S:HandleButton(b)
+ b:SetText(CALENDAR_COPY_EVENT)
+ b:Width(60)
+ b:Height(22)
+ b:Point("TOPLEFT", ColorSwatch, "BOTTOMLEFT", 0, -5)
+
+ -- copy color into buffer on button click
+ b:SetScript("OnClick", function()
+ -- copy current dialog colors into buffer
+ colorBuffer.r, colorBuffer.g, colorBuffer.b = ColorPickerFrame:GetColorRGB()
+
+ -- enable Paste button and display copied color into swatch
+ ColorPPPaste:Enable()
+ ColorPPCopyColorSwatch:SetTexture(colorBuffer.r, colorBuffer.g, colorBuffer.b)
+ ColorPPCopyColorSwatch:Show()
+
+ colorBuffer.a = (ColorPickerFrame.hasOpacity and OpacitySliderFrame:GetValue()) or nil
+ end)
+
+ --class color button
+ b = CreateFrame("Button", "ColorPPClass", ColorPickerFrame, "UIPanelButtonTemplate")
+ b:SetText(CLASS)
+ S:HandleButton(b)
+ b:Width(80)
+ b:Height(22)
+ b:Point("TOP", ColorPPCopy, "BOTTOMRIGHT", 0, -7)
+
+ b:SetScript("OnClick", function()
+ local color = E.media.herocolor
+ ColorPickerFrame:SetColorRGB(color.r, color.g, color.b)
+ ColorSwatch:SetTexture(color.r, color.g, color.b)
+ if ColorPickerFrame.hasOpacity then
+ OpacitySliderFrame:SetValue(0)
+ end
+ end)
+
+ -- add paste button to the ColorPickerFrame
+ b = CreateFrame("Button", "ColorPPPaste", ColorPickerFrame, "UIPanelButtonTemplate")
+ b:SetText(CALENDAR_PASTE_EVENT)
+ S:HandleButton(b)
+ b:Width(60)
+ b:Height(22)
+ b:Point("TOPLEFT", ColorPPCopy, "TOPRIGHT", 2, 0)
+ b:Disable() -- enable when something has been copied
+
+ -- paste color on button click, updating frame components
+ b:SetScript("OnClick", function()
+ ColorPickerFrame:SetColorRGB(colorBuffer.r, colorBuffer.g, colorBuffer.b)
+ ColorSwatch:SetTexture(colorBuffer.r, colorBuffer.g, colorBuffer.b)
+ if ColorPickerFrame.hasOpacity then
+ if colorBuffer.a then --color copied had an alpha value
+ OpacitySliderFrame:SetValue(colorBuffer.a)
+ end
+ end
+ end)
+
+ -- add defaults button to the ColorPickerFrame
+ b = CreateFrame("Button", "ColorPPDefault", ColorPickerFrame, "UIPanelButtonTemplate")
+ b:SetText(DEFAULT)
+ S:HandleButton(b)
+ b:Width(80)
+ b:Height(22)
+ b:Point("TOPLEFT", ColorPPClass, "BOTTOMLEFT", 0, -7)
+ b:Disable() -- enable when something has been copied
+ b:SetScript("OnHide", function(btn)
+ if btn.colors then
+ wipe(btn.colors)
+ end
+ end)
+ b:SetScript("OnShow", function(btn)
+ if btn.colors then
+ btn:Enable()
+ else
+ btn:Disable()
+ end
+ end)
+
+ -- paste color on button click, updating frame components
+ b:SetScript("OnClick", function(btn)
+ local colors = btn.colors
+ ColorPickerFrame:SetColorRGB(colors.r, colors.g, colors.b)
+ ColorSwatch:SetTexture(colors.r, colors.g, colors.b)
+ if ColorPickerFrame.hasOpacity then
+ if colors.a then
+ OpacitySliderFrame:SetValue(colors.a)
+ end
+ end
+ end)
+
+ -- position Color Swatch for copy color
+ ColorPPCopyColorSwatch:Point("BOTTOM", ColorPPPaste, "TOP", 0, 10)
+
+ -- move the Opacity Slider Frame to align with bottom of Copy ColorSwatch
+ OpacitySliderFrame:ClearAllPoints()
+ OpacitySliderFrame:Point("BOTTOM", ColorPPDefault, "BOTTOM", 0, 0)
+ OpacitySliderFrame:Point("RIGHT", ColorPickerFrame, "RIGHT", -35, 18)
+
+ -- set up edit box frames and interior label and text areas
+ local boxes = {"R", "G", "B", "H", "A"}
+ for i = 1, #boxes do
+ local rgb = boxes[i]
+ local box = CreateFrame("EditBox", "ColorPPBox"..rgb, ColorPickerFrame, "InputBoxTemplate")
+ box:Point("TOP", ColorPickerWheel, "BOTTOM", 0, -15)
+ box:SetFrameStrata("DIALOG")
+ box:SetAutoFocus(false)
+ box:SetTextInsets(0,7,0,0)
+ box:SetJustifyH("RIGHT")
+ box:Height(24)
+ box:SetID(i)
+ S:HandleEditBox(box)
+
+ -- hex entry box
+ if i == 4 then
+ box:SetMaxLetters(6)
+ box:Width(56)
+ box:SetNumeric(false)
+ else
+ box:SetMaxLetters(3)
+ box:Width(40)
+ box:SetNumeric(true)
+ end
+
+ -- label
+ local label = box:CreateFontString("ColorPPBoxLabel"..rgb, "ARTWORK", "GameFontNormalSmall")
+ label:Point("RIGHT", box, "LEFT", -5, 0)
+ label:SetText(i == 4 and "#" or rgb)
+ label:SetTextColor(1, 1, 1)
+
+ -- set up scripts to handle event appropriately
+ if i == 5 then
+ box:SetScript("OnEscapePressed", function(self) self:ClearFocus() UpdateAlphaText() end)
+ box:SetScript("OnEnterPressed", function(self) self:ClearFocus() UpdateAlphaText() end)
+ box:SetScript("OnTextChanged", UpdateAlpha)
+ else
+ box:SetScript("OnEscapePressed", function(self) self:ClearFocus() UpdateColorTexts() end)
+ box:SetScript("OnEnterPressed", function(self) self:ClearFocus() UpdateColorTexts() end)
+ box:SetScript("OnTextChanged", UpdateColor)
+ end
+
+ box:SetScript("OnEditFocusGained", function(eb) eb:SetCursorPosition(0) eb:HighlightText() end)
+ box:SetScript("OnEditFocusLost", function(eb) eb:HighlightText(0,0) end)
+ box:SetScript("OnTextSet", box.ClearFocus)
+ box:Show()
+ end
+
+ -- finish up with placement
+ ColorPPBoxA:Point("RIGHT", OpacitySliderFrame, "RIGHT", 10, 0)
+ ColorPPBoxH:Point("RIGHT", ColorPPDefault, "RIGHT", -10, 0)
+ ColorPPBoxB:Point("RIGHT", ColorPPDefault, "LEFT", -40, 0)
+ ColorPPBoxG:Point("RIGHT", ColorPPBoxB, "LEFT", -25, 0)
+ ColorPPBoxR:Point("RIGHT", ColorPPBoxG, "LEFT", -25, 0)
+
+ -- define the order of tab cursor movement
+ ColorPPBoxR:SetScript("OnTabPressed", function() ColorPPBoxG:SetFocus() end)
+ ColorPPBoxG:SetScript("OnTabPressed", function() ColorPPBoxB:SetFocus() end)
+ ColorPPBoxB:SetScript("OnTabPressed", function() ColorPPBoxH:SetFocus() end)
+ ColorPPBoxA:SetScript("OnTabPressed", function() ColorPPBoxR:SetFocus() end)
+
+ -- make the color picker movable.
+ local mover = CreateFrame("Frame", nil, ColorPickerFrame)
+ mover:Point("TOPLEFT", ColorPickerFrame, "TOP", -60, 0)
+ mover:Point("BOTTOMRIGHT", ColorPickerFrame, "TOP", 60, -15)
+ mover:SetScript("OnMouseDown", function() ColorPickerFrame:StartMoving() end)
+ mover:SetScript("OnMouseUp", function() ColorPickerFrame:StopMovingOrSizing() end)
+ mover:EnableMouse(true)
+
+ ColorPickerFrame:SetUserPlaced(true)
+ ColorPickerFrame:EnableKeyboard(false)
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Blizzard/Durability.lua b/ElvUI/Modules/Blizzard/Durability.lua
new file mode 100644
index 0000000..a0879bd
--- /dev/null
+++ b/ElvUI/Modules/Blizzard/Durability.lua
@@ -0,0 +1,27 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales
+local B = E:GetModule("Blizzard")
+
+--Lua functions
+--WoW API / Variables
+
+function B:PositionDurabilityFrame()
+ DurabilityFrame:SetFrameStrata("HIGH")
+ DurabilityFrame:SetScale(0.6)
+
+ DurabilityWeapon:Point("RIGHT", DurabilityWrists, "LEFT", 6, 0)
+ DurabilityShield:Point("LEFT", DurabilityWrists, "RIGHT", -6, 10)
+ DurabilityOffWeapon:Point("LEFT", DurabilityWrists, "RIGHT", -6, 0)
+ DurabilityRanged:Point("TOP", DurabilityShield, "BOTTOM", -1, 0)
+
+ hooksecurefunc(DurabilityFrame, "SetPoint", function(self, _, point)
+ if point ~= Minimap then
+ self:ClearAllPoints()
+
+ if DurabilityShield:IsShown() or DurabilityOffWeapon:IsShown() or DurabilityRanged:IsShown() then
+ self:Point("RIGHT", Minimap, "RIGHT", -7, 0)
+ else
+ self:Point("RIGHT", Minimap, "RIGHT", 8, 0)
+ end
+ end
+ end)
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Blizzard/GM.lua b/ElvUI/Modules/Blizzard/GM.lua
new file mode 100644
index 0000000..b82ddbb
--- /dev/null
+++ b/ElvUI/Modules/Blizzard/GM.lua
@@ -0,0 +1,12 @@
+local E, L = unpack(select(2, ...)); --Import: Engine, Locales
+local B = E:GetModule("Blizzard")
+
+--Lua functions
+--WoW API / Variables
+
+function B:PositionGMFrames()
+ TicketStatusFrame:ClearAllPoints()
+ TicketStatusFrame:SetPoint("TOPLEFT", E.UIParent, "TOPLEFT", 250, -5)
+
+ E:CreateMover(TicketStatusFrame, "GMMover", L["GM Ticket Frame"])
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Blizzard/Kill.lua b/ElvUI/Modules/Blizzard/Kill.lua
new file mode 100644
index 0000000..ff0eb4c
--- /dev/null
+++ b/ElvUI/Modules/Blizzard/Kill.lua
@@ -0,0 +1,10 @@
+local E, L = unpack(select(2, ...)); --Import: Engine, Locales
+local B = E:GetModule("Blizzard")
+
+--Lua functions
+--WoW API / Variables
+
+function B:KillBlizzard()
+ VideoOptionsResolutionPanelUseUIScale:Kill()
+ VideoOptionsResolutionPanelUIScaleSlider:Kill()
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Blizzard/Load_Blizzard.xml b/ElvUI/Modules/Blizzard/Load_Blizzard.xml
new file mode 100644
index 0000000..b874635
--- /dev/null
+++ b/ElvUI/Modules/Blizzard/Load_Blizzard.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/Blizzard/Vehicle.lua b/ElvUI/Modules/Blizzard/Vehicle.lua
new file mode 100644
index 0000000..4436b59
--- /dev/null
+++ b/ElvUI/Modules/Blizzard/Vehicle.lua
@@ -0,0 +1,50 @@
+local E, L = unpack(select(2, ...)); --Import: Engine, Locales
+local B = E:GetModule("Blizzard")
+
+--Lua functions
+local _G = _G
+--WoW API / Variables
+local GetVehicleUIIndicator = GetVehicleUIIndicator
+local GetVehicleUIIndicatorSeat = GetVehicleUIIndicatorSeat
+
+local function VehicleSeatIndicator_SetPosition(self, _, point)
+ if point ~= VehicleSeatMover then
+ self:ClearAllPoints()
+ self:Point("TOPLEFT", VehicleSeatMover, "TOPLEFT", 0, 0)
+ end
+end
+
+local function VehicleSetUp(vehicleID)
+ if vehicleID == 0 or vehicleID == VehicleSeatIndicator.currSkin then return end
+
+ local _, numSeatIndicators = GetVehicleUIIndicator(vehicleID)
+ local size = E.db.general.vehicleSeatIndicatorSize
+
+ VehicleSeatIndicator:Size(size)
+
+ for i = 1, numSeatIndicators do
+ local _, xOffset, yOffset = GetVehicleUIIndicatorSeat(vehicleID, i)
+ local button = _G["VehicleSeatIndicatorButton"..i]
+ button:Size(size / 4)
+ button:Point("CENTER", button:GetParent(), "TOPLEFT", xOffset * size, -yOffset * size)
+ end
+end
+
+function B:UpdateVehicleFrame()
+ if VehicleSeatIndicator.currSkin then
+ VehicleSetUp(VehicleSeatIndicator.currSkin)
+ end
+end
+
+function B:PositionVehicleFrame()
+ if not self.vehicleFrameHooked then
+ hooksecurefunc(VehicleSeatIndicator, "SetPoint", VehicleSeatIndicator_SetPosition)
+ hooksecurefunc("VehicleSeatIndicator_SetUpVehicle", VehicleSetUp)
+ E:CreateMover(VehicleSeatIndicator, "VehicleSeatMover", L["Vehicle Seat Frame"], nil, nil, nil, nil, nil, "general,blizzUIImprovements")
+ self.vehicleFrameHooked = true
+ end
+
+ VehicleSeatIndicator:Size(E.db.general.vehicleSeatIndicatorSize)
+
+ self:UpdateVehicleFrame()
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Blizzard/WatchFrame.lua b/ElvUI/Modules/Blizzard/WatchFrame.lua
new file mode 100644
index 0000000..47c1c0b
--- /dev/null
+++ b/ElvUI/Modules/Blizzard/WatchFrame.lua
@@ -0,0 +1,50 @@
+local E, L = unpack(select(2, ...)); --Import: Engine, Locales
+local B = E:GetModule("Blizzard")
+
+--Lua functions
+local min = math.min
+--WoW API / Variables
+local GetScreenHeight = GetScreenHeight
+
+local hideRule = "[@arena1,exists][@arena2,exists][@arena3,exists][@arena4,exists][@arena5,exists][@boss1,exists][@boss2,exists][@boss3,exists][@boss4,exists]"
+
+function B:SetObjectiveFrameAutoHide()
+ if E.db.general.watchFrameAutoHide then
+ RegisterStateDriver(WatchFrame, "visibility", hideRule)
+ else
+ UnregisterStateDriver(WatchFrame, "visibility")
+ end
+end
+
+function B:SetWatchFrameHeight()
+ local top = WatchFrame:GetTop() or 0
+ local screenHeight = GetScreenHeight()
+ local gapFromTop = screenHeight - top
+ local maxHeight = screenHeight - gapFromTop
+ local watchFrameHeight = min(maxHeight, E.db.general.watchFrameHeight)
+
+ WatchFrame:Height(watchFrameHeight)
+end
+
+function B:MoveWatchFrame()
+ local WatchFrameHolder = CreateFrame("Frame", "WatchFrameHolder", E.UIParent)
+ WatchFrameHolder:Size(207, 22)
+ WatchFrameHolder:Point("TOPRIGHT", E.UIParent, "TOPRIGHT", -135, -300)
+
+ E:CreateMover(WatchFrameHolder, "WatchFrameMover", L["Objective Frame"], nil, nil, nil, nil, nil, "general,objectiveFrameGroup")
+ WatchFrameHolder:SetAllPoints(WatchFrameMover)
+
+ WatchFrame:ClearAllPoints()
+ WatchFrame:SetPoint("TOP", WatchFrameHolder, "TOP")
+ B:SetWatchFrameHeight()
+ WatchFrame:SetClampedToScreen(false)
+
+ hooksecurefunc(WatchFrame, "SetPoint", function(_, _, parent)
+ if parent ~= WatchFrameHolder then
+ WatchFrame:ClearAllPoints()
+ WatchFrame:SetPoint("TOP", WatchFrameHolder, "TOP")
+ end
+ end)
+
+ self:SetObjectiveFrameAutoHide()
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Chat/Chat.lua b/ElvUI/Modules/Chat/Chat.lua
new file mode 100644
index 0000000..73c8e2f
--- /dev/null
+++ b/ElvUI/Modules/Chat/Chat.lua
@@ -0,0 +1,2033 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local CH = E:GetModule("Chat")
+local LO = E:GetModule("Layout")
+local Skins = E:GetModule("Skins")
+local LibBase64 = E.Libs.Base64
+local LSM = E.Libs.LSM
+
+--Lua functions
+local _G = _G
+local time = time
+local pairs, ipairs, unpack, select, tostring, pcall, next, tonumber, type = pairs, ipairs, unpack, select, tostring, pcall, next, tonumber, type
+local tinsert, tremove, tconcat, wipe = table.insert, table.remove, table.concat, table.wipe
+local gsub, find, gmatch, format, strtrim = string.gsub, string.find, string.gmatch, string.format, string.trim
+local strlower, strmatch, strsub, strlen, strupper = strlower, strmatch, strsub, strlen, strupper
+--WoW API / Variables
+local BetterDate = BetterDate
+local ChatEdit_ActivateChat = ChatEdit_ActivateChat
+local ChatEdit_ChooseBoxForSend = ChatEdit_ChooseBoxForSend
+local ChatEdit_ParseText = ChatEdit_ParseText
+local ChatEdit_SetLastTellTarget = ChatEdit_SetLastTellTarget
+local ChatFrame_ConfigEventHandler = ChatFrame_ConfigEventHandler
+local ChatFrame_GetMessageEventFilters = ChatFrame_GetMessageEventFilters
+local ChatFrame_SendTell = ChatFrame_SendTell
+local ChatFrame_SystemEventHandler = ChatFrame_SystemEventHandler
+local ChatHistory_GetAccessID = ChatHistory_GetAccessID
+local Chat_GetChatCategory = Chat_GetChatCategory
+local CreateFrame = CreateFrame
+local FCFManager_ShouldSuppressMessage = FCFManager_ShouldSuppressMessage
+local FCFTab_UpdateAlpha = FCFTab_UpdateAlpha
+local FCF_GetCurrentChatFrame = FCF_GetCurrentChatFrame
+local FCF_SavePositionAndDimensions = FCF_SavePositionAndDimensions
+local FCF_SetLocked = FCF_SetLocked
+local FCF_StartAlertFlash = FCF_StartAlertFlash
+local FloatingChatFrame_OnEvent = FloatingChatFrame_OnEvent
+local GMChatFrame_IsGM = GMChatFrame_IsGM
+local GetChannelName = GetChannelName
+local GetGuildRosterMOTD = GetGuildRosterMOTD
+local GetMouseFocus = GetMouseFocus
+local GetNumPartyMembers = GetNumPartyMembers
+local GetNumRaidMembers = GetNumRaidMembers
+local GetPlayerInfoByGUID = GetPlayerInfoByGUID
+local HasLFGRestrictions = HasLFGRestrictions
+local InCombatLockdown = InCombatLockdown
+local IsAltKeyDown = IsAltKeyDown
+local IsInInstance = IsInInstance
+local IsMouseButtonDown = IsMouseButtonDown
+local IsShiftKeyDown = IsShiftKeyDown
+local PlaySoundFile = PlaySoundFile
+local ScrollFrameTemplate_OnMouseWheel = ScrollFrameTemplate_OnMouseWheel
+local StaticPopup_Visible = StaticPopup_Visible
+local ToggleFrame = ToggleFrame
+local UnitIsSameServer = UnitIsSameServer
+local UnitName = UnitName
+local hooksecurefunc = hooksecurefunc
+
+local AFK = AFK
+local CHAT_BN_CONVERSATION_GET_LINK = CHAT_BN_CONVERSATION_GET_LINK
+local CHAT_FILTERED = CHAT_FILTERED
+local CHAT_FRAMES = CHAT_FRAMES
+local CHAT_IGNORED = CHAT_IGNORED
+local CHAT_OPTIONS = CHAT_OPTIONS
+local CHAT_RESTRICTED = CHAT_RESTRICTED
+local DEFAULT_CHAT_FRAME = DEFAULT_CHAT_FRAME
+local DND = DND
+local ICON_LIST = ICON_LIST
+local ICON_TAG_LIST = ICON_TAG_LIST
+local MAX_WOW_CHAT_CHANNELS = MAX_WOW_CHAT_CHANNELS
+local NUM_CHAT_WINDOWS = NUM_CHAT_WINDOWS
+local RAID_WARNING = RAID_WARNING
+
+local throttle = {}
+
+CH.ClassNames = {}
+CH.Keywords = {}
+CH.Smileys = {}
+
+local DEFAULT_STRINGS = {
+ BATTLEGROUND = L["BG"],
+ GUILD = L["G"],
+ PARTY = L["P"],
+ RAID = L["R"],
+ OFFICER = L["O"],
+ BATTLEGROUND_LEADER = L["BGL"],
+ PARTY_LEADER = L["PL"],
+ RAID_LEADER = L["RL"],
+}
+
+local hyperlinkTypes = {
+ ["item"] = true,
+ ["spell"] = true,
+ ["unit"] = true,
+ ["quest"] = true,
+ ["enchant"] = true,
+ ["achievement"] = true,
+ ["instancelock"] = true,
+ ["talent"] = true,
+ ["glyph"] = true,
+}
+
+local tabTexs = {
+ "",
+ "Selected",
+ "Highlight"
+}
+
+local historyTypes = { -- the events set on the chats are still in FindURL_Events, this is used to ignore some types only
+ CHAT_MSG_WHISPER = "WHISPER",
+ CHAT_MSG_WHISPER_INFORM = "WHISPER",
+ CHAT_MSG_BN_WHISPER = "WHISPER",
+ CHAT_MSG_BN_WHISPER_INFORM = "WHISPER",
+ CHAT_MSG_GUILD = "GUILD",
+ CHAT_MSG_GUILD_ACHIEVEMENT = "GUILD",
+ CHAT_MSG_OFFICER = "OFFICER",
+ CHAT_MSG_PARTY = "PARTY",
+ CHAT_MSG_PARTY_LEADER = "PARTY",
+ CHAT_MSG_RAID = "RAID",
+ CHAT_MSG_RAID_LEADER = "RAID",
+ CHAT_MSG_RAID_WARNING = "RAID",
+ CHAT_MSG_BATTLEGROUND = "BATTLEGROUND",
+ CHAT_MSG_BATTLEGROUND_LEADER = "BATTLEGROUND",
+ CHAT_MSG_CHANNEL = "CHANNEL",
+ CHAT_MSG_SAY = "SAY",
+ CHAT_MSG_YELL = "YELL",
+ CHAT_MSG_EMOTE = "EMOTE" -- this never worked, check it sometime.
+}
+
+function CH:RemoveSmiley(key)
+ if key and (type(key) == "string") then
+ CH.Smileys[key] = nil
+ end
+end
+
+function CH:AddSmiley(key, texture)
+ if key and (type(key) == "string" and not find(key, ":%%", 1, true)) and texture then
+ CH.Smileys[key] = texture
+ end
+end
+
+local specialChatIcons
+do --this can save some main file locals
+ local y = ":13:25"
+-- local ElvMelon = E:TextureString(E.Media.ChatLogos.ElvMelon,y)
+-- local ElvRainbow = E:TextureString(E.Media.ChatLogos.ElvRainbow,y)
+-- local ElvRed = E:TextureString(E.Media.ChatLogos.ElvRed,y)
+-- local ElvOrange = E:TextureString(E.Media.ChatLogos.ElvOrange,y)
+-- local ElvYellow = E:TextureString(E.Media.ChatLogos.ElvYellow,y)
+-- local ElvGreen = E:TextureString(E.Media.ChatLogos.ElvGreen,y)
+-- local ElvBlue = E:TextureString(E.Media.ChatLogos.ElvBlue,y)
+-- local ElvPurple = E:TextureString(E.Media.ChatLogos.ElvPurple,y)
+ local ElvPink = E:TextureString(E.Media.ChatLogos.ElvPink,y)
+
+ specialChatIcons = {
+ ["Крольчонак-x100"] = ElvPink,
+ }
+end
+
+local function ChatFrame_OnMouseScroll(frame, delta)
+ if delta < 0 then
+ if IsShiftKeyDown() then
+ frame:ScrollToBottom()
+ elseif IsAltKeyDown() then
+ frame:ScrollDown()
+ else
+ for _ = 1, (CH.db.numScrollMessages or 3) do
+ frame:ScrollDown()
+ end
+ end
+ elseif delta > 0 then
+ if IsShiftKeyDown() then
+ frame:ScrollToTop()
+ elseif IsAltKeyDown() then
+ frame:ScrollUp()
+ else
+ for _ = 1, (CH.db.numScrollMessages or 3) do
+ frame:ScrollUp()
+ end
+ end
+
+ if CH.db.scrollDownInterval ~= 0 then
+ if frame.ScrollTimer then
+ CH:CancelTimer(frame.ScrollTimer, true)
+ end
+
+ frame.ScrollTimer = CH:ScheduleTimer("ScrollToBottom", CH.db.scrollDownInterval, frame)
+ end
+ end
+end
+
+function CH:GetGroupDistribution()
+ local inInstance, kind = IsInInstance()
+ if inInstance and (kind == "pvp") then
+ return "/bg "
+ elseif GetNumRaidMembers() > 0 then
+ return "/ra "
+ elseif GetNumPartyMembers() > 0 then
+ return "/p "
+ else
+ return "/s "
+ end
+end
+
+function CH:InsertEmotions(msg)
+ for word in gmatch(msg, "%s-(%S+)%s*") do
+ local pattern = E:EscapeString(word)
+ local emoji = CH.Smileys[pattern]
+
+ if emoji then
+ pattern = format("%s%s%s", "([%s%p]-)", pattern, "([%s%p]*)")
+
+ if strmatch(msg, pattern) then
+ local base64 = LibBase64:Encode(word)
+
+ if base64 then
+ msg = gsub(msg, pattern, format("%s%s%s%s%s", "%1|Helvmoji:%%", base64, "|h|cFFffffff|r|h", emoji, "%2"))
+ else
+ msg = gsub(msg, pattern, format("%s%s%s", "%1", emoji, "%2"))
+ end
+ end
+ end
+ end
+
+ return msg
+end
+
+function CH:GetSmileyReplacementText(msg)
+ if not msg or not self.db.emotionIcons or find(msg, "/run") or find(msg, "/dump") or find(msg, "/script") then
+ return msg
+ end
+
+ local origlen = strlen(msg)
+ local startpos = 1
+ local outstr = ""
+ local _, pos, endpos
+
+ while startpos <= origlen do
+ pos = find(msg, "|H", startpos, true)
+ endpos = pos or origlen
+ outstr = outstr .. CH:InsertEmotions(strsub(msg, startpos, endpos)) --run replacement on this bit
+ startpos = endpos + 1
+
+ if pos then
+ _, endpos = find(msg, "|h.-|h", startpos)
+ endpos = endpos or origlen
+
+ if startpos < endpos then
+ outstr = outstr .. strsub(msg, startpos, endpos) --don't run replacement on this bit
+ startpos = endpos + 1
+ end
+ end
+ end
+
+ return outstr
+end
+
+function CH:StyleChat(frame)
+ local name = frame:GetName()
+ _G[name.."TabText"]:FontTemplate(LSM:Fetch("font", self.db.tabFont), self.db.tabFontSize, self.db.tabFontOutline)
+
+ if frame.styled then return end
+
+ frame:SetFrameLevel(4)
+ frame:SetClampRectInsets(0, 0, 0, 0)
+ frame:SetClampedToScreen(false)
+ frame:StripTextures(true)
+
+ _G[name.."ButtonFrame"]:Kill()
+
+ local id = frame:GetID()
+ local tab = _G[name.."Tab"]
+ local editbox = _G[name.."EditBox"]
+ local language = _G[name.."EditBoxLanguage"]
+
+ --Character count
+ local charCount = editbox:CreateFontString()
+ charCount:FontTemplate()
+ charCount:SetTextColor(190, 190, 190, 0.4)
+ charCount:Point("TOPRIGHT", editbox, "TOPRIGHT", -5, 0)
+ charCount:Point("BOTTOMRIGHT", editbox, "BOTTOMRIGHT", -5, 0)
+ charCount:SetJustifyH("CENTER")
+ charCount:Width(40)
+ editbox.characterCount = charCount
+
+ for _, texName in ipairs(tabTexs) do
+ _G[format("%sTab%sLeft", name, texName)]:SetTexture(nil)
+ _G[format("%sTab%sMiddle", name, texName)]:SetTexture(nil)
+ _G[format("%sTab%sRight", name, texName)]:SetTexture(nil)
+ end
+
+ tab:SetHitRectInsets(0, 0, 11, 1)
+
+ tab.glow:Point("BOTTOMLEFT", 8, 2)
+ tab.glow:Point("BOTTOMRIGHT", -8, 2)
+
+ hooksecurefunc(tab, "SetAlpha", function(t, alpha)
+ if alpha ~= 1 and (not t.isDocked or GeneralDockManager.selected:GetID() == t:GetID()) then
+ t:SetAlpha(1)
+ elseif alpha < 0.6 then
+ t:SetAlpha(0.6)
+ end
+ end)
+
+ tab.text = _G[name.."TabText"]
+
+ if tab.conversationIcon then
+ tab.text:Point("LEFT", tab.leftTexture, "RIGHT", 10, -5)
+
+ tab.conversationIcon:ClearAllPoints()
+ tab.conversationIcon:Point("RIGHT", tab.text, "LEFT", -1, 0)
+ end
+
+ local function OnTextChanged(editBox)
+ local text = editBox:GetText()
+ local len = strlen(text)
+ local MIN_REPEAT_CHARACTERS = CH.db.numAllowedCombatRepeat
+
+ if MIN_REPEAT_CHARACTERS ~= 0 and InCombatLockdown() then
+ if len > MIN_REPEAT_CHARACTERS then
+ local repeatChar = true
+ for i = 1, MIN_REPEAT_CHARACTERS do
+ if strsub(text, -i, -i) ~= strsub(text, (-1 - i), (-1 - i)) then
+ repeatChar = false
+ break
+ end
+ end
+ if repeatChar then
+ editBox:Hide()
+ return
+ end
+ end
+ end
+
+ if text == "/tt " then
+ local unitname, realm = UnitName("target")
+ if unitname and realm and not UnitIsSameServer("player", "target") then
+ unitname = format("%s-%s", unitname, gsub(realm, " ", ""))
+ end
+ if unitname then
+ ChatFrame_SendTell(unitname, editBox.chatFrame)
+ else
+ UIErrorsFrame:AddMessage(E.InfoColor..L["Invalid Target"])
+ end
+ elseif text == "/gr " then
+ editBox:SetText(CH:GetGroupDistribution()..strsub(text, 5))
+ ChatEdit_ParseText(editBox, 0)
+ end
+
+ editbox.characterCount:SetText(len > 0 and (255 - len) or "")
+ end
+
+ local a, b, c = select(6, editbox:GetRegions())
+ a:Kill()
+ b:Kill()
+ c:Kill()
+
+ _G[format("%sEditBoxFocusLeft", name)]:Kill()
+ _G[format("%sEditBoxFocusMid", name)]:Kill()
+ _G[format("%sEditBoxFocusRight", name)]:Kill()
+
+ editbox:SetTemplate(nil, true)
+ editbox:SetAltArrowKeyMode(CH.db.useAltKey)
+ editbox:SetAllPoints(LeftChatDataPanel)
+ editbox:Hide()
+
+ for _, text in ipairs(ElvCharacterDB.ChatEditHistory) do
+ editbox:AddHistoryLine(text)
+ end
+
+ editbox:HookScript("OnTextChanged", OnTextChanged)
+ self:SecureHook(editbox, "AddHistoryLine", "ChatEdit_AddHistory")
+
+ editbox:HookScript("OnEditFocusGained", function(editBox)
+ if not LeftChatPanel:IsShown() then
+ LeftChatPanel.editboxforced = true
+ LeftChatToggleButton:GetScript("OnEnter")(LeftChatToggleButton)
+ editBox:Show()
+ end
+ end)
+ editbox:HookScript("OnEditFocusLost", function(editBox)
+ if LeftChatPanel.editboxforced then
+ LeftChatPanel.editboxforced = nil
+ if LeftChatPanel:IsShown() then
+ LeftChatToggleButton:GetScript("OnLeave")(LeftChatToggleButton)
+ editBox:Hide()
+ end
+ end
+ end)
+
+ language:Height(22)
+ language:StripTextures()
+ language:SetTemplate("Transparent")
+ language:Point("LEFT", editbox, "RIGHT", -32, 0)
+
+ --copy chat button
+ local copyButton = CreateFrame("Frame", format("CopyChatButton%d", id), frame)
+ copyButton:EnableMouse(true)
+ copyButton:SetAlpha(0.35)
+ copyButton:Size(20, 22)
+ copyButton:Point("TOPRIGHT", 0, id == 2 and -7 or -2)
+ copyButton:SetFrameLevel(frame:GetFrameLevel() + 5)
+ frame.copyButton = copyButton
+
+ local copyTexture = frame.copyButton:CreateTexture(nil, "OVERLAY")
+ copyTexture:SetInside()
+ copyTexture:SetTexture(E.Media.Textures.Copy)
+ copyButton.texture = copyTexture
+
+ copyButton:SetScript("OnMouseUp", function(_, btn)
+ if btn == "RightButton" and id == 1 then
+ ToggleFrame(ChatMenu)
+ else
+ CH:CopyChat(frame)
+ end
+ end)
+
+ copyButton:SetScript("OnEnter", function(button) button:SetAlpha(1) end)
+ copyButton:SetScript("OnLeave", function(button)
+ if _G[button:GetParent():GetName().."TabText"]:IsShown() then
+ button:SetAlpha(0.35)
+ else
+ button:SetAlpha(0)
+ end
+ end)
+
+ frame.styled = true
+end
+
+function CH:AddMessage(msg, infoR, infoG, infoB, infoID, accessID, typeID, extraData, isHistory, historyTime)
+ if CH.db.timeStampFormat ~= "NONE" then
+ local timeStamp = BetterDate(CH.db.timeStampFormat, isHistory == "ElvUI_ChatHistory" and historyTime or time())
+
+ if CH.db.useCustomTimeColor then
+ local color = CH.db.customTimeColor
+ local hexColor = E:RGBToHex(color.r, color.g, color.b)
+ msg = format("%s[%s]|r %s", hexColor, timeStamp, msg)
+ else
+ msg = format("[%s] %s", timeStamp, msg)
+ end
+ end
+
+ self.OldAddMessage(self, msg, infoR, infoG, infoB, infoID, accessID, typeID, extraData)
+end
+
+function CH:UpdateSettings()
+ for _, frameName in ipairs(CHAT_FRAMES) do
+ _G[frameName.."EditBox"]:SetAltArrowKeyMode(CH.db.useAltKey)
+ end
+end
+
+local removeIconFromLine
+do
+ local raidIconFunc = function(x)
+ x = x ~= "" and _G["RAID_TARGET_"..x]
+ return x and ("{"..strlower(x).."}") or ""
+ end
+ local stripTextureFunc = function(w, x, y)
+ if x == "" then
+ return (w ~= "" and w) or (y ~= "" and y) or ""
+ end
+ end
+ local hyperLinkFunc = function(w, x, y)
+ if w ~= "" then return end
+ local emoji = (x ~= "" and x) and strmatch(x, "elvmoji:%%(.+)")
+ return (emoji and LibBase64:Decode(emoji)) or y
+ end
+ removeIconFromLine = function(text)
+ text = gsub(text, "|TInterface\\TargetingFrame\\UI%-RaidTargetingIcon_(%d+):0|t", raidIconFunc) --converts raid icons into {star} etc, if possible.
+ text = gsub(text, "(%s?)(|?)|T.-|t(%s?)", stripTextureFunc) --strip any other texture out but keep a single space from the side(s).
+ text = gsub(text, "(|?)|H(.-)|h(.-)|h", hyperLinkFunc) --strip hyperlink data only keeping the actual text.
+ return text
+ end
+end
+
+local function colorizeLine(text, r, g, b)
+ local hexCode = E:RGBToHex(r, g, b)
+ local hexReplacement = format("|r%s", hexCode)
+
+ text = gsub(text, "|r", hexReplacement) -- If the message contains color strings then we need to add message color hex code after every "|r"
+ text = format("%s%s|r", hexCode, text) -- Add message color
+
+ return text
+end
+
+local chatTypeIndexToName = {}
+local copyLines = {}
+
+for chatType in pairs(ChatTypeInfo) do
+ chatTypeIndexToName[GetChatTypeIndex(chatType)] = chatType
+end
+
+function CH:GetLines(frame)
+ local lineCount = 0
+ local _, message, lineID, info, r, g, b
+
+ for i = 1, frame:GetNumMessages() do
+ message, _, lineID = frame:GetMessageInfo(i)
+
+ if message then
+ info = ChatTypeInfo[chatTypeIndexToName[lineID]]
+
+ if info then
+ r, g, b = info.r, info.g, info.b
+ else
+ r, g, b = 1, 1, 1
+ end
+
+ message = removeIconFromLine(message)
+ message = colorizeLine(message, r, g, b)
+
+ lineCount = lineCount + 1
+ copyLines[lineCount] = message
+ end
+ end
+
+ return lineCount
+end
+
+function CH:CopyChat(frame)
+ if not self.copyChatFrame:IsShown() then
+ local lineCount = self:GetLines(frame)
+ local text = tconcat(copyLines, "\n", 1, lineCount)
+
+ self.copyChatFrame.editBox:SetText(text)
+ self.copyChatFrame:Show()
+ else
+ self.copyChatFrame:Hide()
+ end
+end
+
+function CH:OnEnter(frame)
+ _G[frame:GetName().."Text"]:Show()
+
+ if frame.conversationIcon then
+ frame.conversationIcon:Show()
+ end
+end
+
+function CH:OnLeave(frame)
+ _G[frame:GetName().."Text"]:Hide()
+
+ if frame.conversationIcon then
+ frame.conversationIcon:Hide()
+ end
+end
+
+function CH:SetupChatTabs(frame, hook)
+ if hook and (not self.hooks or not self.hooks[frame] or not self.hooks[frame].OnEnter) then
+ self:HookScript(frame, "OnEnter")
+ self:HookScript(frame, "OnLeave")
+ elseif not hook and self.hooks and self.hooks[frame] and self.hooks[frame].OnEnter then
+ self:Unhook(frame, "OnEnter")
+ self:Unhook(frame, "OnLeave")
+ end
+
+ if not hook then
+ _G[frame:GetName().."Text"]:Show()
+
+ if frame.owner and frame.owner.button and GetMouseFocus() ~= frame.owner.button then
+ frame.owner.button:SetAlpha(0.35)
+ end
+ if frame.conversationIcon then
+ frame.conversationIcon:Show()
+ end
+ elseif GetMouseFocus() ~= frame then
+ _G[frame:GetName().."Text"]:Hide()
+
+ if frame.owner and frame.owner.button and GetMouseFocus() ~= frame.owner.button then
+ frame.owner.button:SetAlpha(0)
+ end
+
+ if frame.conversationIcon then
+ frame.conversationIcon:Hide()
+ end
+ end
+end
+
+function CH:UpdateAnchors()
+ for _, frameName in ipairs(CHAT_FRAMES) do
+ local frame = _G[frameName.."EditBox"]
+
+ frame:ClearAllPoints()
+ if not E.db.datatexts.leftChatPanel and self.db.editBoxPosition == "BELOW_CHAT" then
+ frame:Point("TOPLEFT", ChatFrame1, "BOTTOMLEFT", -4, -4)
+ frame:Point("BOTTOMRIGHT", ChatFrame1, "BOTTOMRIGHT", 7, -LeftChatTab:GetHeight() - 4)
+ elseif self.db.editBoxPosition == "BELOW_CHAT" then
+ frame:SetAllPoints(LeftChatDataPanel)
+ else
+ frame:Point("BOTTOMLEFT", ChatFrame1, "TOPLEFT", -1, 3)
+ frame:Point("TOPRIGHT", ChatFrame1, "TOPRIGHT", 4, LeftChatTab:GetHeight() + 3)
+ end
+ end
+
+ CH:PositionChat(true)
+end
+
+local function FindRightChatID()
+ local rightChatID
+
+ for id, frameName in ipairs(CHAT_FRAMES) do
+ local chat = _G[frameName]
+
+ if E:FramesOverlap(chat, RightChatPanel) and not E:FramesOverlap(chat, LeftChatPanel) then
+ rightChatID = id
+ break
+ end
+ end
+
+ return rightChatID
+end
+
+function CH:UpdateChatTabs()
+ local fadeUndockedTabs = self.db.fadeUndockedTabs
+ local fadeTabsNoBackdrop = self.db.fadeTabsNoBackdrop
+
+ for id, frameName in ipairs(CHAT_FRAMES) do
+ local chat = _G[frameName]
+ local tab = _G[format("%sTab", frameName)]
+
+ if chat:IsShown() and (id <= NUM_CHAT_WINDOWS) and (id == self.RightChatWindowID) then
+ if self.db.panelBackdrop == "HIDEBOTH" or self.db.panelBackdrop == "LEFT" then
+ CH:SetupChatTabs(tab, fadeTabsNoBackdrop and true or false)
+ else
+ CH:SetupChatTabs(tab, false)
+ end
+ elseif not chat.isDocked and chat:IsShown() then
+ tab:SetParent(RightChatPanel)
+ chat:SetParent(RightChatPanel)
+ CH:SetupChatTabs(tab, fadeUndockedTabs and true or false)
+ else
+ if self.db.panelBackdrop == "HIDEBOTH" or self.db.panelBackdrop == "RIGHT" then
+ CH:SetupChatTabs(tab, fadeTabsNoBackdrop and true or false)
+ else
+ CH:SetupChatTabs(tab, false)
+ end
+ end
+ end
+end
+
+function CH:RefreshToggleButtons()
+ LeftChatToggleButton:SetAlpha(E.db.LeftChatPanelFaded and E.db.chat.fadeChatToggles and 0 or 1)
+ RightChatToggleButton:SetAlpha(E.db.RightChatPanelFaded and E.db.chat.fadeChatToggles and 0 or 1)
+end
+
+function CH:PositionChat(override)
+ if (InCombatLockdown() and not override and self.initialMove) or (IsMouseButtonDown("LeftButton") and not override) then return end
+ if not RightChatPanel or not LeftChatPanel then return end
+ if not self.db.lockPositions or not E.private.chat.enable then return end
+
+ RightChatPanel:Size(self.db.separateSizes and self.db.panelWidthRight or self.db.panelWidth, self.db.separateSizes and self.db.panelHeightRight or self.db.panelHeight)
+ LeftChatPanel:Size(self.db.panelWidth, self.db.panelHeight)
+
+ CombatLogQuickButtonFrame_Custom:Size(LeftChatTab:GetWidth(), LeftChatTab:GetHeight())
+
+ self.RightChatWindowID = FindRightChatID()
+
+ local fadeUndockedTabs = self.db.fadeUndockedTabs
+ local fadeTabsNoBackdrop = self.db.fadeTabsNoBackdrop
+
+ for id, frameName in ipairs(CHAT_FRAMES) do
+ local BASE_OFFSET = 57 + E.Spacing*3
+
+ local chat = _G[frameName]
+ local tab = _G[format("%sTab", frameName)]
+
+ tab.isDocked = chat.isDocked
+ tab.owner = chat
+
+ if chat:IsShown() and (id <= NUM_CHAT_WINDOWS) and id == self.RightChatWindowID then
+ chat:ClearAllPoints()
+
+ if E.db.datatexts.rightChatPanel then
+ chat:Point("BOTTOMLEFT", RightChatDataPanel, "TOPLEFT", 1, 4)
+ else
+ BASE_OFFSET = BASE_OFFSET - 24
+ chat:Point("BOTTOMLEFT", RightChatDataPanel, "BOTTOMLEFT", 1, 2)
+ end
+ if id ~= 2 then
+ chat:Size((self.db.separateSizes and self.db.panelWidthRight or self.db.panelWidth) - 11, (self.db.separateSizes and self.db.panelHeightRight or self.db.panelHeight) - BASE_OFFSET)
+ else
+ chat:Size(self.db.panelWidth - 11, (self.db.panelHeight - BASE_OFFSET) - CombatLogQuickButtonFrame_Custom:GetHeight())
+ end
+
+ --Pass a 2nd argument which prevents an infinite loop in our ON_FCF_SavePositionAndDimensions function
+ if chat:GetLeft() then
+ FCF_SavePositionAndDimensions(chat, true)
+ end
+
+ tab:SetParent(RightChatPanel)
+ chat:SetParent(RightChatPanel)
+
+ if chat:IsMovable() then
+ chat:SetUserPlaced(true)
+ end
+ if self.db.panelBackdrop == "HIDEBOTH" or self.db.panelBackdrop == "LEFT" then
+ CH:SetupChatTabs(tab, fadeTabsNoBackdrop and true or false)
+ else
+ CH:SetupChatTabs(tab, false)
+ end
+ elseif not chat.isDocked and chat:IsShown() then
+ tab:SetParent(UIParent)
+ chat:SetParent(UIParent)
+ CH:SetupChatTabs(tab, fadeUndockedTabs and true or false)
+ else
+ if id ~= 2 and (id <= NUM_CHAT_WINDOWS) then
+ chat:ClearAllPoints()
+ if E.db.datatexts.leftChatPanel then
+ chat:Point("BOTTOMLEFT", LeftChatToggleButton, "TOPLEFT", 1, 4)
+ else
+ BASE_OFFSET = BASE_OFFSET - 24
+ chat:Point("BOTTOMLEFT", LeftChatToggleButton, "BOTTOMLEFT", 1, 2)
+ end
+ chat:Size(self.db.panelWidth - 11, (self.db.panelHeight - BASE_OFFSET))
+
+ --Pass a 2nd argument which prevents an infinite loop in our ON_FCF_SavePositionAndDimensions function
+ if chat:GetLeft() then
+ FCF_SavePositionAndDimensions(chat, true)
+ end
+ end
+ chat:SetParent(LeftChatPanel)
+ if id > 2 then
+ tab:SetParent(GeneralDockManagerScrollFrameChild)
+ else
+ tab:SetParent(GeneralDockManager)
+ end
+ if chat:IsMovable() then
+ chat:SetUserPlaced(true)
+ end
+
+ if self.db.panelBackdrop == "HIDEBOTH" or self.db.panelBackdrop == "RIGHT" then
+ CH:SetupChatTabs(tab, fadeTabsNoBackdrop and true or false)
+ else
+ CH:SetupChatTabs(tab, false)
+ end
+ end
+ end
+
+ LO:RepositionChatDataPanels()
+
+ self.initialMove = true
+end
+
+function CH:Panels_ColorUpdate()
+ local panelColor = self.db.panelColor
+ LeftChatPanel.backdrop:SetBackdropColor(panelColor.r, panelColor.g, panelColor.b, panelColor.a)
+ RightChatPanel.backdrop:SetBackdropColor(panelColor.r, panelColor.g, panelColor.b, panelColor.a)
+end
+
+function CH:UpdateChatTabColors()
+ for _, frameName in ipairs(CHAT_FRAMES) do
+ local tab = _G[format("%sTab", frameName)]
+ CH:FCFTab_UpdateColors(tab, tab.selected)
+ end
+end
+E.valueColorUpdateFuncs[CH.UpdateChatTabColors] = true
+
+function CH:ScrollToBottom(frame)
+ frame:ScrollToBottom()
+
+ self:CancelTimer(frame.ScrollTimer, true)
+end
+
+function CH:PrintURL(url)
+ return "|cFFFFFFFF[|Hurl:"..url.."|h"..url.."|h]|r "
+end
+
+local tempURLs = {}
+local tempURLsCount = 0
+local function tempReplaceURL(url)
+ tempURLsCount = tempURLsCount + 1
+ local id = "|Hurl:"..tempURLsCount.."|h"
+ tempURLs[id] = CH:PrintURL(url)
+ return id
+end
+
+function CH:FindURL(event, msg, author, ...)
+ if not CH.db.url then
+ msg = CH:CheckKeyword(msg, author)
+ msg = CH:GetSmileyReplacementText(msg)
+ return false, msg, author, ...
+ end
+
+ local text, tag = msg, strmatch(msg, "{(.-)}")
+ if tag and ICON_TAG_LIST[strlower(tag)] then
+ text = gsub(gsub(text, "(%S)({.-})", "%1 %2"), "({.-})(%S)", "%1 %2")
+ end
+
+ local x, found = 0
+ local newMsg = gsub(gsub(text, "(%S)(|c.-|H.-|h.-|h|r)", "%1 %2"), "(|c.-|H.-|h.-|h|r)(%S)", "%1 %2")
+
+ -- https://example.com
+ newMsg, found = gsub(newMsg, "([A-z][A-z0-9+-%.]+://%S+)", tempReplaceURL)
+ x = x + found
+ -- www.example.com
+ newMsg, found = gsub(newMsg, "(www%.[A-z0-9-]+%.%S+)", tempReplaceURL)
+ x = x + found
+ -- example@example.com
+ newMsg, found = gsub(newMsg, "(%S+@[A-z][A-z0-9-]+%.[A-z0-9-]+)", tempReplaceURL)
+ x = x + found
+ -- 1.1.1.1[:1337]
+ newMsg, found = gsub(newMsg, "(%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?[:%d]*)", tempReplaceURL)
+ x = x + found
+
+ if x > 0 then
+ newMsg = gsub(newMsg, "(|Hurl:%d+|h)", tempURLs)
+ wipe(tempURLs)
+ tempURLsCount = 0
+
+ newMsg = CH:CheckKeyword(newMsg, author)
+ newMsg = CH:GetSmileyReplacementText(newMsg)
+ return false, newMsg, author, ...
+ end
+
+ msg = CH:CheckKeyword(msg, author)
+ msg = CH:GetSmileyReplacementText(msg)
+
+ return false, msg, author, ...
+end
+
+function CH:SetChatEditBoxMessage(message)
+ local ChatFrameEditBox = ChatEdit_ChooseBoxForSend()
+ local editBoxText = ChatFrameEditBox:GetText()
+
+ if not ChatFrameEditBox:IsShown() then
+ ChatEdit_ActivateChat(ChatFrameEditBox)
+ end
+
+ if editBoxText and editBoxText ~= "" then
+ ChatFrameEditBox:SetText("")
+ end
+
+ ChatFrameEditBox:Insert(message)
+ ChatFrameEditBox:HighlightText()
+end
+
+local function HyperLinkedURL(data)
+ if strsub(data, 1, 3) == "url" then
+ local currentLink = strsub(data, 5)
+ if currentLink and currentLink ~= "" then
+ CH:SetChatEditBoxMessage(currentLink)
+ end
+ end
+end
+
+local SetHyperlink = ItemRefTooltip.SetHyperlink
+function ItemRefTooltip:SetHyperlink(data, ...)
+ if strsub(data, 1, 3) == "url" then
+ HyperLinkedURL(data)
+ else
+ SetHyperlink(self, data, ...)
+ end
+end
+
+local hyperLinkEntered
+function CH:OnHyperlinkEnter(frame, refString)
+ if InCombatLockdown() then return end
+ local linkToken = strmatch(refString, "^([^:]+)")
+ if hyperlinkTypes[linkToken] then
+ GameTooltip:SetOwner(frame, "ANCHOR_CURSOR")
+ GameTooltip:SetHyperlink(refString)
+ GameTooltip:Show()
+ hyperLinkEntered = frame
+ end
+end
+
+function CH:OnHyperlinkLeave()
+ if hyperLinkEntered then
+ hyperLinkEntered = nil
+ GameTooltip:Hide()
+ end
+end
+
+function CH:OnMessageScrollChanged(frame)
+ if hyperLinkEntered == frame then
+ hyperLinkEntered = nil
+ GameTooltip:Hide()
+ end
+end
+
+function CH:ToggleHyperlink(enable)
+ for _, frameName in ipairs(CHAT_FRAMES) do
+ local frame = _G[frameName]
+ local hooked = self.hooks and self.hooks[frame] and self.hooks[frame].OnHyperlinkEnter
+ if enable and not hooked then
+ self:HookScript(frame, "OnHyperlinkEnter")
+ self:HookScript(frame, "OnHyperlinkLeave")
+ self:HookScript(frame, "OnMessageScrollChanged")
+ elseif not enable and hooked then
+ self:Unhook(frame, "OnHyperlinkEnter")
+ self:Unhook(frame, "OnHyperlinkLeave")
+ self:Unhook(frame, "OnMessageScrollChanged")
+ end
+ end
+end
+
+function CH:DisableChatThrottle()
+ wipe(throttle)
+end
+
+function CH:ShortChannel()
+ return format("|Hchannel:%s|h[%s]|h", self, DEFAULT_STRINGS[strupper(self)] or gsub(self, "channel:", ""))
+end
+
+function CH:HandleShortChannels(msg)
+ msg = gsub(msg, "|Hchannel:(.-)|h%[(.-)%]|h", self.ShortChannel)
+ msg = gsub(msg, "CHANNEL:", "")
+ msg = gsub(msg, "^(.-|h) "..L["whispers"], "%1")
+ msg = gsub(msg, "^(.-|h) "..L["says"], "%1")
+ msg = gsub(msg, "^(.-|h) "..L["yells"], "%1")
+ msg = gsub(msg, "<"..AFK..">", "[|cffFF0000"..AFK.."|r] ")
+ msg = gsub(msg, "<"..DND..">", "[|cffE7E716"..DND.."|r] ")
+ msg = gsub(msg, "^%["..RAID_WARNING.."%]", "["..L["RW"].."]")
+
+ return msg
+end
+
+local PluginIconsCalls = {}
+function CH:AddPluginIcons(func)
+ tinsert(PluginIconsCalls, func)
+end
+
+function CH:GetPluginIcon(sender, name, realm)
+ local icon
+ for _,func in ipairs(PluginIconsCalls) do
+ icon = func(sender, name, realm)
+ if icon and icon ~= "" then break end
+ end
+ return icon
+end
+
+function CH:GetColoredName(event, _, arg2, _, _, _, _, _, arg8, _, _, _, arg12)
+ local chatType = strsub(event, 10)
+ if strsub(chatType, 1, 7) == "WHISPER" then
+ chatType = "WHISPER"
+ elseif strsub(chatType, 1, 7) == "CHANNEL" then
+ chatType = "CHANNEL"..arg8
+ end
+
+ local info = ChatTypeInfo[chatType]
+ if info and info.colorNameByClass and arg12 ~= "" then
+ local _, englishClass = GetPlayerInfoByGUID(arg12)
+
+ if englishClass then
+ local classColorTable = E.media.herocolor
+ if not classColorTable then
+ return arg2
+ end
+ return format("\124cff%.2x%.2x%.2x", classColorTable.r*255, classColorTable.g*255, classColorTable.b*255)..arg2.."\124r"
+ end
+ end
+
+ return arg2
+end
+
+function CH:ChatFrame_MessageEventHandler(frame, event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, isHistory, historyTime, historyName)
+ if strsub(event, 1, 8) == "CHAT_MSG" then
+ local historySavedName --we need to extend the arguments on CH.ChatFrame_MessageEventHandler so we can properly handle saved names without overriding
+ if isHistory == "ElvUI_ChatHistory" then
+ historySavedName = historyName
+ end
+
+ local chatType = strsub(event, 10)
+ local info = ChatTypeInfo[chatType]
+
+ local chatFilters = ChatFrame_GetMessageEventFilters(event)
+ if chatFilters then
+ for _, filterFunc in next, chatFilters do
+ local filter, newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12 = filterFunc(frame, event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)
+ if filter then
+ return true
+ elseif newarg1 then
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 = newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12
+ end
+ end
+ end
+
+ local _, _, englishClass, _, _, _, name, realm = pcall(GetPlayerInfoByGUID, arg12)
+ local coloredName = historySavedName or CH:GetColoredName(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)
+
+ local nameWithRealm = strmatch(realm ~= "" and realm or E.myrealm, "%s*(%S+)$")
+ if name and name ~= "" then
+ nameWithRealm = name.."-"..nameWithRealm
+ CH.ClassNames[strlower(name)] = englishClass
+ CH.ClassNames[strlower(nameWithRealm)] = englishClass
+ end
+
+ local channelLength = strlen(arg4)
+ local infoType = chatType
+ if (strsub(chatType, 1, 7) == "CHANNEL") and (chatType ~= "CHANNEL_LIST") and ((arg1 ~= "INVITE") or (chatType ~= "CHANNEL_NOTICE_USER")) then
+ if arg1 == "WRONG_PASSWORD" then
+ local staticPopup = _G[StaticPopup_Visible("CHAT_CHANNEL_PASSWORD") or ""]
+ if staticPopup and strupper(staticPopup.data) == strupper(arg9) then
+ -- Don't display invalid password messages if we're going to prompt for a password (bug 102312)
+ return
+ end
+ end
+
+ local found = 0
+ for index, value in pairs(frame.channelList) do
+ if channelLength > strlen(value) then
+ -- arg9 is the channel name without the number in front...
+ if ((arg7 > 0) and (frame.zoneChannelList[index] == arg7)) or (strupper(value) == strupper(arg9)) then
+ found = 1
+ infoType = "CHANNEL"..arg8
+ info = ChatTypeInfo[infoType]
+ if (chatType == "CHANNEL_NOTICE") and (arg1 == "YOU_LEFT") then
+ frame.channelList[index] = nil
+ frame.zoneChannelList[index] = nil
+ end
+ break
+ end
+ end
+ end
+ if (found == 0) or not info then
+ return true
+ end
+ end
+
+ local chatGroup = Chat_GetChatCategory(chatType)
+ local chatTarget
+ if chatGroup == "CHANNEL" or chatGroup == "BN_CONVERSATION" then
+ chatTarget = tostring(arg8)
+ elseif chatGroup == "WHISPER" or chatGroup == "BN_WHISPER" then
+ chatTarget = strupper(arg2)
+ end
+
+ if FCFManager_ShouldSuppressMessage(frame, chatGroup, chatTarget) then
+ return true
+ end
+
+ if chatGroup == "WHISPER" or chatGroup == "BN_WHISPER" then
+ if frame.privateMessageList and not frame.privateMessageList[strlower(arg2)] then
+ return true
+ elseif frame.excludePrivateMessageList and frame.excludePrivateMessageList[strlower(arg2)] then
+ return true
+ end
+ elseif chatGroup == "BN_CONVERSATION" then
+ if frame.bnConversationList and not frame.bnConversationList[arg8] then
+ return true
+ elseif frame.excludeBNConversationList and frame.excludeBNConversationList[arg8] then
+ return true
+ end
+ end
+
+ if chatType == "SYSTEM" or chatType == "SKILL" or chatType == "LOOT" or chatType == "MONEY"
+ or chatType == "OPENING" or chatType == "TRADESKILLS" or chatType == "PET_INFO" or chatType == "TARGETICONS" then
+ frame:AddMessage(arg1, info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ elseif strsub(chatType,1,7) == "COMBAT_" then
+ frame:AddMessage(arg1, info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ elseif strsub(chatType,1,6) == "SPELL_" then
+ frame:AddMessage(arg1, info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ elseif strsub(chatType,1,10) == "BG_SYSTEM_" then
+ frame:AddMessage(arg1, info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ elseif strsub(chatType,1,11) == "ACHIEVEMENT" then
+ frame:AddMessage(format(arg1, "|Hplayer:"..arg2.."|h".."["..coloredName.."]".."|h"), info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ elseif strsub(chatType,1,18) == "GUILD_ACHIEVEMENT" then
+ frame:AddMessage(format(arg1, "|Hplayer:"..arg2.."|h".."["..coloredName.."]".."|h"), info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ elseif chatType == "IGNORED" then
+ frame:AddMessage(format(CHAT_IGNORED, arg2), info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ elseif chatType == "FILTERED" then
+ frame:AddMessage(format(CHAT_FILTERED, arg2), info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ elseif chatType == "RESTRICTED" then
+ frame:AddMessage(CHAT_RESTRICTED, info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ elseif chatType == "CHANNEL_LIST" then
+ if channelLength > 0 then
+ frame:AddMessage(format(_G["CHAT_"..chatType.."_GET"]..arg1, tonumber(arg8), arg4), info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ else
+ frame:AddMessage(arg1, info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ end
+ elseif chatType == "CHANNEL_NOTICE_USER" then
+ local globalstring = _G["CHAT_"..arg1.."_NOTICE_BN"]
+ if not globalstring then
+ globalstring = _G["CHAT_"..arg1.."_NOTICE"]
+ end
+
+ if arg5 ~= "" then
+ -- TWO users in this notice (E.G. x kicked y)
+ frame:AddMessage(format(globalstring, arg8, arg4, arg2, arg5), info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ elseif arg1 == "INVITE" then
+ frame:AddMessage(format(globalstring, arg4, arg2), info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ else
+ frame:AddMessage(format(globalstring, arg8, arg4, arg2), info.r, info.g, info.b, info.id, false, nil, nil, isHistory, historyTime)
+ end
+ elseif chatType == "CHANNEL_NOTICE" then
+ if arg1 == "NOT_IN_LFG" then return end
+ local globalstring = _G["CHAT_"..arg1.."_NOTICE_BN"]
+ if not globalstring then
+ globalstring = _G["CHAT_"..arg1.."_NOTICE"]
+ end
+ if arg10 > 0 then
+ arg4 = arg4.." "..arg10
+ end
+
+ local accessID = ChatHistory_GetAccessID(Chat_GetChatCategory(chatType), arg8)
+ local typeID = ChatHistory_GetAccessID(infoType, arg8)
+ frame:AddMessage(format(globalstring, arg8, arg4), info.r, info.g, info.b, info.id, false, accessID, typeID, isHistory, historyTime)
+ else
+ local body
+
+ -- Add AFK/DND flags
+ -- Player Flags
+ local pflag, chatIcon, pluginChatIcon = "", specialChatIcons[nameWithRealm], CH:GetPluginIcon(nameWithRealm, name, realm)
+ if type(chatIcon) == "function" then chatIcon = chatIcon() end
+ if arg6 ~= "" then
+ if arg6 == "GM" then
+ --If it was a whisper, dispatch it to the GMChat addon.
+ if chatType == "WHISPER" then
+ return
+ end
+ --Add Blizzard Icon, this was sent by a GM
+ pflag = "|TInterface\\ChatFrame\\UI-ChatIcon-Blizz.blp:0:2:0:-3|t "
+ elseif arg6 == "DEV" then
+ --Add Blizzard Icon, this was sent by a Dev
+ pflag = "|TInterface\\ChatFrame\\UI-ChatIcon-Blizz.blp:0:2:0:-3|t "
+ elseif arg6 == "DND" or arg6 == "AFK" then
+ pflag = (pflag or "").._G["CHAT_FLAG_"..arg6]
+ else
+ pflag = _G["CHAT_FLAG_"..arg6]
+ end
+ else
+ -- Special Chat Icon
+ if chatIcon then
+ pflag = pflag..chatIcon
+ end
+ -- Plugin Chat Icon
+ if pluginChatIcon then
+ pflag = pflag..pluginChatIcon
+ end
+ end
+
+ if chatType == "WHISPER_INFORM" and GMChatFrame_IsGM and GMChatFrame_IsGM(arg2) then
+ return
+ end
+
+ local showLink = 1
+ if strsub(chatType, 1, 7) == "MONSTER" or strsub(chatType, 1, 9) == "RAID_BOSS" then
+ showLink = nil
+ else
+ arg1 = gsub(arg1, "%%", "%%%%")
+ end
+
+ if chatType == "PARTY_LEADER" and HasLFGRestrictions() then
+ chatType = "PARTY_GUIDE"
+ end
+
+ -- Search for icon links and replace them with texture links.
+ local term
+ for tag in gmatch(arg1, "%b{}") do
+ term = strlower(gsub(tag, "[{}]", ""))
+ if ICON_TAG_LIST[term] and ICON_LIST[ICON_TAG_LIST[term]] then
+ arg1 = gsub(arg1, tag, ICON_LIST[ICON_TAG_LIST[term]].."0|t")
+ end
+ end
+
+ local playerLink
+
+ if chatType ~= "BN_WHISPER" and chatType ~= "BN_WHISPER_INFORM" and chatType ~= "BN_CONVERSATION" then
+ playerLink = "|Hplayer:"..arg2..":"..arg11..":"..chatGroup..(chatTarget and ":"..chatTarget or "").."|h"
+ else
+ playerLink = "|HBNplayer:"..arg2..":"..arg13..":"..arg11..":"..chatGroup..(chatTarget and ":"..chatTarget or "").."|h"
+ end
+
+ if arg3 ~= "" and arg3 ~= "Universal" and arg3 ~= frame.defaultLanguage then
+ local languageHeader = "["..arg3.."] "
+ if showLink and arg2 ~= "" then
+ body = format(_G["CHAT_"..chatType.."_GET"]..languageHeader..arg1, pflag..playerLink.."["..coloredName.."]".."|h")
+ else
+ body = format(_G["CHAT_"..chatType.."_GET"]..languageHeader..arg1, pflag..arg2)
+ end
+ else
+ if not showLink or strlen(arg2) == 0 then
+ body = format(_G["CHAT_"..chatType.."_GET"]..arg1, pflag..arg2, arg2)
+ else
+ if chatType == "EMOTE" then
+ body = format(_G["CHAT_"..chatType.."_GET"]..arg1, pflag..playerLink..coloredName.."|h")
+ elseif chatType == "TEXT_EMOTE" then
+ body = gsub(arg1, arg2, pflag..playerLink..coloredName.."|h", 1)
+ else
+ body = format(_G["CHAT_"..chatType.."_GET"]..arg1, pflag..playerLink.."["..coloredName.."]".."|h")
+ end
+ end
+ end
+
+ -- Add Channel
+ arg4 = gsub(arg4, "%s%-%s.*", "")
+ if chatGroup == "BN_CONVERSATION" then
+ body = format(CHAT_BN_CONVERSATION_GET_LINK, arg8, MAX_WOW_CHAT_CHANNELS + arg8)..body
+ elseif channelLength > 0 then
+ body = "|Hchannel:channel:"..arg8.."|h["..arg4.."]|h "..body
+ end
+
+ if CH.db.shortChannels and (chatType ~= "EMOTE" and chatType ~= "TEXT_EMOTE") then
+ body = CH:HandleShortChannels(body)
+ end
+
+ local accessID = ChatHistory_GetAccessID(chatGroup, chatTarget)
+ local typeID = ChatHistory_GetAccessID(infoType, chatTarget)
+
+ if not historySavedName and arg2 ~= E.myname and not CH.SoundTimer and (not CH.db.noAlertInCombat or not InCombatLockdown()) then
+ local channels = chatGroup ~= "WHISPER" and chatGroup or (chatType == "WHISPER" or chatType == "BN_WHISPER") and "WHISPER"
+ local alertType = CH.db.channelAlerts[channels]
+
+ if alertType and alertType ~= "None" then
+ PlaySoundFile(LSM:Fetch("sound", alertType), "Master")
+ CH.SoundTimer = E:Delay(1, CH.ThrottleSound)
+ end
+ end
+
+ frame:AddMessage(body, info.r, info.g, info.b, info.id, false, accessID, typeID, isHistory, historyTime)
+
+
+ if not historySavedName and (chatType == "WHISPER" or chatType == "BN_WHISPER") then
+ ChatEdit_SetLastTellTarget(arg2)
+ end
+ end
+
+ if not historySavedName and not frame:IsShown() then
+ if (frame == DEFAULT_CHAT_FRAME and info.flashTabOnGeneral) or (frame ~= DEFAULT_CHAT_FRAME and info.flashTab) then
+ if not CHAT_OPTIONS.HIDE_FRAME_ALERTS or chatType == "WHISPER" or chatType == "BN_WHISPER" then
+ FCF_StartAlertFlash(frame) --This would taint if we were not using LibChatAnims
+ end
+ end
+ end
+
+ return true
+ end
+end
+
+function CH:ChatFrame_ConfigEventHandler(...)
+ return ChatFrame_ConfigEventHandler(...)
+end
+
+function CH:ChatFrame_SystemEventHandler(...)
+ return ChatFrame_SystemEventHandler(...)
+end
+
+function CH:ChatFrame_OnEvent(...)
+ if CH:ChatFrame_ConfigEventHandler(...) then return end
+ if CH:ChatFrame_SystemEventHandler(...) then return end
+ if CH:ChatFrame_MessageEventHandler(...) then return end
+end
+
+function CH:FloatingChatFrame_OnEvent(...)
+ CH:ChatFrame_OnEvent(...)
+ FloatingChatFrame_OnEvent(...)
+end
+
+local function FloatingChatFrameOnEvent(...)
+ CH:FloatingChatFrame_OnEvent(...)
+end
+
+function CH:UpdateDockState()
+ if self.db.lockPositions then
+ FCF_SetLocked(ChatFrame1, 1)
+ GeneralDockManager:SetParent(LeftChatPanel)
+ GeneralDockManagerOverflowButton:ClearAllPoints()
+ GeneralDockManagerOverflowButton:Point("BOTTOMRIGHT", LeftChatTab, "BOTTOMRIGHT", -2, 2)
+ else
+ GeneralDockManager:SetParent(UIParent)
+ GeneralDockManagerOverflowButton:ClearAllPoints()
+ GeneralDockManagerOverflowButton:Point("BOTTOMRIGHT", GeneralDockManager, 0, -1)
+ end
+end
+
+function CH:SetupChat()
+ if not E.private.chat.enable then return end
+
+ for id, frameName in ipairs(CHAT_FRAMES) do
+ local frame = _G[frameName]
+
+ self:StyleChat(frame)
+ FCFTab_UpdateAlpha(frame)
+
+ local _, fontSize = frame:GetFont()
+ frame:FontTemplate(LSM:Fetch("font", self.db.font), fontSize, self.db.fontOutline)
+
+ if self.db.fontOutline ~= "NONE" then
+ frame:SetShadowColor(0, 0, 0, 0.2)
+ else
+ frame:SetShadowColor(0, 0, 0, 1)
+ end
+
+ if self.db.maxLines ~= frame:GetMaxLines() then
+ frame:SetMaxLines(self.db.maxLines)
+ end
+ frame:SetTimeVisible(self.db.inactivityTimer)
+ frame:SetShadowOffset(E.mult, -E.mult)
+ frame:SetFading(self.db.fade)
+
+ if id ~= 2 and not frame.OldAddMessage then
+ --Don't add timestamps to combat log, they don't work.
+ --This usually taints, but LibChatAnims should make sure it doesn't.
+ frame.OldAddMessage = frame.AddMessage
+ frame.AddMessage = CH.AddMessage
+ end
+
+ if not frame.scriptsSet then
+ frame:SetScript("OnMouseWheel", ChatFrame_OnMouseScroll)
+
+ if id ~= 2 then
+ frame:SetScript("OnEvent", FloatingChatFrameOnEvent)
+ end
+
+ hooksecurefunc(frame, "SetScript", function(f, script, func)
+ if script == "OnMouseWheel" and func ~= ChatFrame_OnMouseScroll then
+ f:SetScript(script, ChatFrame_OnMouseScroll)
+ end
+ end)
+ frame.scriptsSet = true
+ end
+ end
+
+ self:ToggleHyperlink(self.db.hyperlinkHover)
+
+ self:UpdateDockState()
+ self:PositionChat(true)
+
+ if not self.HookSecured then
+ self:SecureHook("FCF_OpenTemporaryWindow", "SetupChat")
+ self.HookSecured = true
+ end
+end
+
+local function PrepareMessage(author, message)
+ if author ~= "" and message ~= "" then
+ return format("%s%s", strupper(author), message)
+ end
+end
+
+function CH:ChatThrottleHandler(author, msg, when)
+ msg = PrepareMessage(author, msg)
+
+ if msg then
+ for message, msgTime in pairs(throttle) do
+ if (when - msgTime) >= self.db.throttleInterval then
+ throttle[message] = nil
+ end
+ end
+
+ if not throttle[msg] then
+ throttle[msg] = when
+ end
+ end
+end
+
+function CH:ChatThrottleBlockFlag(author, message, when)
+ if author ~= E.myname and self.db.throttleInterval ~= 0 then
+ message = PrepareMessage(author, message)
+ local msgTime = message and throttle[message]
+
+ if msgTime then
+ if (when - msgTime) > self.db.throttleInterval then
+ return false, message
+ end
+ else
+ return false
+ end
+ else
+ return false
+ end
+ return true
+end
+
+function CH:ChatThrottleIntervalHandler(event, message, author, ...)
+ local when = time()
+ local blockFlag, formattedMessage = self:ChatThrottleBlockFlag(author, message, when)
+
+ if blockFlag then
+ return true
+ else
+ if formattedMessage then
+ throttle[formattedMessage] = when
+ end
+ return self:FindURL(event, message, author, ...)
+ end
+end
+
+function CH:CHAT_MSG_CHANNEL(event, message, author, ...)
+ return CH:ChatThrottleIntervalHandler(event, message, author, ...)
+end
+
+function CH:CHAT_MSG_YELL(event, message, author, ...)
+ return CH:ChatThrottleIntervalHandler(event, message, author, ...)
+end
+
+function CH:CHAT_MSG_SAY(event, message, author, ...)
+ return CH:ChatThrottleIntervalHandler(event, message, author, ...)
+end
+
+function CH:ThrottleSound()
+ CH.SoundTimer = nil
+end
+
+local protectLinks = {}
+function CH:CheckKeyword(message, author)
+ local canPlaySound = author ~= E.myname and not self.SoundTimer and self.db.keywordSound ~= "None" and (not self.db.noAlertInCombat or not InCombatLockdown())
+
+ for hyperLink in gmatch(message, "|%x+|H.-|h.-|h|r") do
+ local tempLink = gsub(hyperLink, "%s", "|s")
+ message = gsub(message, E:EscapeString(hyperLink), tempLink)
+ protectLinks[hyperLink] = tempLink
+
+ if canPlaySound then
+ for keyword in pairs(CH.Keywords) do
+ if hyperLink == keyword then
+ PlaySoundFile(LSM:Fetch("sound", self.db.keywordSound), "Master")
+ self.SoundTimer = E:Delay(1, self.ThrottleSound)
+ canPlaySound = nil
+ break
+ end
+ end
+ end
+ end
+
+ local rebuiltString
+ local isFirstWord = true
+ local protectLinksNext = next(protectLinks)
+
+ for word in gmatch(message, "%s-%S+%s*") do
+ if not protectLinksNext or not protectLinks[gsub(gsub(word, "%s", ""), "|s", " ")] then
+ local tempWord = gsub(word, "[%s%p]", "")
+ local lowerCaseWord = strlower(tempWord)
+
+ for keyword in pairs(CH.Keywords) do
+ if lowerCaseWord == strlower(keyword) then
+ word = gsub(word, tempWord, format("%s%s|r", E.media.hexvaluecolor, tempWord))
+
+ if canPlaySound then
+ PlaySoundFile(LSM:Fetch("sound", self.db.keywordSound), "Master")
+ self.SoundTimer = E:Delay(1, self.ThrottleSound)
+ canPlaySound = nil
+ end
+ end
+ end
+
+ if self.db.classColorMentionsChat then
+ tempWord = gsub(word, "^[%s%p]-([^%s%p]+)([%-]?[^%s%p]-)[%s%p]*$", "%1%2")
+ lowerCaseWord = strlower(tempWord)
+
+ local classMatch = CH.ClassNames[lowerCaseWord]
+ local wordMatch = classMatch and lowerCaseWord
+
+ if wordMatch and not E.global.chat.classColorMentionExcludedNames[wordMatch] then
+ local classColorTable = E.media.herocolor
+ word = gsub(word, gsub(tempWord, "%-", "%%-"), format("\124cff%.2x%.2x%.2x%s\124r", classColorTable.r*255, classColorTable.g*255, classColorTable.b*255, tempWord))
+ end
+ end
+ end
+
+ if isFirstWord then
+ rebuiltString = word
+ isFirstWord = nil
+ else
+ rebuiltString = rebuiltString..word
+ end
+ end
+
+ for hyperLink, tempLink in pairs(protectLinks) do
+ rebuiltString = gsub(rebuiltString, E:EscapeString(tempLink), hyperLink)
+ protectLinks[hyperLink] = nil
+ end
+
+ return rebuiltString
+end
+
+function CH:AddLines(lines, ...)
+ for i = select("#", ...), 1, -1 do
+ local x = select(i, ...)
+ if x:IsObjectType("FontString") and not x:GetName() then
+ tinsert(lines, x:GetText())
+ end
+ end
+end
+
+function CH:ChatEdit_OnEnterPressed(editBox)
+ local chatType = editBox:GetAttribute("chatType")
+ local chatFrame = chatType and editBox:GetParent()
+ if chatFrame and (not chatFrame.isTemporary) and (ChatTypeInfo[chatType].sticky == 1) then
+ if not self.db.sticky then chatType = "SAY" end
+ editBox:SetAttribute("chatType", chatType)
+ end
+end
+
+function CH:SetChatFont(dropDown, chatFrame, fontSize)
+ if not chatFrame then
+ chatFrame = FCF_GetCurrentChatFrame()
+ end
+ if not fontSize then
+ fontSize = dropDown.value
+ end
+
+ chatFrame:FontTemplate(LSM:Fetch("font", self.db.font), fontSize, self.db.fontOutline)
+
+ if self.db.fontOutline ~= "NONE" then
+ chatFrame:SetShadowColor(0, 0, 0, 0.2)
+ else
+ chatFrame:SetShadowColor(0, 0, 0, 1)
+ end
+ chatFrame:SetShadowOffset(E.mult, -E.mult)
+end
+
+CH.SecureSlashCMD = {
+ "^/assist",
+ "^/camp",
+ "^/cancelaura",
+ "^/cancelform",
+ "^/cast",
+ "^/castsequence",
+ "^/equip",
+ "^/exit",
+ "^/logout",
+ "^/reload",
+ "^/rl",
+ "^/startattack",
+ "^/stopattack",
+ "^/tar",
+ "^/target",
+ "^/use"
+}
+
+function CH:ChatEdit_AddHistory(_, text)
+ text = strtrim(text)
+
+ if text ~= "" then
+ for _, command in ipairs(CH.SecureSlashCMD) do
+ if find(text, command) then
+ return
+ end
+ end
+
+ for i, historyText in ipairs(ElvCharacterDB.ChatEditHistory) do
+ if historyText == text then
+ tremove(ElvCharacterDB.ChatEditHistory, i)
+ break
+ end
+ end
+
+ tinsert(ElvCharacterDB.ChatEditHistory, text)
+
+ if #ElvCharacterDB.ChatEditHistory > CH.db.editboxHistorySize then
+ tremove(ElvCharacterDB.ChatEditHistory, 1)
+ end
+ end
+end
+
+function CH:UpdateChatKeywords()
+ wipe(CH.Keywords)
+
+ local keywords = self.db.keywords
+ keywords = gsub(keywords, ",%s", ",")
+
+ for stringValue in gmatch(keywords, "[^,]+") do
+ if stringValue ~= "" then
+ CH.Keywords[stringValue] = true
+ end
+ end
+end
+
+function CH:UpdateFading()
+ for _, frameName in ipairs(CHAT_FRAMES) do
+ local frame = _G[frameName]
+ frame:SetTimeVisible(self.db.inactivityTimer)
+ frame:SetFading(self.db.fade)
+ end
+end
+
+function CH:DisplayChatHistory()
+ local data = ElvCharacterDB.ChatHistoryLog
+ if not next(data) then return end
+
+ CH.SoundTimer = true
+ for _, frameName in ipairs(CHAT_FRAMES) do
+ for _, d in ipairs(data) do
+ if type(d) == "table" then
+ for _, messageType in ipairs(_G[frameName].messageTypeList) do
+ if (not historyTypes[d[50]] or self.db.showHistory[historyTypes[d[50]]]) and gsub(strsub(d[50], 10), "_INFORM", "") == messageType then
+ self:ChatFrame_MessageEventHandler(_G[frameName],d[50],d[1],d[2],d[3],d[4],d[5],d[6],d[7],d[8],d[9],d[10],d[11],d[12],0,"ElvUI_ChatHistory",d[51],d[52])
+ end
+ end
+ end
+ end
+ end
+ CH.SoundTimer = nil
+end
+
+tremove(ChatTypeGroup.GUILD, 2)
+function CH:DelayGuildMOTD()
+ tinsert(ChatTypeGroup.GUILD, 2, "GUILD_MOTD")
+
+ local registerGuildEvents = function(msg)
+ for _, frameName in ipairs(CHAT_FRAMES) do
+ local chat = _G[frameName]
+ if chat:IsEventRegistered("CHAT_MSG_GUILD") then
+ if msg then
+ CH:ChatFrame_SystemEventHandler(chat, "GUILD_MOTD", msg)
+ end
+ chat:RegisterEvent("GUILD_MOTD")
+ end
+ end
+ end
+
+ if not IsInGuild() then
+ registerGuildEvents()
+ return
+ end
+
+ local delay, checks = 0, 0
+ CreateFrame("Frame"):SetScript("OnUpdate", function(df, elapsed)
+ delay = delay + elapsed
+ if delay < 5 then return end
+
+ local msg = GetGuildRosterMOTD()
+
+ if msg and msg ~= "" then
+ registerGuildEvents(msg)
+ df:SetScript("OnUpdate", nil)
+ else -- 5 seconds can be too fast for the API response. let's try once every 5 seconds (max 5 checks).
+ delay, checks = 0, checks + 1
+ if checks >= 5 then
+ registerGuildEvents()
+ df:SetScript("OnUpdate", nil)
+ end
+ end
+ end)
+end
+
+function CH:SaveChatHistory(event, ...)
+ if historyTypes[event] and not self.db.showHistory[historyTypes[event]] then return end
+
+ if self.db.throttleInterval ~= 0 and (event == "CHAT_MSG_SAY" or event == "CHAT_MSG_YELL" or event == "CHAT_MSG_CHANNEL") then
+ local message, author = ...
+ local when = time()
+
+ if not self:ChatThrottleBlockFlag(author, message, when) then
+ self:ChatThrottleHandler(author, message, when)
+ else
+ return
+ end
+ end
+
+ if not CH.db.chatHistory then return end
+
+ if select("#", ...) > 0 then
+ local historyLog = ElvCharacterDB.ChatHistoryLog
+
+ local historyEntry = {...}
+ historyEntry[50] = event
+ historyEntry[51] = time()
+ historyEntry[52] = self:GetColoredName(event, ...)
+
+ while #historyLog >= self.db.historySize do
+ tremove(historyLog, 1)
+ end
+
+ tinsert(historyLog, historyEntry)
+ end
+end
+
+function CH:FCF_SetWindowAlpha(frame, alpha)
+ frame.oldAlpha = alpha or 1
+end
+
+function CH:ON_FCF_SavePositionAndDimensions(_, noLoop)
+ if not noLoop then
+ CH:PositionChat()
+ end
+
+ if not self.db.lockPositions then
+ CH:UpdateChatTabs() --It was not done in PositionChat, so do it now
+ end
+end
+
+local FindURL_Events = {
+ "CHAT_MSG_WHISPER",
+ "CHAT_MSG_WHISPER_INFORM",
+ "CHAT_MSG_BN_WHISPER",
+ "CHAT_MSG_BN_WHISPER_INFORM",
+ "CHAT_MSG_GUILD_ACHIEVEMENT",
+ "CHAT_MSG_GUILD",
+ "CHAT_MSG_OFFICER",
+ "CHAT_MSG_PARTY",
+ "CHAT_MSG_PARTY_LEADER",
+ "CHAT_MSG_RAID",
+ "CHAT_MSG_RAID_LEADER",
+ "CHAT_MSG_RAID_WARNING",
+ "CHAT_MSG_BATTLEGROUND",
+ "CHAT_MSG_BATTLEGROUND_LEADER",
+ "CHAT_MSG_CHANNEL",
+ "CHAT_MSG_SAY",
+ "CHAT_MSG_YELL",
+ "CHAT_MSG_EMOTE",
+ "CHAT_MSG_TEXT_EMOTE",
+ "CHAT_MSG_AFK",
+ "CHAT_MSG_DND",
+}
+
+function CH:DefaultSmileys()
+ local x = ":16:16"
+ if next(CH.Smileys) then
+ wipe(CH.Smileys)
+ end
+
+ -- new keys
+ CH:AddSmiley(":angry:", E:TextureString(E.Media.ChatEmojis.Angry, x))
+ CH:AddSmiley(":blush:", E:TextureString(E.Media.ChatEmojis.Blush, x))
+ CH:AddSmiley(":broken_heart:", E:TextureString(E.Media.ChatEmojis.BrokenHeart, x))
+ CH:AddSmiley(":call_me:", E:TextureString(E.Media.ChatEmojis.CallMe, x))
+ CH:AddSmiley(":cry:", E:TextureString(E.Media.ChatEmojis.Cry, x))
+ CH:AddSmiley(":facepalm:", E:TextureString(E.Media.ChatEmojis.Facepalm, x))
+ CH:AddSmiley(":grin:", E:TextureString(E.Media.ChatEmojis.Grin, x))
+ CH:AddSmiley(":heart:", E:TextureString(E.Media.ChatEmojis.Heart, x))
+ CH:AddSmiley(":heart_eyes:", E:TextureString(E.Media.ChatEmojis.HeartEyes, x))
+ CH:AddSmiley(":joy:", E:TextureString(E.Media.ChatEmojis.Joy, x))
+ CH:AddSmiley(":kappa:", E:TextureString(E.Media.ChatEmojis.Kappa, x))
+ CH:AddSmiley(":middle_finger:", E:TextureString(E.Media.ChatEmojis.MiddleFinger, x))
+ CH:AddSmiley(":murloc:", E:TextureString(E.Media.ChatEmojis.Murloc, x))
+ CH:AddSmiley(":ok_hand:", E:TextureString(E.Media.ChatEmojis.OkHand, x))
+ CH:AddSmiley(":open_mouth:", E:TextureString(E.Media.ChatEmojis.OpenMouth, x))
+ CH:AddSmiley(":poop:", E:TextureString(E.Media.ChatEmojis.Poop, x))
+ CH:AddSmiley(":rage:", E:TextureString(E.Media.ChatEmojis.Rage, x))
+ CH:AddSmiley(":sadkitty:", E:TextureString(E.Media.ChatEmojis.SadKitty, x))
+ CH:AddSmiley(":scream:", E:TextureString(E.Media.ChatEmojis.Scream, x))
+ CH:AddSmiley(":scream_cat:", E:TextureString(E.Media.ChatEmojis.ScreamCat, x))
+ CH:AddSmiley(":slight_frown:", E:TextureString(E.Media.ChatEmojis.SlightFrown, x))
+ CH:AddSmiley(":smile:", E:TextureString(E.Media.ChatEmojis.Smile, x))
+ CH:AddSmiley(":smirk:", E:TextureString(E.Media.ChatEmojis.Smirk, x))
+ CH:AddSmiley(":sob:", E:TextureString(E.Media.ChatEmojis.Sob, x))
+ CH:AddSmiley(":sunglasses:", E:TextureString(E.Media.ChatEmojis.Sunglasses, x))
+ CH:AddSmiley(":thinking:", E:TextureString(E.Media.ChatEmojis.Thinking, x))
+ CH:AddSmiley(":thumbs_up:", E:TextureString(E.Media.ChatEmojis.ThumbsUp, x))
+ CH:AddSmiley(":semi_colon:", E:TextureString(E.Media.ChatEmojis.SemiColon, x))
+ CH:AddSmiley(":wink:", E:TextureString(E.Media.ChatEmojis.Wink, x))
+ CH:AddSmiley(":zzz:", E:TextureString(E.Media.ChatEmojis.ZZZ, x))
+ CH:AddSmiley(":stuck_out_tongue:", E:TextureString(E.Media.ChatEmojis.StuckOutTongue, x))
+ CH:AddSmiley(":stuck_out_tongue_closed_eyes:", E:TextureString(E.Media.ChatEmojis.StuckOutTongueClosedEyes, x))
+
+ -- Darth's keys
+ CH:AddSmiley(":meaw:", E:TextureString(E.Media.ChatEmojis.Meaw, x))
+
+ -- Simpy's keys
+ CH:AddSmiley(">:%(", E:TextureString(E.Media.ChatEmojis.Rage, x))
+ CH:AddSmiley(":%$", E:TextureString(E.Media.ChatEmojis.Blush, x))
+ CH:AddSmiley("<\\3", E:TextureString(E.Media.ChatEmojis.BrokenHeart, x))
+ CH:AddSmiley(":\'%)", E:TextureString(E.Media.ChatEmojis.Joy, x))
+ CH:AddSmiley(";\'%)", E:TextureString(E.Media.ChatEmojis.Joy, x))
+ CH:AddSmiley(",,!,,", E:TextureString(E.Media.ChatEmojis.MiddleFinger, x))
+ CH:AddSmiley("D:<", E:TextureString(E.Media.ChatEmojis.Rage, x))
+ CH:AddSmiley(":o3", E:TextureString(E.Media.ChatEmojis.ScreamCat, x))
+ CH:AddSmiley("XP", E:TextureString(E.Media.ChatEmojis.StuckOutTongueClosedEyes, x))
+ CH:AddSmiley("8%-%)", E:TextureString(E.Media.ChatEmojis.Sunglasses, x))
+ CH:AddSmiley("8%)", E:TextureString(E.Media.ChatEmojis.Sunglasses, x))
+ CH:AddSmiley(":%+1:", E:TextureString(E.Media.ChatEmojis.ThumbsUp, x))
+ CH:AddSmiley(":;:", E:TextureString(E.Media.ChatEmojis.SemiColon, x))
+ CH:AddSmiley(";o;", E:TextureString(E.Media.ChatEmojis.Sob, x))
+
+ -- old keys
+ CH:AddSmiley(":%-@", E:TextureString(E.Media.ChatEmojis.Angry, x))
+ CH:AddSmiley(":@", E:TextureString(E.Media.ChatEmojis.Angry, x))
+ CH:AddSmiley(":%-%)", E:TextureString(E.Media.ChatEmojis.Smile, x))
+ CH:AddSmiley(":%)", E:TextureString(E.Media.ChatEmojis.Smile, x))
+ CH:AddSmiley(":D", E:TextureString(E.Media.ChatEmojis.Grin, x))
+ CH:AddSmiley(":%-D", E:TextureString(E.Media.ChatEmojis.Grin, x))
+ CH:AddSmiley(";%-D", E:TextureString(E.Media.ChatEmojis.Grin, x))
+ CH:AddSmiley(";D", E:TextureString(E.Media.ChatEmojis.Grin, x))
+ CH:AddSmiley("=D", E:TextureString(E.Media.ChatEmojis.Grin, x))
+ CH:AddSmiley("xD", E:TextureString(E.Media.ChatEmojis.Grin, x))
+ CH:AddSmiley("XD", E:TextureString(E.Media.ChatEmojis.Grin, x))
+ CH:AddSmiley(":%-%(", E:TextureString(E.Media.ChatEmojis.SlightFrown, x))
+ CH:AddSmiley(":%(", E:TextureString(E.Media.ChatEmojis.SlightFrown, x))
+ CH:AddSmiley(":o", E:TextureString(E.Media.ChatEmojis.OpenMouth, x))
+ CH:AddSmiley(":%-o", E:TextureString(E.Media.ChatEmojis.OpenMouth, x))
+ CH:AddSmiley(":%-O", E:TextureString(E.Media.ChatEmojis.OpenMouth, x))
+ CH:AddSmiley(":O", E:TextureString(E.Media.ChatEmojis.OpenMouth, x))
+ CH:AddSmiley(":%-0", E:TextureString(E.Media.ChatEmojis.OpenMouth, x))
+ CH:AddSmiley(":P", E:TextureString(E.Media.ChatEmojis.StuckOutTongue, x))
+ CH:AddSmiley(":%-P", E:TextureString(E.Media.ChatEmojis.StuckOutTongue, x))
+ CH:AddSmiley(":p", E:TextureString(E.Media.ChatEmojis.StuckOutTongue, x))
+ CH:AddSmiley(":%-p", E:TextureString(E.Media.ChatEmojis.StuckOutTongue, x))
+ CH:AddSmiley("=P", E:TextureString(E.Media.ChatEmojis.StuckOutTongue, x))
+ CH:AddSmiley("=p", E:TextureString(E.Media.ChatEmojis.StuckOutTongue, x))
+ CH:AddSmiley(";%-p", E:TextureString(E.Media.ChatEmojis.StuckOutTongueClosedEyes, x))
+ CH:AddSmiley(";p", E:TextureString(E.Media.ChatEmojis.StuckOutTongueClosedEyes, x))
+ CH:AddSmiley(";P", E:TextureString(E.Media.ChatEmojis.StuckOutTongueClosedEyes, x))
+ CH:AddSmiley(";%-P", E:TextureString(E.Media.ChatEmojis.StuckOutTongueClosedEyes, x))
+ CH:AddSmiley(";%-%)", E:TextureString(E.Media.ChatEmojis.Wink, x))
+ CH:AddSmiley(";%)", E:TextureString(E.Media.ChatEmojis.Wink, x))
+ CH:AddSmiley(":S", E:TextureString(E.Media.ChatEmojis.Smirk, x))
+ CH:AddSmiley(":%-S", E:TextureString(E.Media.ChatEmojis.Smirk, x))
+ CH:AddSmiley(":,%(", E:TextureString(E.Media.ChatEmojis.Cry, x))
+ CH:AddSmiley(":,%-%(", E:TextureString(E.Media.ChatEmojis.Cry, x))
+ CH:AddSmiley(":\'%(", E:TextureString(E.Media.ChatEmojis.Cry, x))
+ CH:AddSmiley(":\'%-%(", E:TextureString(E.Media.ChatEmojis.Cry, x))
+ CH:AddSmiley(":F", E:TextureString(E.Media.ChatEmojis.MiddleFinger, x))
+ CH:AddSmiley("<3", E:TextureString(E.Media.ChatEmojis.Heart, x))
+ CH:AddSmiley("3", E:TextureString(E.Media.ChatEmojis.BrokenHeart, x))
+end
+
+function CH:BuildCopyChatFrame()
+ local frame = CreateFrame("Frame", "CopyChatFrame", E.UIParent)
+ frame:Hide()
+ frame:SetTemplate("Transparent")
+ frame:Size(700, 200)
+ frame:Point("BOTTOM", E.UIParent, "BOTTOM", 0, 3)
+ frame:SetFrameStrata("DIALOG")
+ frame:EnableMouse(true)
+ frame:SetMovable(true)
+ frame:SetResizable(true)
+ frame:SetMinResize(350, 100)
+ tinsert(UISpecialFrames, "CopyChatFrame")
+ self.copyChatFrame = frame
+
+ local scrollFrame = CreateFrame("ScrollFrame", "$parentScrollFrame", frame, "UIPanelScrollFrameTemplate")
+ scrollFrame:Point("TOPLEFT", frame, "TOPLEFT", 8, -30)
+ scrollFrame:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -29, 8)
+ frame.scrollFrame = scrollFrame
+
+ scrollFrame.scrollBar = CopyChatFrameScrollFrameScrollBar
+ Skins:HandleScrollBar(scrollFrame.scrollBar)
+ scrollFrame.scrollBar:Point("TOPLEFT", scrollFrame, "TOPRIGHT", 3, -19)
+ scrollFrame.scrollBar:Point("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ local editBox = CreateFrame("EditBox", "$parentEditBox", frame)
+ editBox:Size(scrollFrame:GetWidth(), 200)
+ editBox:SetFontObject(ChatFontNormal)
+ editBox:SetAutoFocus(false)
+ editBox:SetMultiLine(true)
+ editBox:SetMaxLetters(99999)
+ scrollFrame:SetScrollChild(editBox)
+ frame.editBox = editBox
+
+ local closeButton = CreateFrame("Button", "$parentCloseButton", frame, "UIPanelCloseButton")
+ closeButton:Point("TOPRIGHT", -1, 1)
+ closeButton:SetFrameLevel(closeButton:GetFrameLevel() + 1)
+ Skins:HandleCloseButton(closeButton)
+ frame.closeButton = closeButton
+
+ frame:SetScript("OnMouseDown", function(f, button)
+ if button == "LeftButton" and not f.isMoving then
+ f:StartMoving()
+ f.isMoving = true
+ elseif button == "RightButton" and not f.isSizing then
+ f:StartSizing()
+ f.isSizing = true
+ end
+ end)
+ frame:SetScript("OnMouseUp", function(f, button)
+ if button == "LeftButton" and f.isMoving then
+ f:StopMovingOrSizing()
+ f.isMoving = nil
+ elseif button == "RightButton" and f.isSizing then
+ f:StopMovingOrSizing()
+ f.isSizing = nil
+ end
+ end)
+ frame:SetScript("OnHide", function(f)
+ if f.isMoving or f.isSizing then
+ f:StopMovingOrSizing()
+ f.isMoving = nil
+ f.isSizing = nil
+ end
+ end)
+
+ scrollFrame:SetScript("OnSizeChanged", function(f)
+ editBox:Size(f:GetSize())
+ end)
+ scrollFrame:HookScript("OnVerticalScroll", function(f, offset)
+ editBox:SetHitRectInsets(0, 0, offset, (editBox:GetHeight() - offset - f:GetHeight()))
+ end)
+
+ editBox:SetScript("OnTextChanged", function(_, userInput)
+ if userInput then return end
+
+ local _, max = scrollFrame.scrollBar:GetMinMaxValues()
+ for _ = 1, max do
+ ScrollFrameTemplate_OnMouseWheel(scrollFrame, -1)
+ end
+ end)
+ editBox:SetScript("OnEscapePressed", function()
+ frame:Hide()
+ end)
+end
+
+CH.TabStyles = {
+ NONE = "%s",
+ ARROW = "%s>|r%s%s<|r",
+ ARROW1 = "%s>|r %s %s<|r",
+ ARROW2 = "%s<|r%s%s>|r",
+ ARROW3 = "%s<|r %s %s>|r",
+ BOX = "%s[|r%s%s]|r",
+ BOX1 = "%s[|r %s %s]|r",
+ CURLY = "%s{|r%s%s}|r",
+ CURLY1 = "%s{|r %s %s}|r",
+ CURVE = "%s(|r%s%s)|r",
+ CURVE1 = "%s(|r %s %s)|r"
+}
+
+function CH:FCFTab_UpdateColors(tab, selected)
+ local chat = _G[format("ChatFrame%s", tab:GetID())]
+
+ tab.selected = selected
+
+ if selected and chat.isDocked then
+ if self.db.tabSelector ~= "NONE" then
+ local color = self.db.tabSelectorColor
+ local hexColor = E:RGBToHex(color.r, color.g, color.b)
+ tab:SetFormattedText(self.TabStyles[self.db.tabSelector] or self.TabStyles.ARROW1, hexColor, chat.name, hexColor)
+ tab.textReformatted = true
+ elseif tab.textReformatted then
+ tab:SetText(chat.name)
+ tab.textReformatted = nil
+ end
+
+ if self.db.tabSelectedTextEnabled then
+ local color = self.db.tabSelectedTextColor
+ tab:GetFontString():SetTextColor(color.r, color.g, color.b)
+ return
+ end
+ elseif tab.textReformatted then
+ tab:SetText(chat.name)
+ tab.textReformatted = nil
+ end
+
+ tab:GetFontString():SetTextColor(unpack(E.media.rgbvaluecolor))
+end
+
+function CH:ResetEditboxHistory()
+ wipe(ElvCharacterDB.ChatEditHistory)
+end
+
+function CH:ResetHistory()
+ wipe(ElvCharacterDB.ChatHistoryLog)
+end
+
+function CH:Initialize()
+ self:DelayGuildMOTD() --Keep this before `is Chat Enabled` check
+
+ if not E.private.chat.enable then return end
+
+ self.Initialized = true
+ self.db = E.db.chat
+
+ if not ElvCharacterDB.ChatEditHistory then ElvCharacterDB.ChatEditHistory = {} end
+ if not ElvCharacterDB.ChatHistoryLog or not self.db.chatHistory then ElvCharacterDB.ChatHistoryLog = {} end
+
+ FriendsMicroButton:Kill()
+ ChatFrameMenuButton:Kill()
+
+ self:SetupChat()
+ self:DefaultSmileys()
+ self:UpdateChatKeywords()
+ self:UpdateFading()
+ self:UpdateAnchors()
+ self:Panels_ColorUpdate()
+
+ self:SecureHook("ChatEdit_OnEnterPressed")
+ self:SecureHook("FCF_SetWindowAlpha")
+ self:SecureHook("FCFTab_UpdateColors")
+ self:SecureHook("FCF_SetChatWindowFontSize", "SetChatFont")
+ self:SecureHook("FCF_SavePositionAndDimensions", "ON_FCF_SavePositionAndDimensions")
+ self:RegisterEvent("UPDATE_CHAT_WINDOWS", "SetupChat")
+ self:RegisterEvent("UPDATE_FLOATING_CHAT_WINDOWS", "SetupChat")
+
+ if WIM then
+ WIM.RegisterWidgetTrigger("chat_display", "whisper,chat,w2w,demo", "OnHyperlinkClick", function(self) CH.clickedframe = self end)
+ WIM.RegisterItemRefHandler("url", HyperLinkedURL)
+ end
+
+ if not self.db.lockPositions then CH:UpdateChatTabs() end --It was not done in PositionChat, so do it now
+
+ for _, event in ipairs(FindURL_Events) do
+ ChatFrame_AddMessageEventFilter(event, CH[event] or CH.FindURL)
+ local nType = strsub(event, 10)
+ if nType ~= "AFK" and nType ~= "DND" then
+ self:RegisterEvent(event, "SaveChatHistory")
+ end
+ end
+
+ if self.db.chatHistory then self:DisplayChatHistory() end
+ self:BuildCopyChatFrame()
+
+ -- Editbox Backdrop Color
+ hooksecurefunc("ChatEdit_UpdateHeader", function(editbox)
+ local chatType = editbox:GetAttribute("chatType")
+ if not chatType then return end
+
+ local chanTarget = editbox:GetAttribute("channelTarget")
+ local chanName = chanTarget and GetChannelName(chanTarget)
+
+ --Increase inset on right side to make room for character count text
+ local insetLeft, insetRight, insetTop, insetBottom = editbox:GetTextInsets()
+ editbox:SetTextInsets(insetLeft, insetRight + 30, insetTop, insetBottom)
+
+ if chanName and (chatType == "CHANNEL") then
+ if chanName == 0 then
+ editbox:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ else
+ local info = ChatTypeInfo[chatType..chanName]
+ editbox:SetBackdropBorderColor(info.r, info.g, info.b)
+ end
+ else
+ local info = ChatTypeInfo[chatType]
+ editbox:SetBackdropBorderColor(info.r, info.g, info.b)
+ end
+ end)
+
+ GeneralDockManagerOverflowButton:Size(17)
+ GeneralDockManagerOverflowButtonList:SetTemplate("Transparent")
+ hooksecurefunc(GeneralDockManagerScrollFrame, "SetPoint", function(self, point, anchor, attachTo, x, y)
+ if anchor == GeneralDockManagerOverflowButton and x == 0 and y == 0 then
+ self:Point(point, anchor, attachTo, -2, -4)
+ end
+ end)
+
+ CombatLogQuickButtonFrame_Custom:StripTextures()
+ CombatLogQuickButtonFrame_Custom:CreateBackdrop("Default", true)
+ CombatLogQuickButtonFrame_Custom.backdrop:Point("TOPLEFT", 0, -1)
+ CombatLogQuickButtonFrame_Custom.backdrop:Point("BOTTOMRIGHT", -22, -1)
+
+ CombatLogQuickButtonFrame_CustomProgressBar:StripTextures()
+ CombatLogQuickButtonFrame_CustomProgressBar:SetStatusBarTexture(E.media.normTex)
+ CombatLogQuickButtonFrame_CustomProgressBar:SetStatusBarColor(0.31, 0.31, 0.31)
+ CombatLogQuickButtonFrame_CustomProgressBar:ClearAllPoints()
+ CombatLogQuickButtonFrame_CustomProgressBar:SetInside(CombatLogQuickButtonFrame_Custom.backdrop)
+
+ Skins:HandleNextPrevButton(CombatLogQuickButtonFrame_CustomAdditionalFilterButton)
+ CombatLogQuickButtonFrame_CustomAdditionalFilterButton:Size(22)
+ CombatLogQuickButtonFrame_CustomAdditionalFilterButton:Point("TOPRIGHT", CombatLogQuickButtonFrame_Custom, "TOPRIGHT", 3, -1)
+ CombatLogQuickButtonFrame_CustomAdditionalFilterButton:SetHitRectInsets(0, 0, 0, 0)
+end
+
+local function InitializeCallback()
+ CH:Initialize()
+end
+
+E:RegisterModule(CH:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Chat/Load_Chat.xml b/ElvUI/Modules/Chat/Load_Chat.xml
new file mode 100644
index 0000000..2a357f4
--- /dev/null
+++ b/ElvUI/Modules/Chat/Load_Chat.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/DataBars/DataBars.lua b/ElvUI/Modules/DataBars/DataBars.lua
new file mode 100644
index 0000000..f9149ef
--- /dev/null
+++ b/ElvUI/Modules/DataBars/DataBars.lua
@@ -0,0 +1,63 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local mod = E:GetModule("DataBars")
+
+--Lua functions
+--WoW API / Variables
+local GetExpansionLevel = GetExpansionLevel
+local MAX_PLAYER_LEVEL_TABLE = MAX_PLAYER_LEVEL_TABLE
+
+function mod:OnLeave()
+ if (self == ElvUI_ExperienceBar and mod.db.experience.mouseover) or (self == ElvUI_ReputationBar and mod.db.reputation.mouseover) then
+ E:UIFrameFadeOut(self, 1, self:GetAlpha(), 0)
+ end
+ GameTooltip:Hide()
+end
+
+function mod:CreateBar(name, onEnter, onClick, ...)
+ local bar = CreateFrame("Button", name, E.UIParent)
+ bar:Point(...)
+ bar:SetScript("OnEnter", onEnter)
+ bar:SetScript("OnLeave", mod.OnLeave)
+ bar:SetScript("OnClick", onClick)
+ bar:SetFrameStrata("LOW")
+ bar:SetTemplate("Transparent")
+ bar:Hide()
+
+ bar.statusBar = CreateFrame("StatusBar", nil, bar)
+ bar.statusBar:SetInside()
+ bar.statusBar:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(bar.statusBar)
+ bar.text = bar.statusBar:CreateFontString(nil, "OVERLAY")
+ bar.text:FontTemplate()
+ bar.text:Point("CENTER")
+
+ return bar
+end
+
+function mod:UpdateDataBarDimensions()
+ self:UpdateExperienceDimensions()
+ self:UpdateReputationDimensions()
+end
+
+function mod:PLAYER_LEVEL_UP(level)
+ local maxLevel = MAX_PLAYER_LEVEL_TABLE[GetExpansionLevel()]
+ if (level ~= maxLevel or not self.db.experience.hideAtMaxLevel) and self.db.experience.enable then
+ self:UpdateExperience("PLAYER_LEVEL_UP", level)
+ else
+ self.expBar:Hide()
+ end
+end
+
+function mod:Initialize()
+ self.db = E.db.databars
+
+ self:LoadExperienceBar()
+ self:LoadReputationBar()
+ self:RegisterEvent("PLAYER_LEVEL_UP")
+end
+
+local function InitializeCallback()
+ mod:Initialize()
+end
+
+E:RegisterModule(mod:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataBars/Experience.lua b/ElvUI/Modules/DataBars/Experience.lua
new file mode 100644
index 0000000..abc93dd
--- /dev/null
+++ b/ElvUI/Modules/DataBars/Experience.lua
@@ -0,0 +1,182 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local mod = E:GetModule("DataBars")
+local LSM = LibStub("LibSharedMedia-3.0")
+
+--Lua functions
+local min = math.min
+local format = string.format
+--WoW API / Variables
+local GetExpansionLevel = GetExpansionLevel
+local GetPetExperience = GetPetExperience
+local GetXPExhaustion = GetXPExhaustion
+local InCombatLockdown = InCombatLockdown
+local IsXPUserDisabled = IsXPUserDisabled
+local UnitLevel = UnitLevel
+local UnitXP = UnitXP
+local UnitXPMax = UnitXPMax
+local MAX_PLAYER_LEVEL_TABLE = MAX_PLAYER_LEVEL_TABLE
+
+function mod:GetXP(unit)
+ if unit == "pet" then
+ return GetPetExperience()
+ else
+ return UnitXP(unit), UnitXPMax(unit)
+ end
+end
+
+function mod:UpdateExperience(event)
+ if not mod.db.experience.enable then return end
+
+ local bar = self.expBar
+ local hideXP = ((UnitLevel("player") == MAX_PLAYER_LEVEL_TABLE[GetExpansionLevel()] and self.db.experience.hideAtMaxLevel) or IsXPUserDisabled())
+
+ if hideXP or (event == "PLAYER_REGEN_DISABLED" and self.db.experience.hideInCombat) then
+ E:DisableMover(self.expBar.mover:GetName())
+ bar:Hide()
+ elseif not hideXP and (not self.db.experience.hideInCombat or not InCombatLockdown()) then
+ E:EnableMover(self.expBar.mover:GetName())
+ bar:Show()
+
+ if self.db.experience.hideInVehicle then
+ E:RegisterObjectForVehicleLock(bar, E.UIParent)
+ else
+ E:UnregisterObjectForVehicleLock(bar)
+ end
+
+ local cur, max = self:GetXP("player")
+ if max <= 0 then max = 1 end
+ bar.statusBar:SetMinMaxValues(0, max)
+ bar.statusBar:SetValue(cur - 1 >= 0 and cur - 1 or 0)
+ bar.statusBar:SetValue(cur)
+
+ local rested = GetXPExhaustion()
+ local text = ""
+ local textFormat = self.db.experience.textFormat
+
+ if rested and rested > 0 then
+ bar.rested:SetMinMaxValues(0, max)
+ bar.rested:SetValue(min(cur + rested, max))
+
+ if textFormat == "PERCENT" then
+ text = format("%d%% R:%d%%", cur / max * 100, rested / max * 100)
+ elseif textFormat == "CURMAX" then
+ text = format("%s - %s R:%s", E:ShortValue(cur), E:ShortValue(max), E:ShortValue(rested))
+ elseif textFormat == "CURPERC" then
+ text = format("%s - %d%% R:%s [%d%%]", E:ShortValue(cur), cur / max * 100, E:ShortValue(rested), rested / max * 100)
+ elseif textFormat == "CUR" then
+ text = format("%s R:%s", E:ShortValue(cur), E:ShortValue(rested))
+ elseif textFormat == "REM" then
+ text = format("%s R:%s", E:ShortValue(max - cur), E:ShortValue(rested))
+ elseif textFormat == "CURREM" then
+ text = format("%s - %s R:%s", E:ShortValue(cur), E:ShortValue(max - cur), E:ShortValue(rested))
+ elseif textFormat == "CURPERCREM" then
+ text = format("%s - %d%% (%s) R:%s", E:ShortValue(cur), cur / max * 100, E:ShortValue(max - cur), E:ShortValue(rested))
+ end
+ else
+ bar.rested:SetMinMaxValues(0, 1)
+ bar.rested:SetValue(0)
+
+ if textFormat == "PERCENT" then
+ text = format("%d%%", cur / max * 100)
+ elseif textFormat == "CURMAX" then
+ text = format("%s - %s", E:ShortValue(cur), E:ShortValue(max))
+ elseif textFormat == "CURPERC" then
+ text = format("%s - %d%%", E:ShortValue(cur), cur / max * 100)
+ elseif textFormat == "CUR" then
+ text = format("%s", E:ShortValue(cur))
+ elseif textFormat == "REM" then
+ text = format("%s", E:ShortValue(max - cur))
+ elseif textFormat == "CURREM" then
+ text = format("%s - %s", E:ShortValue(cur), E:ShortValue(max - cur))
+ elseif textFormat == "CURPERCREM" then
+ text = format("%s - %d%% (%s)", E:ShortValue(cur), cur / max * 100, E:ShortValue(max - cur))
+ end
+ end
+
+ bar.text:SetText(text)
+ end
+end
+
+function mod:ExperienceBar_OnEnter()
+ if mod.db.experience.mouseover then
+ E:UIFrameFadeIn(self, 0.4, self:GetAlpha(), 1)
+ end
+ GameTooltip:ClearLines()
+ GameTooltip:SetOwner(self, "ANCHOR_CURSOR", 0, -4)
+
+ local cur, max = mod:GetXP("player")
+ local rested = GetXPExhaustion()
+ GameTooltip:AddLine(L["Experience"])
+ GameTooltip:AddLine(" ")
+
+ GameTooltip:AddDoubleLine(L["XP:"], format(" %d / %d (%d%%)", cur, max, cur/max * 100), 1, 1, 1)
+ GameTooltip:AddDoubleLine(L["Remaining:"], format(" %d (%d%% - %d "..L["Bars"]..")", max - cur, (max - cur) / max * 100, 20 * (max - cur) / max), 1, 1, 1)
+
+ if rested then
+ GameTooltip:AddDoubleLine(L["Rested:"], format("+%d (%d%%)", rested, rested / max * 100), 1, 1, 1)
+ end
+
+ GameTooltip:Show()
+end
+
+function mod:ExperienceBar_OnClick()
+
+end
+
+function mod:UpdateExperienceDimensions()
+ self.expBar:Width(self.db.experience.width)
+ self.expBar:Height(self.db.experience.height)
+
+ self.expBar.text:FontTemplate(LSM:Fetch("font", self.db.experience.font), self.db.experience.textSize, self.db.experience.fontOutline)
+ self.expBar.rested:SetOrientation(self.db.experience.orientation)
+
+ self.expBar.statusBar:SetOrientation(self.db.experience.orientation)
+
+ if self.db.experience.mouseover then
+ self.expBar:SetAlpha(0)
+ else
+ self.expBar:SetAlpha(1)
+ end
+end
+
+function mod:EnableDisable_ExperienceBar()
+ local maxLevel = MAX_PLAYER_LEVEL_TABLE[GetExpansionLevel()]
+ if (UnitLevel("player") ~= maxLevel or not self.db.experience.hideAtMaxLevel) and self.db.experience.enable then
+ self:RegisterEvent("PLAYER_XP_UPDATE", "UpdateExperience")
+ self:RegisterEvent("DISABLE_XP_GAIN", "UpdateExperience")
+ self:RegisterEvent("ENABLE_XP_GAIN", "UpdateExperience")
+ self:RegisterEvent("UPDATE_EXHAUSTION", "UpdateExperience")
+ self:UnregisterEvent("UPDATE_EXPANSION_LEVEL")
+ self:UpdateExperience()
+ E:EnableMover(self.expBar.mover:GetName())
+ else
+ self:UnregisterEvent("PLAYER_XP_UPDATE")
+ self:UnregisterEvent("DISABLE_XP_GAIN")
+ self:UnregisterEvent("ENABLE_XP_GAIN")
+ self:UnregisterEvent("UPDATE_EXHAUSTION")
+ self:RegisterEvent("UPDATE_EXPANSION_LEVEL", "EnableDisable_ExperienceBar")
+ self.expBar:Hide()
+ E:DisableMover(self.expBar.mover:GetName())
+ end
+end
+
+function mod:LoadExperienceBar()
+ self.expBar = self:CreateBar("ElvUI_ExperienceBar", self.ExperienceBar_OnEnter, self.ExperienceBar_OnClick, "LEFT", LeftChatPanel, "RIGHT", -E.Border + E.Spacing*3, 0)
+ self.expBar.statusBar:SetStatusBarColor(0, 0.4, 1, .8)
+ self.expBar.rested = CreateFrame("StatusBar", nil, self.expBar)
+ self.expBar.rested:SetInside()
+ self.expBar.rested:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(self.expBar.rested)
+ self.expBar.rested:SetStatusBarColor(1, 0, 1, 0.2)
+
+ self.expBar.eventFrame = CreateFrame("Frame")
+ self.expBar.eventFrame:Hide()
+ self.expBar.eventFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
+ self.expBar.eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
+ self.expBar.eventFrame:SetScript("OnEvent", function(_, event) mod:UpdateExperience(event) end)
+
+ self:UpdateExperienceDimensions()
+
+ E:CreateMover(self.expBar, "ExperienceBarMover", L["Experience Bar"], nil, nil, nil, nil, nil, "databars,experience")
+ self:EnableDisable_ExperienceBar()
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/DataBars/Load_DataBars.xml b/ElvUI/Modules/DataBars/Load_DataBars.xml
new file mode 100644
index 0000000..dfe5f03
--- /dev/null
+++ b/ElvUI/Modules/DataBars/Load_DataBars.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/DataBars/PetExperience.lua b/ElvUI/Modules/DataBars/PetExperience.lua
new file mode 100644
index 0000000..440f5b4
--- /dev/null
+++ b/ElvUI/Modules/DataBars/PetExperience.lua
@@ -0,0 +1,145 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local mod = E:GetModule("DataBars")
+local LSM = LibStub("LibSharedMedia-3.0")
+
+--Lua functions
+local max, min = math.max, math.min
+local format = string.format
+--WoW API
+local GetPetExperience = GetPetExperience
+local HasPetUI = HasPetUI
+local UnitLevel = UnitLevel
+
+function mod:PetExperienceBar_Update(event)
+ if E.myclass ~= "HUNTER" or not mod.db.petExperience.enable then return end
+
+ local bar = self.petExpBar
+ local _, hunterPet = HasPetUI()
+ local hideBar = not hunterPet or (UnitLevel("pet") == self.maxExpansionLevel and self.db.petExperience.hideAtMaxLevel)
+
+ if hideBar or (event == "PLAYER_REGEN_DISABLED" and self.db.petExperience.hideInCombat) then
+ E:DisableMover(self.petExpBar.mover:GetName())
+ bar:Hide()
+ elseif not hideBar and (not self.db.petExperience.hideInCombat or not self.inCombatLockdown) then
+ E:EnableMover(self.petExpBar.mover:GetName())
+ bar:Show()
+
+ local textFormat = self.db.petExperience.textFormat
+ local curExp, maxExp = GetPetExperience()
+ maxExp = max(1, maxExp)
+
+ bar.statusBar:SetMinMaxValues(min(0, curExp), maxExp)
+ -- bar.statusBar:SetValue(curExp - 1 >= 0 and curExp - 1 or 0)
+ bar.statusBar:SetValue(curExp)
+
+ if textFormat == "PERCENT" then
+ bar.text:SetFormattedText("%d%%", curExp / maxExp * 100)
+ elseif textFormat == "CURMAX" then
+ bar.text:SetFormattedText("%s - %s", E:ShortValue(curExp), E:ShortValue(maxExp))
+ elseif textFormat == "CURPERC" then
+ bar.text:SetFormattedText("%s - %d%%", E:ShortValue(curExp), curExp / maxExp * 100)
+ elseif textFormat == "CUR" then
+ bar.text:SetFormattedText("%s", E:ShortValue(curExp))
+ elseif textFormat == "REM" then
+ bar.text:SetFormattedText("%s", E:ShortValue(maxExp - curExp))
+ elseif textFormat == "CURREM" then
+ bar.text:SetFormattedText("%s - %s", E:ShortValue(curExp), E:ShortValue(maxExp - curExp))
+ elseif textFormat == "CURPERCREM" then
+ bar.text:SetFormattedText("%s - %d%% (%s)", E:ShortValue(curExp), curExp / maxExp * 100, E:ShortValue(maxExp - curExp))
+ end
+ end
+end
+
+function mod:PetExperienceBar_OnEnter()
+ if mod.db.petExperience.mouseover then
+ E:UIFrameFadeIn(self, 0.4, self:GetAlpha(), 1)
+ end
+
+ local curExp, maxExp = GetPetExperience()
+ maxExp = max(1, maxExp)
+
+ GameTooltip:ClearLines()
+ GameTooltip:SetOwner(self, "ANCHOR_CURSOR", 0, -4)
+
+ GameTooltip:AddLine(L["Pet Experience"])
+ GameTooltip:AddLine(" ")
+
+ GameTooltip:AddDoubleLine(L["XP:"], format("%d / %d (%d%%)", curExp, maxExp, curExp / maxExp * 100), 1, 1, 1)
+ GameTooltip:AddDoubleLine(L["Remaining:"], format("%d (%d%% - %d %s)", maxExp - curExp, (maxExp - curExp) / maxExp * 100, 20 * (maxExp - curExp) / maxExp, L["Bars"]), 1, 1, 1)
+
+ GameTooltip:Show()
+end
+
+function mod:PetExperienceBar_OnClick()
+
+end
+
+function mod:PetExperienceBar_UpdateDimensions()
+ if E.myclass ~= "HUNTER" then return end
+
+ self.petExpBar:Size(self.db.petExperience.width, self.db.petExperience.height)
+ self.petExpBar:SetAlpha(self.db.petExperience.mouseover and 0 or 1)
+
+ self.petExpBar.text:FontTemplate(LSM:Fetch("font", self.db.petExperience.font), self.db.petExperience.textSize, self.db.petExperience.fontOutline)
+
+ self.petExpBar.statusBar:SetOrientation(self.db.petExperience.orientation)
+ self.petExpBar.statusBar:SetRotatesTexture(self.db.petExperience.orientation ~= "HORIZONTAL")
+
+ if self.petExpBar.bubbles then
+ self:UpdateBarBubbles(self.petExpBar, self.db.petExperience)
+ elseif self.db.petExperience.showBubbles then
+ local bubbles = self:CreateBarBubbles(self.petExpBar)
+ bubbles:SetFrameLevel(5)
+ self:UpdateBarBubbles(self.petExpBar, self.db.petExperience)
+ end
+end
+
+function mod:PetExperienceBar_Toggle()
+ if E.myclass ~= "HUNTER" then return end
+
+ if self.db.petExperience.enable then
+ self.petExpBar.eventFrame:RegisterEvent("UNIT_PET")
+ self.petExpBar.eventFrame:RegisterEvent("UNIT_PET_EXPERIENCE")
+ self.petExpBar.eventFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
+ self.petExpBar.eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
+
+ self:PetExperienceBar_Update()
+ E:EnableMover(self.petExpBar.mover:GetName())
+ else
+ self.petExpBar.eventFrame:UnregisterEvent("UNIT_PET")
+ self.petExpBar.eventFrame:UnregisterEvent("UNIT_PET_EXPERIENCE")
+ self.petExpBar.eventFrame:UnregisterEvent("PLAYER_REGEN_DISABLED")
+ self.petExpBar.eventFrame:UnregisterEvent("PLAYER_REGEN_ENABLED")
+
+ self.petExpBar:Hide()
+ E:DisableMover(self.petExpBar.mover:GetName())
+ end
+end
+
+function mod:PetExperienceBar_Load()
+ if E.myclass ~= "HUNTER" then return end
+
+ self.petExpBar = self:CreateBar("ElvUI_PetExperienceBar", self.PetExperienceBar_OnEnter, self.PetExperienceBar_OnClick, "LEFT", LeftChatPanel, "RIGHT", -E.Border + E.Spacing*3, 0)
+ self.petExpBar.statusBar:SetStatusBarColor(1, 1, 0.41, 0.8)
+
+ self.petExpBar.eventFrame = CreateFrame("Frame")
+ self.petExpBar.eventFrame:Hide()
+ self.petExpBar.eventFrame:SetScript("OnEvent", function(_, event, arg1)
+ if event == "UNIT_PET" then
+ if arg1 == "player" then
+ self:PetExperienceBar_Toggle()
+ end
+ elseif event == "PLAYER_REGEN_DISABLED" then
+ self.inCombatLockdown = true
+ elseif event == "PLAYER_REGEN_ENABLED" then
+ self.inCombatLockdown = false
+ else
+ self:PetExperienceBar_Update(event)
+ end
+ end)
+
+ self:PetExperienceBar_UpdateDimensions()
+
+ E:CreateMover(self.petExpBar, "PetExperienceBarMover", L["Pet Experience Bar"], nil, nil, nil, nil, nil, "databars,petExperience")
+ self:PetExperienceBar_Toggle()
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/DataBars/Reputation.lua b/ElvUI/Modules/DataBars/Reputation.lua
new file mode 100644
index 0000000..3cc2dfa
--- /dev/null
+++ b/ElvUI/Modules/DataBars/Reputation.lua
@@ -0,0 +1,145 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local mod = E:GetModule("DataBars")
+local LSM = LibStub("LibSharedMedia-3.0")
+
+--Lua functions
+local _G = _G
+local format = string.format
+--WoW API / Variables
+local GetFactionInfo = GetFactionInfo
+local GetNumFactions = GetNumFactions
+local GetWatchedFactionInfo = GetWatchedFactionInfo
+local InCombatLockdown = InCombatLockdown
+local FACTION_BAR_COLORS = FACTION_BAR_COLORS
+local REPUTATION = REPUTATION
+local STANDING = STANDING
+local UNKNOWN = UNKNOWN
+
+function mod:UpdateReputation(event)
+ if not mod.db.reputation.enable then return end
+
+ local bar = self.repBar
+
+ local ID, standingLabel
+ local name, reaction, min, max, value = GetWatchedFactionInfo()
+ local numFactions = GetNumFactions()
+
+ if not name or (event == "PLAYER_REGEN_DISABLED" and self.db.reputation.hideInCombat) then
+ bar:Hide()
+ elseif name and (not self.db.reputation.hideInCombat or not InCombatLockdown()) then
+ bar:Show()
+
+ if self.db.reputation.hideInVehicle then
+ E:RegisterObjectForVehicleLock(bar, E.UIParent)
+ else
+ E:UnregisterObjectForVehicleLock(bar)
+ end
+
+ local text = ""
+ local textFormat = self.db.reputation.textFormat
+ local color = FACTION_BAR_COLORS[reaction] or FACTION_BAR_COLORS[1]
+ bar.statusBar:SetStatusBarColor(color.r, color.g, color.b)
+
+ bar.statusBar:SetMinMaxValues(min, max)
+ bar.statusBar:SetValue(value)
+
+ for i = 1, numFactions do
+ local factionName, _, standingID = GetFactionInfo(i)
+ if factionName == name then
+ ID = standingID
+ end
+ end
+
+ if ID then
+ standingLabel = _G["FACTION_STANDING_LABEL"..ID]
+ else
+ standingLabel = UNKNOWN
+ end
+
+ --Prevent a division by zero
+ local maxMinDiff = max - min
+ if maxMinDiff == 0 then
+ maxMinDiff = 1
+ end
+
+ if textFormat == "PERCENT" then
+ text = format("%s: %d%% [%s]", name, ((value - min) / maxMinDiff * 100), standingLabel)
+ elseif textFormat == "CURMAX" then
+ text = format("%s: %s - %s [%s]", name, E:ShortValue(value - min), E:ShortValue(max - min), standingLabel)
+ elseif textFormat == "CURPERC" then
+ text = format("%s: %s - %d%% [%s]", name, E:ShortValue(value - min), ((value - min) / maxMinDiff * 100), standingLabel)
+ elseif textFormat == "CUR" then
+ text = format("%s: %s [%s]", name, E:ShortValue(value - min), standingLabel)
+ elseif textFormat == "REM" then
+ text = format("%s: %s [%s]", name, E:ShortValue((max - min) - (value-min)), standingLabel)
+ elseif textFormat == "CURREM" then
+ text = format("%s: %s - %s [%s]", name, E:ShortValue(value - min), E:ShortValue((max - min) - (value-min)), standingLabel)
+ elseif textFormat == "CURPERCREM" then
+ text = format("%s: %s - %d%% (%s) [%s]", name, E:ShortValue(value - min), ((value - min) / maxMinDiff * 100), E:ShortValue((max - min) - (value-min)), standingLabel)
+ end
+
+ bar.text:SetText(text)
+ end
+end
+
+function mod:ReputationBar_OnEnter()
+ if mod.db.reputation.mouseover then
+ E:UIFrameFadeIn(self, 0.4, self:GetAlpha(), 1)
+ end
+ GameTooltip:ClearLines()
+ GameTooltip:SetOwner(self, "ANCHOR_CURSOR", 0, -4)
+
+ local name, reaction, min, max, value = GetWatchedFactionInfo()
+ if name then
+ GameTooltip:AddLine(name)
+ GameTooltip:AddLine(" ")
+
+ GameTooltip:AddDoubleLine(STANDING..":", _G["FACTION_STANDING_LABEL"..reaction], 1, 1, 1)
+ GameTooltip:AddDoubleLine(REPUTATION..":", format("%d / %d (%d%%)", value - min, max - min, (value - min) / ((max - min == 0) and max or (max - min)) * 100), 1, 1, 1)
+ end
+ GameTooltip:Show()
+end
+
+function mod:ReputationBar_OnClick()
+ ToggleCharacter("ReputationFrame")
+end
+
+function mod:UpdateReputationDimensions()
+ self.repBar:Width(self.db.reputation.width)
+ self.repBar:Height(self.db.reputation.height)
+ self.repBar.statusBar:SetOrientation(self.db.reputation.orientation)
+ self.repBar.text:FontTemplate(LSM:Fetch("font", self.db.reputation.font), self.db.reputation.textSize, self.db.reputation.fontOutline)
+ if self.db.reputation.mouseover then
+ self.repBar:SetAlpha(0)
+ else
+ self.repBar:SetAlpha(1)
+ end
+end
+
+function mod:EnableDisable_ReputationBar()
+ if self.db.reputation.enable then
+ self:RegisterEvent("UPDATE_FACTION", "UpdateReputation")
+ self:UpdateReputation()
+ E:EnableMover(self.repBar.mover:GetName())
+ else
+ self:UnregisterEvent("UPDATE_FACTION")
+ self.repBar:Hide()
+ E:DisableMover(self.repBar.mover:GetName())
+ end
+end
+
+function mod:LoadReputationBar()
+ self.repBar = self:CreateBar("ElvUI_ReputationBar", self.ReputationBar_OnEnter, self.ReputationBar_OnClick, "RIGHT", RightChatPanel, "LEFT", E.Border - E.Spacing*3, 0)
+ E:RegisterStatusBar(self.repBar.statusBar)
+
+ self.repBar.eventFrame = CreateFrame("Frame")
+ self.repBar.eventFrame:Hide()
+ self.repBar.eventFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
+ self.repBar.eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
+ self.repBar.eventFrame:SetScript("OnEvent", function(_, event) mod:UpdateReputation(event) end)
+
+ self:UpdateReputationDimensions()
+
+ E:CreateMover(self.repBar, "ReputationBarMover", L["Reputation Bar"], nil, nil, nil, nil, nil, "databars,reputation")
+ self:EnableDisable_ReputationBar()
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Achievement.lua b/ElvUI/Modules/DataTexts/Achievement.lua
new file mode 100644
index 0000000..c5ca07f
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Achievement.lua
@@ -0,0 +1,32 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local join = string.join
+--WoW API / Variables
+local GetTotalAchievementPoints = GetTotalAchievementPoints
+local ToggleAchievementFrame = ToggleAchievementFrame
+local ACHIEVEMENTS = ACHIEVEMENTS
+
+local displayNumberString = ""
+local lastPanel
+
+local function OnEvent(self)
+ lastPanel = self
+ self.text:SetFormattedText(displayNumberString, GetTotalAchievementPoints())
+end
+
+local function OnClick()
+ ToggleAchievementFrame()
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", ACHIEVEMENTS, ": ", hex, "%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Achievement", {"ACHIEVEMENT_EARNED"}, OnEvent, nil, OnClick, nil, nil, ACHIEVEMENTS)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Armor.lua b/ElvUI/Modules/DataTexts/Armor.lua
new file mode 100644
index 0000000..53d6d7a
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Armor.lua
@@ -0,0 +1,58 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local format, join = string.format, string.join
+--WoW API / Variables
+local UnitArmor = UnitArmor
+local UnitLevel = UnitLevel
+local PaperDollFrame_GetArmorReduction = PaperDollFrame_GetArmorReduction
+local ARMOR = ARMOR
+
+local chanceString = "%.2f%%"
+local displayString = ""
+local _, effectiveArmor
+local lastPanel
+
+local function OnEvent(self)
+ _, effectiveArmor = UnitArmor("player")
+
+ self.text:SetFormattedText(displayString, effectiveArmor)
+
+ lastPanel = self
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ DT.tooltip:AddLine(L["Mitigation By Level: "])
+ DT.tooltip:AddLine(" ")
+
+ local playerLevel = E.mylevel + 3
+ local targetLevel = UnitLevel("target")
+ local armorReduction
+
+ for i = 1, 4 do
+ armorReduction = PaperDollFrame_GetArmorReduction(effectiveArmor, playerLevel)
+ DT.tooltip:AddDoubleLine(playerLevel, format(chanceString, armorReduction), 1, 1, 1)
+ playerLevel = playerLevel - 1
+ end
+
+ if targetLevel and targetLevel > 0 and (targetLevel > playerLevel + 3 or targetLevel < playerLevel) then
+ armorReduction = PaperDollFrame_GetArmorReduction(effectiveArmor, targetLevel)
+ DT.tooltip:AddDoubleLine(targetLevel, format(chanceString, armorReduction), 1, 1, 1)
+ end
+
+ DT.tooltip:Show()
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", ARMOR, ": ", hex, "%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Armor", {"UNIT_RESISTANCES"}, OnEvent, nil, nil, OnEnter, nil, ARMOR)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/AttackPower.lua b/ElvUI/Modules/DataTexts/AttackPower.lua
new file mode 100644
index 0000000..5c59c99
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/AttackPower.lua
@@ -0,0 +1,73 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local max = math.max
+local format, join = string.format, string.join
+--WoW API / Variables
+local ComputePetBonus = ComputePetBonus
+local UnitAttackPower = UnitAttackPower
+local UnitRangedAttackPower = UnitRangedAttackPower
+local ATTACK_POWER = ATTACK_POWER
+local ATTACK_POWER_MAGIC_NUMBER = ATTACK_POWER_MAGIC_NUMBER
+local ATTACK_POWER_TOOLTIP = ATTACK_POWER_TOOLTIP
+local MELEE_ATTACK_POWER = MELEE_ATTACK_POWER
+local MELEE_ATTACK_POWER_TOOLTIP = MELEE_ATTACK_POWER_TOOLTIP
+local PET_BONUS_TOOLTIP_RANGED_ATTACK_POWER = PET_BONUS_TOOLTIP_RANGED_ATTACK_POWER
+local PET_BONUS_TOOLTIP_SPELLDAMAGE = PET_BONUS_TOOLTIP_SPELLDAMAGE
+local RANGED_ATTACK_POWER = RANGED_ATTACK_POWER
+local RANGED_ATTACK_POWER_TOOLTIP = RANGED_ATTACK_POWER_TOOLTIP
+
+local apower, base, posBuff, negBuff
+local displayNumberString = ""
+local lastPanel
+
+local function OnEvent(self)
+ lastPanel = self
+
+ if E.Role == "Ranged" then
+ base, posBuff, negBuff = UnitRangedAttackPower("player")
+ apower = base + posBuff + negBuff
+ else
+ base, posBuff, negBuff = UnitAttackPower("player")
+ apower = base + posBuff + negBuff
+ end
+
+ self.text:SetFormattedText(displayNumberString, apower)
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ if E.Role == "Ranged" then
+ local petAPBonus = ComputePetBonus("PET_BONUS_RAP_TO_AP", apower)
+ local petSpellDmgBonus = ComputePetBonus("PET_BONUS_RAP_TO_SPELLDMG", apower)
+
+ DT.tooltip:AddDoubleLine(RANGED_ATTACK_POWER, apower, 1, 1, 1, 1, 1, 1)
+ DT.tooltip:AddLine(format(RANGED_ATTACK_POWER_TOOLTIP, max(0, apower) / ATTACK_POWER_MAGIC_NUMBER), nil, nil, nil, 1)
+
+ if petAPBonus > 0 then
+ DT.tooltip:AddLine(format(PET_BONUS_TOOLTIP_RANGED_ATTACK_POWER, petAPBonus), nil, nil, nil)
+ end
+
+ if petSpellDmgBonus > 0 then
+ DT.tooltip:AddLine(format(PET_BONUS_TOOLTIP_SPELLDAMAGE, petSpellDmgBonus), nil, nil, nil)
+ end
+ else
+ DT.tooltip:AddDoubleLine(MELEE_ATTACK_POWER, apower, 1, 1, 1, 1, 1, 1)
+ DT.tooltip:AddLine(format(MELEE_ATTACK_POWER_TOOLTIP, max(0, apower) / ATTACK_POWER_MAGIC_NUMBER), nil, nil, nil, 1)
+ end
+
+ DT.tooltip:Show()
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", ATTACK_POWER, ": ", hex, "%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Attack Power", {"UNIT_ATTACK_POWER", "UNIT_RANGED_ATTACK_POWER"}, OnEvent, nil, nil, OnEnter, nil, ATTACK_POWER_TOOLTIP)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Avoidance.lua b/ElvUI/Modules/DataTexts/Avoidance.lua
new file mode 100644
index 0000000..e5dddab
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Avoidance.lua
@@ -0,0 +1,122 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local select = select
+local abs = math.abs
+local format, join = string.format, string.join
+--WoW API / Variables
+local GetBlockChance = GetBlockChance
+local GetBonusBarOffset = GetBonusBarOffset
+local GetDodgeChance = GetDodgeChance
+local GetInventoryItemID = GetInventoryItemID
+local GetInventorySlotInfo = GetInventorySlotInfo
+local GetItemInfo = GetItemInfo
+local GetParryChance = GetParryChance
+local UnitLevel = UnitLevel
+local BLOCK_CHANCE = BLOCK_CHANCE
+local BOSS = BOSS
+local DEFENSE = DEFENSE
+local DODGE_CHANCE = DODGE_CHANCE
+local PARRY_CHANCE = PARRY_CHANCE
+
+local displayString = ""
+local chanceString = "%.2f%%"
+local chanceString2 = "+%.2f%%"
+local AVD_DECAY_RATE = 0.2
+local targetlvl, playerlvl
+local baseMissChance, levelDifference, dodge, parry, block, avoidance, unhittable
+local lastPanel
+
+local function IsWearingShield()
+ local slotID = GetInventorySlotInfo("SecondaryHandSlot")
+ local itemID = GetInventoryItemID("player", slotID)
+
+ if itemID then
+ return select(9, GetItemInfo(itemID))
+ end
+end
+
+local function OnEvent(self)
+ targetlvl, playerlvl = UnitLevel("target"), E.mylevel
+
+ baseMissChance = E.myrace == "NightElf" and 7 or 5
+ if targetlvl == -1 then
+ levelDifference = 3
+ elseif targetlvl > playerlvl then
+ levelDifference = (targetlvl - playerlvl)
+ elseif targetlvl < playerlvl and targetlvl > 0 then
+ levelDifference = (targetlvl - playerlvl)
+ else
+ levelDifference = 0
+ end
+
+ if levelDifference >= 0 then
+ dodge = (GetDodgeChance() - levelDifference * AVD_DECAY_RATE)
+ parry = (GetParryChance() - levelDifference * AVD_DECAY_RATE)
+ block = (GetBlockChance() - levelDifference * AVD_DECAY_RATE)
+ baseMissChance = (baseMissChance - levelDifference * AVD_DECAY_RATE)
+ else
+ dodge = (GetDodgeChance() + abs(levelDifference * AVD_DECAY_RATE))
+ parry = (GetParryChance() + abs(levelDifference * AVD_DECAY_RATE))
+ block = (GetBlockChance() + abs(levelDifference * AVD_DECAY_RATE))
+ baseMissChance = (baseMissChance+ abs(levelDifference * AVD_DECAY_RATE))
+ end
+
+ if dodge <= 0 then dodge = 0 end
+ if parry <= 0 then parry = 0 end
+ if block <= 0 then block = 0 end
+
+ if GetBonusBarOffset() == 3 then
+ parry = 0
+ end
+
+ if IsWearingShield() ~= "INVTYPE_SHIELD" then
+ block = 0
+ end
+
+ avoidance = (dodge + parry + block + baseMissChance)
+ unhittable = avoidance - 102.4
+
+ self.text:SetFormattedText(displayString, avoidance)
+
+ lastPanel = self
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ if targetlvl > 1 then
+ DT.tooltip:AddDoubleLine(L["Avoidance Breakdown"], join("", " (", L["lvl"], " ", targetlvl, ")"))
+ elseif targetlvl == -1 then
+ DT.tooltip:AddDoubleLine(L["Avoidance Breakdown"], join("", " (", BOSS, ")"))
+ else
+ DT.tooltip:AddDoubleLine(L["Avoidance Breakdown"], join("", " (", L["lvl"], " ", playerlvl, ")"))
+ end
+
+ DT.tooltip:AddLine(" ")
+ DT.tooltip:AddDoubleLine(DODGE_CHANCE, format(chanceString, dodge), 1, 1, 1)
+ DT.tooltip:AddDoubleLine(PARRY_CHANCE, format(chanceString, parry), 1, 1, 1)
+ DT.tooltip:AddDoubleLine(BLOCK_CHANCE, format(chanceString, block), 1, 1, 1)
+ DT.tooltip:AddDoubleLine(L["Miss Chance"], format(chanceString, baseMissChance), 1, 1, 1)
+ DT.tooltip:AddLine(" ")
+
+ if unhittable > 0 then
+ DT.tooltip:AddDoubleLine(L["Unhittable:"], format(chanceString2, unhittable), 1, 1, 1, 0, 1, 0)
+ else
+ DT.tooltip:AddDoubleLine(L["Unhittable:"], format(chanceString, unhittable), 1, 1, 1, 1, 0, 0)
+ end
+
+ DT.tooltip:Show()
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", DEFENSE, ": ", hex, "%.2f%%|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Avoidance", {"COMBAT_RATING_UPDATE", "PLAYER_TARGET_CHANGED"}, OnEvent, nil, nil, OnEnter, nil, L["Avoidance Breakdown"])
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Bags.lua b/ElvUI/Modules/DataTexts/Bags.lua
new file mode 100644
index 0000000..95d64d0
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Bags.lua
@@ -0,0 +1,91 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local format, join = string.format, string.join
+--WoW API / Variables
+local ContainerIDToInventoryID = ContainerIDToInventoryID
+local GetBackpackCurrencyInfo = GetBackpackCurrencyInfo
+local GetContainerNumFreeSlots = GetContainerNumFreeSlots
+local GetContainerNumSlots = GetContainerNumSlots
+local GetInventoryItemLink = GetInventoryItemLink
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local BACKPACK_TOOLTIP = BACKPACK_TOOLTIP
+local CURRENCY = CURRENCY
+local MAX_WATCHED_TOKENS = MAX_WATCHED_TOKENS
+local NUM_BAG_SLOTS = NUM_BAG_SLOTS
+
+local currencyString = "|T%s:14:14:0:0:64:64:4:60:4:60|t %s"
+local displayString = ""
+local lastPanel
+
+local function OnEvent(self)
+ local free, total = 0, 0
+ for i = 0, NUM_BAG_SLOTS do
+ free, total = free + GetContainerNumFreeSlots(i), total + GetContainerNumSlots(i)
+ end
+ self.text:SetFormattedText(displayString, total - free, total)
+
+ lastPanel = self
+end
+
+local function OnClick()
+ OpenAllBags()
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ local r, g, b
+ local _, name, quality, link
+ local free, total, used
+
+ for i = 0, NUM_BAG_SLOTS do
+ free, total = GetContainerNumFreeSlots(i), GetContainerNumSlots(i)
+ used = total - free
+
+ if i == 0 then
+ DT.tooltip:AddLine(L["Bags"]..":")
+ DT.tooltip:AddDoubleLine(BACKPACK_TOOLTIP, format("%d / %d", used, total), 1, 1, 1)
+ else
+ link = GetInventoryItemLink("player", ContainerIDToInventoryID(i))
+ if link then
+ name, _, quality = GetItemInfo(link)
+ r, g, b = GetItemQualityColor(quality)
+ DT.tooltip:AddDoubleLine(name, format("%d / %d", used, total), r, g, b)
+ end
+ end
+ end
+
+ local count, currencyType, icon
+ for i = 1, MAX_WATCHED_TOKENS do
+ name, count, currencyType, icon = GetBackpackCurrencyInfo(i)
+ if name and i == 1 then
+ DT.tooltip:AddLine(" ")
+ DT.tooltip:AddLine(CURRENCY..":")
+ end
+
+ if name and count then
+ if currencyType == 1 then
+ icon = "Interface\\PVPFrame\\PVP-ArenaPoints-Icon"
+ elseif currencyType == 2 then
+ icon = "Interface\\PVPFrame\\PVP-Currency-"..E.myfaction
+ end
+ DT.tooltip:AddDoubleLine(format(currencyString, icon, name), count, 1, 1, 1)
+ end
+ end
+
+ DT.tooltip:Show()
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", L["Bags"], ": ", hex, "%d/%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Bags", {"PLAYER_ENTERING_WORLD", "BAG_UPDATE"}, OnEvent, nil, OnClick, OnEnter, nil, L["Bags"])
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Battleground.lua b/ElvUI/Modules/DataTexts/Battleground.lua
new file mode 100644
index 0000000..769320a
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Battleground.lua
@@ -0,0 +1,91 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local select = select
+local join = string.join
+--WoW API / Variables
+local GetBattlefieldScore = GetBattlefieldScore
+local GetBattlefieldStatData = GetBattlefieldStatData
+local GetBattlefieldStatInfo = GetBattlefieldStatInfo
+local GetNumBattlefieldScores = GetNumBattlefieldScores
+local GetNumBattlefieldStats = GetNumBattlefieldStats
+
+local displayString = ""
+local lastPanel
+
+local dataLayout = {
+ ["LeftChatDataPanel"] = {
+ ["left"] = 11,
+ ["middle"] = 5,
+ ["right"] = 2
+ },
+ ["RightChatDataPanel"] = {
+ ["left"] = 4,
+ ["middle"] = 3,
+ ["right"] = 12
+ }
+}
+
+local dataStrings = {
+ [11] = DAMAGE,
+ [5] = HONOR,
+ [2] = KILLING_BLOWS,
+ [4] = DEATHS,
+ [3] = HONORABLE_KILLS,
+ [12] = SHOW_COMBAT_HEALING
+}
+
+function DT:UPDATE_BATTLEFIELD_SCORE()
+ lastPanel = self
+
+ local pointIndex = dataLayout[self:GetParent():GetName()][self.pointIndex]
+ for i = 1, GetNumBattlefieldScores() do
+ local name = GetBattlefieldScore(i)
+ if name == E.myname then
+ self.text:SetFormattedText(displayString, dataStrings[pointIndex], E:ShortValue(select(pointIndex, GetBattlefieldScore(i))))
+ break
+ end
+ end
+end
+
+function DT:BattlegroundStats()
+ DT:SetupTooltip(self)
+
+ local numStatInfo = GetNumBattlefieldStats()
+ if numStatInfo then
+ for i = 1, GetNumBattlefieldScores() do
+ local name = GetBattlefieldScore(i)
+ if name and name == E.myname then
+ local classColor = E.media.herocolor
+
+ DT.tooltip:AddDoubleLine(L["Stats For:"], name, 1, 1, 1, classColor.r, classColor.g, classColor.b)
+ DT.tooltip:AddLine(" ")
+
+ -- Add extra statistics to watch based on what BG you are in.
+ for j = 1, numStatInfo do
+ DT.tooltip:AddDoubleLine(GetBattlefieldStatInfo(j), GetBattlefieldStatData(i, j), 1, 1, 1)
+ end
+
+ break
+ end
+ end
+ end
+
+ DT.tooltip:Show()
+end
+
+function DT:HideBattlegroundTexts()
+ DT.ForceHideBGStats = true
+ DT:LoadDataTexts()
+ E:Print(L["Battleground datatexts temporarily hidden, to show type /bgstats or right click the 'C' icon near the minimap."])
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", "%s: ", hex, "%s|r")
+
+ if lastPanel ~= nil then
+ DT.UPDATE_BATTLEFIELD_SCORE(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/CombatTime.lua b/ElvUI/Modules/DataTexts/CombatTime.lua
new file mode 100644
index 0000000..1fdabfb
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/CombatTime.lua
@@ -0,0 +1,42 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local floor = math.floor
+local format, join = string.format, string.join
+--WoW API / Variables
+local COMBAT = COMBAT
+
+local timer = 0
+local displayNumberString = ""
+
+local lastPanel
+
+local function OnUpdate(self, elapsed)
+ timer = timer + elapsed
+ self.text:SetFormattedText(displayNumberString, format("%02d:%02d:%02d", floor(timer / 60), timer % 60, (timer - floor(timer)) * 100))
+end
+
+local function OnEvent(self, event)
+ if event == "PLAYER_REGEN_DISABLED" then
+ timer = 0
+ self:SetScript("OnUpdate", OnUpdate)
+ elseif event == "PLAYER_REGEN_ENABLED" then
+ self:SetScript("OnUpdate", nil)
+ else
+ self.text:SetFormattedText(displayNumberString, "00:00:00")
+ end
+
+ lastPanel = self
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", COMBAT, ": ", hex, "%s|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Combat Time", {"PLAYER_REGEN_ENABLED", "PLAYER_REGEN_DISABLED"}, OnEvent, nil, nil, nil, nil, L["Combat Time"])
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/ConfigElvUI.lua b/ElvUI/Modules/DataTexts/ConfigElvUI.lua
new file mode 100644
index 0000000..91d1669
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/ConfigElvUI.lua
@@ -0,0 +1,72 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local pairs = pairs
+local find, join = string.find, string.join
+--WoW API / Variables
+local GetNumAddOns = GetNumAddOns
+local GetAddOnInfo = GetAddOnInfo
+local GetAddOnMetadata = GetAddOnMetadata
+local IsShiftKeyDown = IsShiftKeyDown
+local ReloadUI = ReloadUI
+
+local displayString = ""
+local configText = "ElvUI"
+local plugins
+local lastPanel
+
+local function OnEvent(self, event)
+ lastPanel = self
+
+ if not plugins and event == "PLAYER_ENTERING_WORLD" then
+ for i = 1, GetNumAddOns() do
+ local name, title, _, enabled = GetAddOnInfo(i)
+ if enabled and find(name, "ElvUI") and name ~= "ElvUI" then
+ plugins = plugins or {}
+ plugins[title] = GetAddOnMetadata(i, "version")
+ end
+ end
+
+ self:UnregisterEvent(event)
+ end
+
+ self.text:SetFormattedText(displayString, configText)
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ DT.tooltip:AddDoubleLine(L["Left Click:"], L["Toggle Configuration"], 1, 1, 1)
+ DT.tooltip:AddDoubleLine(L["Hold Shift + Right Click:"], L["Reload UI"], 1, 1, 1)
+
+ if plugins then
+ DT.tooltip:AddLine(" ")
+ DT.tooltip:AddDoubleLine("Plugins:", "Version:")
+
+ for plugin, version in pairs(plugins) do
+ DT.tooltip:AddDoubleLine(plugin, version, 1, 1, 1, 1, 1, 1)
+ end
+ end
+
+ DT.tooltip:Show()
+end
+
+local function OnClick(_, button)
+ if button == "LeftButton" or (button == "RightButton" and not IsShiftKeyDown()) then
+ E:ToggleOptionsUI()
+ elseif button == "RightButton" and IsShiftKeyDown() then
+ ReloadUI()
+ end
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", hex, "%s|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel, "ELVUI_COLOR_UPDATE")
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("ElvUI Config", {"PLAYER_ENTERING_WORLD"}, OnEvent, nil, OnClick, OnEnter)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Coordinates.lua b/ElvUI/Modules/DataTexts/Coordinates.lua
new file mode 100644
index 0000000..83da119
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Coordinates.lua
@@ -0,0 +1,36 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local join = string.join
+--WoW API / Variables
+local GetPlayerMapPosition = GetPlayerMapPosition
+local ToggleFrame = ToggleFrame
+
+local displayString = ""
+local x, y = 0, 0
+
+local timeSinceUpdate = 0
+
+local function OnUpdate(self, elapsed)
+ timeSinceUpdate = timeSinceUpdate + elapsed
+
+ if timeSinceUpdate > 0.03333 then
+ timeSinceUpdate = 0
+
+ x, y = GetPlayerMapPosition("player")
+
+ self.text:SetFormattedText(displayString, x * 100, y * 100)
+ end
+end
+
+local function OnClick()
+ ToggleFrame(WorldMapFrame)
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", hex, "%.2f|r", " , ", hex, "%.2f|r")
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Coords", nil, nil, OnUpdate, OnClick, nil, nil, L["Coords"])
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Crit.lua b/ElvUI/Modules/DataTexts/Crit.lua
new file mode 100644
index 0000000..fb80363
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Crit.lua
@@ -0,0 +1,71 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local format, join = string.format, string.join
+--WoW API / Variables
+local GetCombatRating = GetCombatRating
+local GetCombatRatingBonus = GetCombatRatingBonus
+local GetCritChance = GetCritChance
+local GetRangedCritChance = GetRangedCritChance
+local GetSpellCritChance = GetSpellCritChance
+local COMBAT_RATING_NAME11 = COMBAT_RATING_NAME11
+local CRIT_ABBR = CRIT_ABBR
+local CR_CRIT_MELEE = CR_CRIT_MELEE
+local CR_CRIT_MELEE_TOOLTIP = CR_CRIT_MELEE_TOOLTIP
+local CR_CRIT_RANGED = CR_CRIT_RANGED
+local CR_CRIT_RANGED_TOOLTIP = CR_CRIT_RANGED_TOOLTIP
+local MELEE_CRIT_CHANCE = MELEE_CRIT_CHANCE
+local PAPERDOLLFRAME_TOOLTIP_FORMAT = PAPERDOLLFRAME_TOOLTIP_FORMAT
+local RANGED_CRIT_CHANCE = RANGED_CRIT_CHANCE
+local SPELL_CRIT_CHANCE = SPELL_CRIT_CHANCE
+
+local critRating
+local displayModifierString = ""
+local lastPanel
+
+local function OnEvent(self)
+ lastPanel = self
+
+ if E.Role == "Caster"then
+ critRating = GetSpellCritChance(2)
+ elseif E.Role == "Ranged" then
+ critRating = GetRangedCritChance()
+ else
+ critRating = GetCritChance()
+ end
+
+ self.text:SetFormattedText(displayModifierString, critRating)
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ local text, tooltip
+ if E.Role == "Caster" then
+ text = format("%s %.2f%%", format(PAPERDOLLFRAME_TOOLTIP_FORMAT, SPELL_CRIT_CHANCE), critRating)
+ tooltip = format("%s %d", COMBAT_RATING_NAME11, GetCombatRating(11))
+ elseif E.Role == "Ranged" then
+ text = format("%s %.2f%%", format(PAPERDOLLFRAME_TOOLTIP_FORMAT, RANGED_CRIT_CHANCE), critRating)
+ tooltip = format(CR_CRIT_RANGED_TOOLTIP, GetCombatRating(CR_CRIT_RANGED), GetCombatRatingBonus(CR_CRIT_RANGED))
+ else
+ text = format("%s %.2f%%", format(PAPERDOLLFRAME_TOOLTIP_FORMAT, MELEE_CRIT_CHANCE), critRating)
+ tooltip = format(CR_CRIT_MELEE_TOOLTIP, GetCombatRating(CR_CRIT_MELEE), GetCombatRatingBonus(CR_CRIT_MELEE))
+ end
+
+ DT.tooltip:AddLine(text, 1, 1, 1)
+ DT.tooltip:AddLine(tooltip, nil, nil, nil, 1)
+
+ DT.tooltip:Show()
+end
+
+local function ValueColorUpdate(hex)
+ displayModifierString = join("", CRIT_ABBR, ": ", hex, "%.2f%%|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Crit Chance", {"ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE", "PLAYER_DAMAGE_DONE_MODS"}, OnEvent, nil, nil, OnEnter, nil, MELEE_CRIT_CHANCE)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/DPS.lua b/ElvUI/Modules/DataTexts/DPS.lua
new file mode 100644
index 0000000..5a12520
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/DPS.lua
@@ -0,0 +1,90 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local select = select
+local time = time
+local join = string.join
+--WoW API / Variables
+local UnitGUID = UnitGUID
+
+local events = {SWING_DAMAGE = true, RANGE_DAMAGE = true, SPELL_DAMAGE = true, SPELL_PERIODIC_DAMAGE = true, DAMAGE_SHIELD = true, DAMAGE_SPLIT = true, SPELL_EXTRA_ATTACKS = true}
+local playerID, petID
+local dmgTotal, lastDmgAmount = 0, 0
+local combatTime = 0
+local timeStamp = 0
+local lastSegment = 0
+local lastPanel
+local displayString = ""
+
+local function Reset()
+ timeStamp = 0
+ combatTime = 0
+ dmgTotal = 0
+ lastDmgAmount = 0
+end
+
+local function GetDPS(self)
+ local dps
+ if dmgTotal == 0 or combatTime == 0 then
+ dps = 0
+ else
+ dps = dmgTotal / combatTime
+ end
+ self.text:SetFormattedText(displayString, E:ShortValue(dps))
+end
+
+local function OnEvent(self, event, ...)
+ lastPanel = self
+
+ if event == "PLAYER_REGEN_DISABLED" or event == "PLAYER_LEAVE_COMBAT" then
+ local now = time()
+ if now - lastSegment > 20 then
+ Reset()
+ end
+ lastSegment = now
+ elseif event == "COMBAT_LOG_EVENT_UNFILTERED" then
+ if not events[select(2, ...)] then return end
+
+ local id = select(3, ...)
+ if id == playerID or id == petID then
+ if timeStamp == 0 then
+ timeStamp = ...
+ end
+
+ lastSegment = timeStamp
+ combatTime = (...) - timeStamp
+
+ if select(2, ...) == "SWING_DAMAGE" then
+ lastDmgAmount = select(9, ...)
+ else
+ lastDmgAmount = select(12, ...)
+ end
+
+ dmgTotal = dmgTotal + lastDmgAmount
+ end
+ elseif event == "UNIT_PET" then
+ petID = UnitGUID("pet")
+ elseif event == "PLAYER_ENTERING_WORLD" then
+ playerID = E.myguid
+ self:UnregisterEvent(event)
+ end
+
+ GetDPS(self)
+end
+
+local function OnClick(self)
+ Reset()
+ GetDPS(self)
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", L["DPS"], ": ", hex, "%s")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("DPS", {"PLAYER_ENTERING_WORLD", "COMBAT_LOG_EVENT_UNFILTERED", "PLAYER_LEAVE_COMBAT", "PLAYER_REGEN_DISABLED", "UNIT_PET"}, OnEvent, nil, OnClick, nil, nil, L["DPS"])
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/DataTexts.lua b/ElvUI/Modules/DataTexts/DataTexts.lua
new file mode 100644
index 0000000..5c3e6b5
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/DataTexts.lua
@@ -0,0 +1,347 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+local TT = E:GetModule("Tooltip")
+local LDB = E.Libs.LDB
+local LSM = E.Libs.LSM
+
+--Lua functions
+local pairs, type, error = pairs, type, error
+local strlen = strlen
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local InCombatLockdown = InCombatLockdown
+local IsInInstance = IsInInstance
+
+function DT:Initialize()
+ --if E.db.datatexts.enable ~= true then return end
+
+ self.Initialized = true
+ self.db = E.db.datatexts
+
+ self.tooltip = CreateFrame("GameTooltip", "DatatextTooltip", nil, "GameTooltipTemplate")
+ self.tooltip:SetParent(E.UIParent)
+ self.tooltip:SetFrameStrata("TOOLTIP")
+ TT:HookScript(self.tooltip, "OnShow", "SetStyle")
+
+ -- Ignore header font size on DatatextTooltip
+ local font = LSM:Fetch("font", E.db.tooltip.font)
+ local fontOutline = E.db.tooltip.fontOutline
+ local textSize = E.db.tooltip.textFontSize
+ DatatextTooltipTextLeft1:FontTemplate(font, textSize, fontOutline)
+ DatatextTooltipTextRight1:FontTemplate(font, textSize, fontOutline)
+
+ self:RegisterLDB()
+ LDB.RegisterCallback(E, "LibDataBroker_DataObjectCreated", DT.SetupObjectLDB)
+
+ self:LoadDataTexts()
+
+ self:RegisterEvent("PLAYER_ENTERING_WORLD")
+end
+
+DT.RegisteredPanels = {}
+DT.RegisteredDataTexts = {}
+
+DT.PointLocation = {
+ [1] = "middle",
+ [2] = "left",
+ [3] = "right"
+}
+
+function DT:PLAYER_ENTERING_WORLD()
+ local inInstance, instanceType = IsInInstance()
+ self.isInPVP = inInstance and instanceType == "pvp"
+
+ if (not self.isInPVP and self.ShowingBGStats)
+ or (self.isInPVP and not self.ShowingBGStats and self.db.battleground)
+ then
+ self:LoadDataTexts()
+ self.ShowingBGStats = not self.ShowingBGStats
+ end
+end
+
+local LDBHex = "|cffFFFFFF"
+function DT:SetupObjectLDB(name, obj)
+ local curFrame = nil
+
+ local function OnEnter(dt)
+ DT:SetupTooltip(dt)
+ if obj.OnTooltipShow then
+ obj.OnTooltipShow(DT.tooltip)
+ end
+ if obj.OnEnter then
+ obj.OnEnter(dt)
+ end
+ DT.tooltip:Show()
+ end
+
+ local function OnLeave(dt)
+ if obj.OnLeave then
+ obj.OnLeave(dt)
+ end
+ DT.tooltip:Hide()
+ end
+
+ local function OnClick(dt, button)
+ if obj.OnClick then
+ obj.OnClick(dt, button)
+ end
+ end
+
+ local function textUpdate(_, Name, _, Value)
+ if Value == nil or (strlen(Value) >= 3) or Value == "n/a" or Name == Value then
+ curFrame.text:SetText(Value ~= "n/a" and Value or Name)
+ else
+ curFrame.text:SetFormattedText("%s: %s%s|r", Name, LDBHex, Value)
+ end
+ end
+
+ local function OnCallback(newHex)
+ if name and obj then
+ LDBHex = newHex
+ LDB.callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_text", name, nil, obj.text, obj)
+ end
+ end
+
+ local function OnEvent(dt)
+ curFrame = dt
+ LDB:RegisterCallback("LibDataBroker_AttributeChanged_"..name.."_text", textUpdate)
+ LDB:RegisterCallback("LibDataBroker_AttributeChanged_"..name.."_value", textUpdate)
+ OnCallback(LDBHex)
+ end
+
+ DT:RegisterDatatext(name, {"PLAYER_ENTERING_WORLD"}, OnEvent, nil, OnClick, OnEnter, OnLeave)
+ E.valueColorUpdateFuncs[OnCallback] = true
+
+ --Update config if it has been loaded
+ if DT.PanelLayoutOptions then
+ DT:PanelLayoutOptions()
+ end
+end
+
+function DT:RegisterLDB()
+ for name, obj in LDB:DataObjectIterator() do
+ self:SetupObjectLDB(name, obj)
+ end
+end
+
+function DT:GetDataPanelPoint(panel, i, numPoints)
+ if numPoints == 1 then
+ return "CENTER", panel, "CENTER"
+ else
+ if i == 1 then
+ return "CENTER", panel, "CENTER"
+ elseif i == 2 then
+ return "RIGHT", panel.dataPanels.middle, "LEFT", -4, 0
+ elseif i == 3 then
+ return "LEFT", panel.dataPanels.middle, "RIGHT", 4, 0
+ end
+ end
+end
+
+function DT:UpdateAllDimensions()
+ for _, panel in pairs(DT.RegisteredPanels) do
+ local width = (panel:GetWidth() / panel.numPoints) - 4
+ local height = panel:GetHeight() - 4
+ for i = 1, panel.numPoints do
+ local pointIndex = DT.PointLocation[i]
+ panel.dataPanels[pointIndex]:Width(width)
+ panel.dataPanels[pointIndex]:Height(height)
+ panel.dataPanels[pointIndex]:Point(DT:GetDataPanelPoint(panel, i, panel.numPoints))
+ end
+ end
+end
+
+function DT:Data_OnLeave()
+ DT.tooltip:Hide()
+end
+
+function DT:SetupTooltip(panel)
+ local parent = panel:GetParent()
+ self.tooltip:Hide()
+ self.tooltip:SetOwner(parent, parent.anchor, parent.xOff, parent.yOff)
+ self.tooltip:ClearLines()
+ GameTooltip:Hide()
+end
+
+function DT:RegisterPanel(panel, numPoints, anchor, xOff, yOff)
+ DT.RegisteredPanels[panel:GetName()] = panel
+ panel.dataPanels = {}
+ panel.numPoints = numPoints
+
+ panel.xOff = xOff
+ panel.yOff = yOff
+ panel.anchor = anchor
+ for i = 1, numPoints do
+ local pointIndex = DT.PointLocation[i]
+ if not panel.dataPanels[pointIndex] then
+ panel.dataPanels[pointIndex] = CreateFrame("Button", "DataText"..i, panel)
+ panel.dataPanels[pointIndex]:RegisterForClicks("AnyUp")
+ panel.dataPanels[pointIndex].text = panel.dataPanels[pointIndex]:CreateFontString(nil, "OVERLAY")
+ panel.dataPanels[pointIndex].text:SetAllPoints()
+ panel.dataPanels[pointIndex].text:FontTemplate()
+ panel.dataPanels[pointIndex].text:SetJustifyH("CENTER")
+ panel.dataPanels[pointIndex].text:SetJustifyV("MIDDLE")
+ end
+
+ panel.dataPanels[pointIndex]:Point(DT:GetDataPanelPoint(panel, i, numPoints))
+ end
+
+ panel:SetScript("OnSizeChanged", DT.UpdateAllDimensions)
+ DT.UpdateAllDimensions(panel)
+end
+
+function DT:AssignPanelToDataText(panel, data)
+ panel.name = ""
+ if data.name then
+ panel.name = data.name
+ end
+
+ if data.events then
+ for _, event in pairs(data.events) do
+ panel:RegisterEvent(event)
+ end
+ end
+
+ if data.eventFunc then
+ panel:SetScript("OnEvent", data.eventFunc)
+ data.eventFunc(panel, "ELVUI_FORCE_RUN")
+ end
+
+ if data.onUpdate then
+ panel:SetScript("OnUpdate", data.onUpdate)
+ data.onUpdate(panel, 20000)
+ end
+
+ if data.onClick then
+ panel:SetScript("OnClick", function(p, button)
+ if E.db.datatexts.noCombatClick and InCombatLockdown() then return end
+ data.onClick(p, button)
+ end)
+ end
+
+ if data.onEnter then
+ panel:SetScript("OnEnter", function(p)
+ if E.db.datatexts.noCombatHover and InCombatLockdown() then return end
+ data.onEnter(p)
+ end)
+ end
+
+ if data.onLeave then
+ panel:SetScript("OnLeave", data.onLeave)
+ else
+ panel:SetScript("OnLeave", DT.Data_OnLeave)
+ end
+end
+
+function DT:LoadDataTexts()
+ LDB:UnregisterAllCallbacks(self)
+
+ local fontTemplate = LSM:Fetch("font", self.db.font)
+ local enableBGPanel = self.isInPVP and not self.ForceHideBGStats and self.db.battleground
+ local pointIndex, showBGPanel
+
+ if ElvConfigToggle then
+ ElvConfigToggle.text:FontTemplate(fontTemplate, self.db.fontSize, self.db.fontOutline)
+ end
+
+ for panelName, panel in pairs(DT.RegisteredPanels) do
+ showBGPanel = enableBGPanel and (panelName == "LeftChatDataPanel" or panelName == "RightChatDataPanel")
+
+ --Restore Panels
+ for i = 1, panel.numPoints do
+ pointIndex = DT.PointLocation[i]
+ panel.dataPanels[pointIndex]:UnregisterAllEvents()
+ panel.dataPanels[pointIndex]:SetScript("OnUpdate", nil)
+ panel.dataPanels[pointIndex]:SetScript("OnEnter", nil)
+ panel.dataPanels[pointIndex]:SetScript("OnLeave", nil)
+ panel.dataPanels[pointIndex]:SetScript("OnClick", nil)
+ panel.dataPanels[pointIndex].text:FontTemplate(fontTemplate, self.db.fontSize, self.db.fontOutline)
+ panel.dataPanels[pointIndex].text:SetWordWrap(self.db.wordWrap)
+ panel.dataPanels[pointIndex].text:SetText(nil)
+ panel.dataPanels[pointIndex].pointIndex = pointIndex
+
+ if showBGPanel then
+ panel.dataPanels[pointIndex]:RegisterEvent("UPDATE_BATTLEFIELD_SCORE")
+ panel.dataPanels[pointIndex]:SetScript("OnEvent", DT.UPDATE_BATTLEFIELD_SCORE)
+ panel.dataPanels[pointIndex]:SetScript("OnEnter", DT.BattlegroundStats)
+ panel.dataPanels[pointIndex]:SetScript("OnLeave", DT.Data_OnLeave)
+ panel.dataPanels[pointIndex]:SetScript("OnClick", DT.HideBattlegroundTexts)
+ DT.UPDATE_BATTLEFIELD_SCORE(panel.dataPanels[pointIndex])
+ else
+ --Register Panel to Datatext
+ for name, data in pairs(DT.RegisteredDataTexts) do
+ for option, value in pairs(self.db.panels) do
+ if value and type(value) == "table" then
+ if option == panelName and self.db.panels[option][pointIndex] and self.db.panels[option][pointIndex] == name then
+ DT:AssignPanelToDataText(panel.dataPanels[pointIndex], data)
+ end
+ elseif value and type(value) == "string" and value == name then
+ if self.db.panels[option] == name and option == panelName then
+ DT:AssignPanelToDataText(panel.dataPanels[pointIndex], data)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ if DT.ForceHideBGStats then
+ DT.ForceHideBGStats = nil
+ end
+end
+
+--[[
+ DT:RegisterDatatext(name, events, eventFunc, updateFunc, clickFunc, onEnterFunc, onLeaveFunc, localizedName)
+
+ name - name of the datatext (required)
+ events - must be a table with string values of event names to register
+ eventFunc - function that gets fired when an event gets triggered
+ updateFunc - onUpdate script target function
+ click - function to fire when clicking the datatext
+ onEnterFunc - function to fire OnEnter
+ onLeaveFunc - function to fire OnLeave, if not provided one will be set for you that hides the tooltip.
+ localizedName - localized name of the datetext
+]]
+function DT:RegisterDatatext(name, events, eventFunc, updateFunc, clickFunc, onEnterFunc, onLeaveFunc, localizedName)
+ if name then
+ DT.RegisteredDataTexts[name] = {}
+ else
+ error("Cannot register datatext no name was provided.")
+ end
+
+ DT.RegisteredDataTexts[name].name = name
+
+ if type(events) ~= "table" and events ~= nil then
+ error("Events must be registered as a table.")
+ else
+ DT.RegisteredDataTexts[name].events = events
+ DT.RegisteredDataTexts[name].eventFunc = eventFunc
+ end
+
+ if updateFunc and type(updateFunc) == "function" then
+ DT.RegisteredDataTexts[name].onUpdate = updateFunc
+ end
+
+ if clickFunc and type(clickFunc) == "function" then
+ DT.RegisteredDataTexts[name].onClick = clickFunc
+ end
+
+ if onEnterFunc and type(onEnterFunc) == "function" then
+ DT.RegisteredDataTexts[name].onEnter = onEnterFunc
+ end
+
+ if onLeaveFunc and type(onLeaveFunc) == "function" then
+ DT.RegisteredDataTexts[name].onLeave = onLeaveFunc
+ end
+
+ if localizedName and type(localizedName) == "string" then
+ DT.RegisteredDataTexts[name].localizedName = localizedName
+ end
+end
+
+local function InitializeCallback()
+ DT:Initialize()
+end
+
+E:RegisterModule(DT:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Durability.lua b/ElvUI/Modules/DataTexts/Durability.lua
new file mode 100644
index 0000000..9d2f759
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Durability.lua
@@ -0,0 +1,94 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local ipairs = ipairs
+local format, join = string.format, string.join
+--WoW API / Variables
+local GetInventoryItemDurability = GetInventoryItemDurability
+local GetInventorySlotInfo = GetInventorySlotInfo
+local ToggleCharacter = ToggleCharacter
+local DURABILITY = DURABILITY
+
+local displayString = ""
+local tooltipString = "%d%%"
+local lastPanel
+local totalDurability, current, maxDur
+local invDurability = {}
+
+local slots = {
+ "HeadSlot",
+ "ShoulderSlot",
+ "ChestSlot",
+ "WristSlot",
+ "HandsSlot",
+ "WaistSlot",
+ "LegsSlot",
+ "FeetSlot",
+ "MainHandSlot",
+ "SecondaryHandSlot",
+ "RangedSlot",
+}
+
+local slotsLocales = {
+ ["HeadSlot"] = HEADSLOT,
+ ["ShoulderSlot"] = SHOULDERSLOT,
+ ["ChestSlot"] = CHESTSLOT,
+ ["WristSlot"] = WRISTSLOT,
+ ["HandsSlot"] = HANDSSLOT,
+ ["WaistSlot"] = WAISTSLOT,
+ ["LegsSlot"] = LEGSSLOT,
+ ["FeetSlot"] = FEETSLOT,
+ ["MainHandSlot"] = MAINHANDSLOT,
+ ["SecondaryHandSlot"] = SECONDARYHANDSLOT,
+ ["RangedSlot"] = RANGEDSLOT,
+}
+
+local function OnEvent(self)
+ lastPanel = self
+ totalDurability = 100
+
+ for _, sType in ipairs(slots) do
+ local slot = GetInventorySlotInfo(sType)
+ current, maxDur = GetInventoryItemDurability(slot)
+
+ if current then
+ invDurability[sType] = (current / maxDur) * 100
+
+ if invDurability[sType] < totalDurability then
+ totalDurability = invDurability[sType]
+ end
+ else
+ invDurability[sType] = nil
+ end
+ end
+
+ self.text:SetFormattedText(displayString, totalDurability)
+end
+
+local function OnClick()
+ ToggleCharacter("PaperDollFrame")
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ for _, sType in ipairs(slots) do
+ if invDurability[sType] then
+ DT.tooltip:AddDoubleLine(slotsLocales[sType], format(tooltipString, invDurability[sType]), 1, 1, 1, E:ColorGradient(invDurability[sType] * 0.01, 1, 0, 0, 1, 1, 0, 0, 1, 0))
+ end
+ end
+
+ DT.tooltip:Show()
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", DURABILITY, ": ", hex, "%d%%|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel, "ELVUI_COLOR_UPDATE")
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Durability", {"PLAYER_ENTERING_WORLD", "UPDATE_INVENTORY_DURABILITY", "MERCHANT_SHOW"}, OnEvent, nil, OnClick, OnEnter, nil, DURABILITY)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Friends.lua b/ElvUI/Modules/DataTexts/Friends.lua
new file mode 100644
index 0000000..716a464
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Friends.lua
@@ -0,0 +1,292 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local next = next
+local find, format, join = string.find, string.format, string.join
+local sort, wipe = table.sort, table.wipe
+--WoW API / Variables
+local EasyMenu = EasyMenu
+local GetFriendInfo = GetFriendInfo
+local GetMouseFocus = GetMouseFocus
+local GetNumFriends = GetNumFriends
+local GetQuestDifficultyColor = GetQuestDifficultyColor
+local GetRealZoneText = GetRealZoneText
+local InviteUnit = InviteUnit
+local SendChatMessage = SendChatMessage
+local SetItemRef = SetItemRef
+local ToggleFriendsFrame = ToggleFriendsFrame
+local UnitInParty = UnitInParty
+local UnitInRaid = UnitInRaid
+local UnitIsAFK = UnitIsAFK
+local UnitIsDND = UnitIsDND
+local AFK = AFK
+local DND = DND
+local FRIENDS = FRIENDS
+
+local tthead = {r=0.4, g=0.78, b=1}
+local activezone, inactivezone = {r=0.3, g=1.0, b=0.3}, {r=0.65, g=0.65, b=0.65}
+
+local levelNameFormat = "|cff%02x%02x%02x%d|r |cff%02x%02x%02x%s|r %s"
+local levelNameStatusFormat = "|cff%02x%02x%02x%d|r %s%s %s"
+local onlineInfoFormat = join("", FRIENDS_LIST_ONLINE, ": %s/%s")
+
+local afkStatusString = format("<%s>", AFK)
+local dndStatusString = format("<%s>", DND)
+
+local inGroupStamp = "|cffaaaaaa*|r"
+local friendOnlineString = string.gsub(ERR_FRIEND_ONLINE_SS, ".+|h", "")
+local friendOfflineString = string.gsub(ERR_FRIEND_OFFLINE_S, "%%s", "")
+
+local onlineStatusString = "|cffFFFFFF[|r|cff%s%s|r|cffFFFFFF]|r"
+local onlineStatus = {
+ [""] = "",
+ [afkStatusString] = format(onlineStatusString, "FF9900", L["AFK"]),
+ [dndStatusString] = format(onlineStatusString, "FF3333", L["DND"]),
+}
+
+local displayString = ""
+local lastPanel
+
+local dataTable = {}
+local dataUpdated
+
+local menuFrame = CreateFrame("Frame", "FriendDatatextRightClickMenu", E.UIParent, "UIDropDownMenuTemplate")
+local menuList = {
+ {text = OPTIONS_MENU, isTitle = true, notCheckable = true},
+ {text = INVITE, hasArrow = true, notCheckable = true, keepShownOnClick = true, noClickSound = true, menuList = {}},
+ {text = CHAT_MSG_WHISPER_INFORM, hasArrow = true, notCheckable = true, keepShownOnClick = true, noClickSound = true, menuList = {}},
+ {text = PLAYER_STATUS, hasArrow = true, notCheckable = true, keepShownOnClick = true, noClickSound = true,
+ menuList = {
+ {
+ text = format("|cff2BC226%s|r", AVAILABLE),
+ notCheckable = true,
+ func = function()
+ if UnitIsAFK("player") then
+ SendChatMessage("", "AFK")
+ elseif UnitIsDND("player") then
+ SendChatMessage("", "DND")
+ end
+ end
+ },
+ {
+ text = format("|cffE7E716%s|r", DND),
+ notCheckable = true,
+ func = function()
+ if not UnitIsDND("player") then
+ SendChatMessage("", "DND")
+ end
+ end
+ },
+ {
+ text = format("|cffFF0000%s|r", AFK),
+ notCheckable = true,
+ func = function()
+ if not UnitIsAFK("player") then
+ SendChatMessage("", "AFK")
+ end
+ end
+ }
+ }
+ }
+}
+
+local function inviteClick(_, playerName)
+ menuFrame:Hide()
+ InviteUnit(playerName)
+end
+
+local function whisperClick(_, playerName)
+ menuFrame:Hide()
+ SetItemRef("player:"..playerName, format("|Hplayer:%1$s|h[%1$s]|h", playerName), "LeftButton")
+end
+
+local function sortByName(a, b)
+ if a[1] and b[1] then
+ return a[1] < b[1]
+ end
+end
+
+local function BuildDataTable(total)
+ wipe(dataTable)
+
+ if total == 0 then return end
+
+ local name, level, class, area, connected, status, note, className
+
+ for i = 1, total do
+ name, level, class, area, connected, status, note = GetFriendInfo(i)
+
+ if connected then
+ className = E:UnlocalizedClassName(class) or ""
+ status = onlineStatus[status] or ""
+
+ dataTable[i] = {name, level, className, area, connected, status, note}
+ end
+ end
+
+ if next(dataTable) then
+ sort(dataTable, sortByName)
+ end
+end
+
+local function OnClick(_, btn)
+ if btn == "RightButton" then
+ DT.tooltip:Hide()
+
+ wipe(menuList[2].menuList)
+ wipe(menuList[3].menuList)
+
+ local menuCountWhispers, menuCountInvites = 0, 0
+ local classc, levelc, info, grouped, shouldSkip
+
+ local db = E.db.datatexts.friends
+
+ for i = 1, #dataTable do
+ info = dataTable[i]
+
+ if info[5] then
+ if (info[6] == onlineStatus[afkStatusString]) and db.hideAFK then
+ shouldSkip = true
+ elseif (info[6] == onlineStatus[dndStatusString]) and db.hideDND then
+ shouldSkip = true
+ else
+ shouldSkip = nil
+ end
+
+ if not shouldSkip then
+ classc = E.media.herocolor
+ classc = classc or GetQuestDifficultyColor(info[2])
+ levelc = GetQuestDifficultyColor(info[2])
+
+ if UnitInParty(info[1]) or UnitInRaid(info[1]) then
+ grouped = inGroupStamp
+ else
+ grouped = ""
+
+ menuCountInvites = menuCountInvites + 1
+ menuList[2].menuList[menuCountInvites] = {
+ text = format(levelNameFormat, levelc.r*255, levelc.g*255, levelc.b*255, info[2], classc.r*255, classc.g*255, classc.b*255, info[1], grouped),
+ arg1 = info[1],
+ notCheckable = true,
+ func = inviteClick
+ }
+ end
+
+ menuCountWhispers = menuCountWhispers + 1
+ menuList[3].menuList[menuCountWhispers] = {
+ text = format(levelNameFormat, levelc.r*255, levelc.g*255, levelc.b*255, info[2], classc.r*255, classc.g*255, classc.b*255, info[1], grouped),
+ arg1 = info[1],
+ notCheckable = true,
+ func = whisperClick
+ }
+ end
+ end
+ end
+
+ menuList[2].disabled = menuCountInvites == 0
+ menuList[3].disabled = menuCountWhispers == 0
+
+ EasyMenu(menuList, menuFrame, "cursor", 0, 0, "MENU", 2)
+ else
+ ToggleFriendsFrame(1)
+ end
+end
+
+local function OnEnter(self)
+ local numberOfFriends, onlineFriends = GetNumFriends()
+ if onlineFriends == 0 then return end
+
+ DT:SetupTooltip(self)
+
+ if not dataUpdated then
+ if numberOfFriends > 0 then
+ BuildDataTable(numberOfFriends)
+ end
+
+ dataUpdated = true
+ end
+
+ DT.tooltip:AddDoubleLine(
+ L["Friends List"],
+ format(onlineInfoFormat, onlineFriends, numberOfFriends),
+ tthead.r, tthead.g, tthead.b,
+ tthead.r, tthead.g, tthead.b
+ )
+
+ local playerZone = GetRealZoneText()
+ local db = E.db.datatexts.friends
+ local zonec, classc, levelc, info, grouped, shouldSkip
+
+ for i = 1, #dataTable do
+ info = dataTable[i]
+
+ if info[5] then
+ if (info[6] == onlineStatus[afkStatusString]) and db.hideAFK then
+ shouldSkip = true
+ elseif (info[6] == onlineStatus[dndStatusString]) and db.hideDND then
+ shouldSkip = true
+ else
+ shouldSkip = nil
+ end
+
+ if not shouldSkip then
+ if playerZone == info[4] then
+ zonec = activezone
+ else
+ zonec = inactivezone
+ end
+
+ classc = E.media.herocolor
+ classc = classc or GetQuestDifficultyColor(info[2])
+ levelc = GetQuestDifficultyColor(info[2])
+
+ if UnitInParty(info[1]) or UnitInRaid(info[1]) then
+ grouped = inGroupStamp
+ else
+ grouped = ""
+ end
+
+ DT.tooltip:AddDoubleLine(
+ format(levelNameStatusFormat, levelc.r*255, levelc.g*255, levelc.b*255, info[2], info[1], grouped, info[6]),
+ info[4],
+ classc.r, classc.g, classc.b,
+ zonec.r, zonec.g, zonec.b
+ )
+ end
+ end
+ end
+
+ DT.tooltip:Show()
+end
+
+local function OnEvent(self, event, message)
+ lastPanel = self
+
+ -- special handler to detect friend coming online or going offline
+ if event == "CHAT_MSG_SYSTEM" then
+ if not (find(message, friendOnlineString) or find(message, friendOfflineString)) then return end
+ end
+
+ local _, onlineFriends = GetNumFriends()
+
+ self.text:SetFormattedText(displayString, onlineFriends)
+
+ -- force update when showing tooltip
+ dataUpdated = nil
+
+ if GetMouseFocus() == self then
+ self:GetScript("OnEnter")(self)
+ end
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", FRIENDS, ": ", hex, "%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel, "ELVUI_COLOR_UPDATE")
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Friends", {"PLAYER_ENTERING_WORLD", "CHAT_MSG_SYSTEM", "FRIENDLIST_UPDATE"}, OnEvent, nil, OnClick, OnEnter, nil, FRIENDS)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Gold.lua b/ElvUI/Modules/DataTexts/Gold.lua
new file mode 100644
index 0000000..956163f
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Gold.lua
@@ -0,0 +1,164 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local pairs = pairs
+local format = string.format
+local tinsert, wipe = tinsert, wipe
+--WoW API / Variables
+local GetBackpackCurrencyInfo = GetBackpackCurrencyInfo
+local GetMoney = GetMoney
+local IsLoggedIn = IsLoggedIn
+local IsShiftKeyDown = IsShiftKeyDown
+local CURRENCY = CURRENCY
+local MAX_WATCHED_TOKENS = MAX_WATCHED_TOKENS
+
+local currencyString = "|T%s:14:14:0:0:64:64:4:60:4:60|t %s"
+local resetCountersFormatter = string.join("", "|cffaaaaaa", L["Reset Counters: Hold Shift + Left Click"], "|r")
+local resetDataFormatter = string.join("", "|cffaaaaaa", L["Reset Data: Hold Shift + Right Click"], "|r")
+
+local dataTable = {}
+local dataUpdated
+local myDataID
+local totalGold = 0
+local altGold = 0
+local profit = 0
+local spent = 0
+
+local function BuildDataTable()
+ wipe(dataTable)
+
+ for charName in pairs(ElvDB.gold[E.myrealm]) do
+ if ElvDB.gold[E.myrealm][charName] then
+ local color = E.media.herocolor
+
+ tinsert(dataTable,
+ {
+ name = charName,
+ amount = ElvDB.gold[E.myrealm][charName],
+ amountText = E:FormatMoney(ElvDB.gold[E.myrealm][charName], E.db.datatexts.goldFormat or "BLIZZARD", not E.db.datatexts.goldCoins),
+ r = color.r, g = color.g, b = color.b,
+ }
+ )
+
+ if charName == E.myname then
+ myDataID = #dataTable
+ else
+ altGold = altGold + ElvDB.gold[E.myrealm][charName]
+ end
+ end
+ end
+end
+
+local function OnEvent(self, event)
+ if not IsLoggedIn() then return end
+
+ local curMoney = GetMoney()
+
+ if not dataUpdated and (event == "PLAYER_ENTERING_WORLD" or event == "ELVUI_FORCE_RUN") then
+ ElvDB.gold = ElvDB.gold or {}
+ ElvDB.gold[E.myrealm] = ElvDB.gold[E.myrealm] or {}
+ ElvDB.gold[E.myrealm][E.myname] = ElvDB.gold[E.myrealm][E.myname] or curMoney
+
+ ElvDB.class = ElvDB.class or {}
+ ElvDB.class[E.myrealm] = ElvDB.class[E.myrealm] or {}
+ ElvDB.class[E.myrealm][E.myname] = E.myclass
+
+ BuildDataTable()
+ dataUpdated = true
+
+ self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+ end
+
+ local oldMoney = ElvDB.gold[E.myrealm][E.myname]
+
+ if oldMoney > curMoney then
+ spent = spent - (curMoney - oldMoney)
+ else
+ profit = profit + (curMoney - oldMoney)
+ end
+
+ ElvDB.gold[E.myrealm][E.myname] = curMoney
+ totalGold = altGold + curMoney
+
+ local formattedMoney = E:FormatMoney(curMoney, E.db.datatexts.goldFormat or "BLIZZARD", not E.db.datatexts.goldCoins)
+
+ dataTable[myDataID].amount = curMoney
+ dataTable[myDataID].amountText = formattedMoney
+
+ self.text:SetText(formattedMoney)
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ local style = E.db.datatexts.goldFormat or "BLIZZARD"
+ local textOnly = not E.db.datatexts.goldCoins
+
+ DT.tooltip:AddLine(L["Session:"])
+ DT.tooltip:AddDoubleLine(L["Earned:"], E:FormatMoney(profit, style, textOnly), 1, 1, 1, 1, 1, 1)
+ DT.tooltip:AddDoubleLine(L["Spent:"], E:FormatMoney(spent, style, textOnly), 1, 1, 1, 1, 1, 1)
+
+ if profit < spent then
+ DT.tooltip:AddDoubleLine(L["Deficit:"], E:FormatMoney(profit - spent, style, textOnly), 1, 0, 0, 1, 1, 1)
+ elseif (profit - spent) > 0 then
+ DT.tooltip:AddDoubleLine(L["Profit:"], E:FormatMoney(profit - spent, style, textOnly), 0, 1, 0, 1, 1, 1)
+ end
+
+ DT.tooltip:AddLine(" ")
+ DT.tooltip:AddLine(L["Character: "])
+
+ for _, g in ipairs(dataTable) do
+ DT.tooltip:AddDoubleLine(g.name == E.myname and g.name.." |TInterface\\FriendsFrame\\StatusIcon-Online:14|t" or g.name, g.amountText, g.r, g.g, g.b, 1, 1, 1)
+ end
+
+ DT.tooltip:AddLine(" ")
+ DT.tooltip:AddLine(L["Server: "])
+ DT.tooltip:AddDoubleLine(L["Total: "], E:FormatMoney(totalGold, style, textOnly), 1, 1, 1, 1, 1, 1)
+
+ local name, count, currencyType, icon
+
+ for i = 1, MAX_WATCHED_TOKENS do
+ name, count, currencyType, icon = GetBackpackCurrencyInfo(i)
+
+ if name and i == 1 then
+ DT.tooltip:AddLine(" ")
+ DT.tooltip:AddLine(CURRENCY..":")
+ end
+
+ if name and count then
+ if currencyType == 1 then
+ icon = "Interface\\PVPFrame\\PVP-ArenaPoints-Icon"
+ elseif currencyType == 2 then
+ icon = "Interface\\PVPFrame\\PVP-Currency-"..E.myfaction
+ end
+
+ DT.tooltip:AddDoubleLine(format(currencyString, icon, name), count, 1, 1, 1)
+ end
+ end
+
+ DT.tooltip:AddLine(" ")
+ DT.tooltip:AddLine(resetCountersFormatter)
+ DT.tooltip:AddLine(resetDataFormatter)
+
+ DT.tooltip:Show()
+end
+
+local function OnClick(self, btn)
+ if btn == "RightButton" and IsShiftKeyDown() then
+ ElvDB.gold = nil
+ dataUpdated = nil
+ OnEvent(self, "PLAYER_ENTERING_WORLD")
+ OnEnter(self)
+ elseif btn == "LeftButton" then
+ if IsShiftKeyDown() then
+ profit = 0
+ spent = 0
+ OnEnter(self)
+ else
+ OpenAllBags()
+ end
+ end
+end
+
+DT:RegisterDatatext("Gold", {"PLAYER_ENTERING_WORLD", "PLAYER_MONEY", "SEND_MAIL_MONEY_CHANGED", "SEND_MAIL_COD_CHANGED", "PLAYER_TRADE_MONEY", "TRADE_MONEY_CHANGED"}, OnEvent, nil, OnClick, OnEnter, nil, L["Gold"])
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Guild.lua b/ElvUI/Modules/DataTexts/Guild.lua
new file mode 100644
index 0000000..8421260
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Guild.lua
@@ -0,0 +1,328 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local find, format, join = string.find, string.format, string.join
+local sort, wipe = table.sort, table.wipe
+--WoW API / Variables
+local EasyMenu = EasyMenu
+local GetGuildInfo = GetGuildInfo
+local GetGuildRosterInfo = GetGuildRosterInfo
+local GetGuildRosterMOTD = GetGuildRosterMOTD
+local GetMouseFocus = GetMouseFocus
+local GetNumGuildMembers = GetNumGuildMembers
+local GetQuestDifficultyColor = GetQuestDifficultyColor
+local GetRealZoneText = GetRealZoneText
+local GuildRoster = GuildRoster
+local InviteUnit = InviteUnit
+local IsInGuild = IsInGuild
+local IsShiftKeyDown = IsShiftKeyDown
+local SetItemRef = SetItemRef
+local ToggleFriendsFrame = ToggleFriendsFrame
+local UnitInParty = UnitInParty
+local UnitInRaid = UnitInRaid
+local GUILD = GUILD
+local GUILD_MOTD = GUILD_MOTD
+
+local tthead, ttsubh, ttoff = {r=0.4, g=0.78, b=1}, {r=0.75, g=0.9, b=1}, {r=0.3,g=1,b=0.3}
+local activezone, inactivezone = {r=0.3, g=1.0, b=0.3}, {r=0.65, g=0.65, b=0.65}
+
+local levelNameFormat = "|cff%02x%02x%02x%d|r |cff%02x%02x%02x%s|r %s"
+local levelNameStatusFormat = "|cff%02x%02x%02x%d|r %s%s"
+local onlineInfoFormat = join("", GUILD, ": %d/%d")
+
+local guildMotDFormat = "%s |cffaaaaaa- |cffffffff%s"
+local moreMembersOnlineFormat = join("", "+ %d ", FRIENDS_LIST_ONLINE, "...")
+local nameRankFormat = "%s |cff999999-|cffffffff %s"
+local noteFormat = join("", "|cff999999 ", LABEL_NOTE, ":|r %s")
+local officerNoteFormat = join("", "|cff999999 ", GUILD_RANK1_DESC, ":|r %s")
+
+local inGroupStamp = "|cffaaaaaa*|r"
+local friendOnlineString = select(2, string.split(" ", ERR_FRIEND_ONLINE_SS, 2))
+local friendOfflineString = select(2, string.split(" ", ERR_FRIEND_OFFLINE_S, 2))
+
+local onlineStatusString = "|cffFFFFFF[|r|cffFF0000%s|r|cffFFFFFF]|r"
+local onlineStatus = {
+ [0] = "",
+ [1] = format(onlineStatusString, L["AFK"]),
+ [2] = format(onlineStatusString, L["DND"]),
+}
+
+local displayString = ""
+local noGuildString = ""
+local lastPanel
+
+local dataTable = {}
+local guildMotD = ""
+local currentSortMode = false
+local dataUpdated
+local rosterDelay
+
+local totalOnline = 0
+local totalMembers = 0
+
+local menuFrame = CreateFrame("Frame", "GuildDatatTextRightClickMenu", E.UIParent, "UIDropDownMenuTemplate")
+local menuList = {
+ {text = OPTIONS_MENU, isTitle = true, notCheckable = true},
+ {text = INVITE, hasArrow = true, notCheckable = true, keepShownOnClick = true, noClickSound = true, menuList = {}},
+ {text = CHAT_MSG_WHISPER_INFORM, hasArrow = true, notCheckable = true, keepShownOnClick = true, noClickSound = true, menuList = {}}
+}
+
+local function inviteClick(_, playerName)
+ menuFrame:Hide()
+ InviteUnit(playerName)
+end
+
+local function whisperClick(_, playerName)
+ menuFrame:Hide()
+ SetItemRef("player:"..playerName, format("|Hplayer:%1$s|h[%1$s]|h", playerName), "LeftButton")
+end
+
+local function sortByRank(a, b)
+ if a and b then
+ return a[10] < b[10]
+ end
+end
+
+local function sortByName(a, b)
+ if a and b then
+ return a[1] < b[1]
+ end
+end
+
+local function SortDataTable(shiftKeyDown)
+ if currentSortMode == shiftKeyDown and not dataUpdated then return end
+
+ if shiftKeyDown then
+ sort(dataTable, sortByRank)
+ else
+ sort(dataTable, sortByName)
+ end
+
+ currentSortMode = shiftKeyDown
+ dataUpdated = nil
+end
+
+local function BuildDataTable()
+ wipe(dataTable)
+
+ totalMembers = GetNumGuildMembers()
+ totalOnline = 0
+
+ local _, name, rank, rankIndex, level, zone, note, officernote, connected, status, englishClass
+
+ for i = 1, totalMembers do
+ name, rank, rankIndex, level, _, zone, note, officernote, connected, status, englishClass = GetGuildRosterInfo(i)
+ if not name then break end
+
+ if connected then
+ totalOnline = totalOnline + 1
+ dataTable[#dataTable + 1] = {name, rank, level, zone, note, officernote, connected, onlineStatus[status], englishClass, rankIndex}
+ end
+ end
+
+ dataUpdated = true
+end
+
+local function OnClick(_, btn)
+ if btn == "RightButton" and IsInGuild() then
+ if totalOnline <= 1 then return end
+
+ DT.tooltip:Hide()
+
+ wipe(menuList[2].menuList)
+ wipe(menuList[3].menuList)
+
+ local menuCountWhispers, menuCountInvites = 0, 0
+ local classc, levelc, info, grouped
+
+ for i = 1, #dataTable do
+ info = dataTable[i]
+
+ if info[7] and info[1] ~= E.myname then
+ classc = E.media.herocolor
+ levelc = GetQuestDifficultyColor(info[3])
+
+ if UnitInParty(info[1]) or UnitInRaid(info[1]) then
+ grouped = inGroupStamp
+ else
+ grouped = ""
+
+ menuCountInvites = menuCountInvites + 1
+ menuList[2].menuList[menuCountInvites] = {
+ text = format(levelNameFormat, levelc.r*255,levelc.g*255,levelc.b*255, info[3], classc.r*255,classc.g*255,classc.b*255, info[1], grouped),
+ arg1 = info[1],
+ notCheckable = true,
+ func = inviteClick
+ }
+ end
+
+ menuCountWhispers = menuCountWhispers + 1
+ menuList[3].menuList[menuCountWhispers] = {
+ text = format(levelNameFormat, levelc.r*255,levelc.g*255,levelc.b*255, info[3], classc.r*255,classc.g*255,classc.b*255, info[1], grouped),
+ arg1 = info[1],
+ notCheckable = true,
+ func = whisperClick
+ }
+ end
+ end
+
+ menuList[2].disabled = menuCountInvites == 0
+ menuList[3].disabled = menuCountWhispers == 0
+
+ EasyMenu(menuList, menuFrame, "cursor", 0, 0, "MENU", 2)
+ else
+ ToggleFriendsFrame(3)
+ end
+end
+
+local function OnEnter(self, _, noUpdate)
+ if not IsInGuild() then return end
+
+ DT:SetupTooltip(self)
+
+ if totalOnline == 0 then
+ BuildDataTable()
+ end
+
+ local guildName, guildRank = GetGuildInfo("player")
+
+ local playerZone = GetRealZoneText()
+ local shiftKeyDown = IsShiftKeyDown()
+ local zonec, classc, levelc, info, grouped
+ local shown = 0
+
+ if totalOnline > 1 then
+ SortDataTable(shiftKeyDown)
+ end
+
+ if guildName and guildRank then
+ DT.tooltip:AddDoubleLine(
+ guildName,
+ format(onlineInfoFormat, totalOnline, totalMembers),
+ tthead.r, tthead.g, tthead.b,
+ tthead.r, tthead.g, tthead.b
+ )
+ DT.tooltip:AddLine(guildRank, tthead.r,tthead.g,tthead.b)
+ end
+
+ if guildMotD ~= "" then
+ DT.tooltip:AddLine(" ")
+ DT.tooltip:AddLine(format(guildMotDFormat, GUILD_MOTD, guildMotD), ttsubh.r, ttsubh.g, ttsubh.b, 1)
+ end
+
+ DT.tooltip:AddLine(" ")
+
+ for i = 1, #dataTable do
+ info = dataTable[i]
+
+ if playerZone == info[4] then
+ zonec = activezone
+ else
+ zonec = inactivezone
+ end
+
+ classc = E.media.herocolor
+
+ if shiftKeyDown then
+ DT.tooltip:AddDoubleLine(
+ format(nameRankFormat, info[1], info[2]),
+ info[4],
+ classc.r, classc.g, classc.b,
+ zonec.r, zonec.g, zonec.b
+ )
+
+ if info[5] ~= "" then
+ DT.tooltip:AddLine(format(noteFormat, info[5]), ttsubh.r, ttsubh.g, ttsubh.b, 1)
+ end
+
+ if info[6] ~= "" then
+ DT.tooltip:AddLine(format(officerNoteFormat, info[6]), ttoff.r, ttoff.g, ttoff.b, 1)
+ end
+ else
+ levelc = GetQuestDifficultyColor(info[3])
+
+ if UnitInParty(info[1]) or UnitInRaid(info[1]) then
+ grouped = inGroupStamp
+ else
+ grouped = ""
+ end
+
+ DT.tooltip:AddDoubleLine(
+ format(levelNameStatusFormat, levelc.r*255, levelc.g*255, levelc.b*255, info[3], info[1], grouped, info[8]),
+ info[4],
+ classc.r, classc.g, classc.b,
+ zonec.r, zonec.g, zonec.b
+ )
+ end
+
+ shown = shown + 1
+
+ if shown == 30 then
+ if totalOnline > 30 then
+ DT.tooltip:AddLine(format(moreMembersOnlineFormat, totalOnline - 30), ttsubh.r, ttsubh.g, ttsubh.b)
+ end
+ break
+ end
+ end
+
+ DT.tooltip:Show()
+
+ if not noUpdate then
+ GuildRoster()
+ end
+end
+
+local eventHandlers = {
+ ["ELVUI_FORCE_RUN"] = function(self)
+ guildMotD = GetGuildRosterMOTD()
+ GuildRoster()
+ end,
+ ["GUILD_MOTD"] = function(_, message)
+ guildMotD = message
+ end,
+ ["CHAT_MSG_SYSTEM"] = function(_, message)
+ if rosterDelay then return end
+
+ if find(message, friendOnlineString) or find(message, friendOfflineString) then
+ rosterDelay = E:Delay(10, function()
+ GuildRoster()
+ rosterDelay = nil
+ end)
+ end
+ end,
+ ["GUILD_ROSTER_UPDATE"] = function(self)
+ GuildRoster()
+ BuildDataTable()
+
+ if GetMouseFocus() == self then
+ self:GetScript("OnEnter")(self, nil, true)
+ end
+ end,
+ ["PLAYER_GUILD_UPDATE"] = GuildRoster,
+ ["ELVUI_COLOR_UPDATE"] = E.noop,
+}
+
+local function OnEvent(self, event, ...)
+ lastPanel = self
+
+ if IsInGuild() then
+ eventHandlers[event](self, ...)
+
+ self.text:SetFormattedText(displayString, totalOnline)
+ else
+ self.text:SetText(noGuildString)
+ end
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", GUILD, ": ", hex, "%d|r")
+ noGuildString = join("", hex, L["No Guild"])
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel, "ELVUI_COLOR_UPDATE")
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Guild", {"CHAT_MSG_SYSTEM", "GUILD_ROSTER_UPDATE", "PLAYER_GUILD_UPDATE", "GUILD_MOTD"}, OnEvent, nil, OnClick, OnEnter, nil, GUILD)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/HPS.lua b/ElvUI/Modules/DataTexts/HPS.lua
new file mode 100644
index 0000000..0970e8c
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/HPS.lua
@@ -0,0 +1,87 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local select = select
+local time = time
+local max = math.max
+local join = string.join
+--WoW API / Variables
+local UnitGUID = UnitGUID
+
+local events = {SPELL_HEAL = true, SPELL_PERIODIC_HEAL = true}
+local playerID, petID
+local healTotal, lastHealAmount = 0, 0
+local combatTime = 0
+local timeStamp = 0
+local lastSegment = 0
+local lastPanel
+local displayString = ""
+
+local function Reset()
+ timeStamp = 0
+ combatTime = 0
+ healTotal = 0
+ lastHealAmount = 0
+end
+
+local function GetHPS(self)
+ local hps
+ if healTotal == 0 or combatTime == 0 then
+ hps = 0
+ else
+ hps = healTotal / combatTime
+ end
+ self.text:SetFormattedText(displayString, E:ShortValue(hps))
+end
+
+local function OnEvent(self, event, ...)
+ lastPanel = self
+
+ if event == "PLAYER_REGEN_DISABLED" or event == "PLAYER_LEAVE_COMBAT" then
+ local now = time()
+ if now - lastSegment > 20 then
+ Reset()
+ end
+ lastSegment = now
+ elseif event == "COMBAT_LOG_EVENT_UNFILTERED" then
+ if not events[select(2, ...)] then return end
+
+ local id = select(3, ...)
+ if id == playerID or id == petID then
+ if timeStamp == 0 then
+ timeStamp = ...
+ end
+
+ lastSegment = timeStamp
+ combatTime = (...) - timeStamp
+
+ local overHeal = select(13, ...)
+ lastHealAmount = select(12, ...)
+ healTotal = healTotal + max(0, lastHealAmount - overHeal)
+ end
+ elseif event == "UNIT_PET" then
+ petID = UnitGUID("pet")
+ elseif event == "PLAYER_ENTERING_WORLD" then
+ playerID = E.myguid
+ self:UnregisterEvent(event)
+ end
+
+ GetHPS(self)
+end
+
+local function OnClick(self)
+ Reset()
+ GetHPS(self)
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", L["HPS"], ": ", hex, "%s")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("HPS", {"PLAYER_ENTERING_WORLD", "COMBAT_LOG_EVENT_UNFILTERED", "PLAYER_LEAVE_COMBAT", "PLAYER_REGEN_DISABLED", "UNIT_PET"}, OnEvent, nil, OnClick, nil, nil, L["HPS"])
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Haste.lua b/ElvUI/Modules/DataTexts/Haste.lua
new file mode 100644
index 0000000..e7c9db1
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Haste.lua
@@ -0,0 +1,76 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local format, join = string.format, string.join
+--WoW API / Variables
+local GetCombatRating = GetCombatRating
+local GetCombatRatingBonus = GetCombatRatingBonus
+local UnitAttackSpeed = UnitAttackSpeed
+local UnitRangedDamage = UnitRangedDamage
+local ATTACK_SPEED = ATTACK_SPEED
+local CR_HASTE_MELEE = CR_HASTE_MELEE
+local CR_HASTE_RANGED = CR_HASTE_RANGED
+local CR_HASTE_RATING_TOOLTIP = CR_HASTE_RATING_TOOLTIP
+local CR_HASTE_SPELL = CR_HASTE_SPELL
+local PAPERDOLLFRAME_TOOLTIP_FORMAT = PAPERDOLLFRAME_TOOLTIP_FORMAT
+local SPELL_HASTE = SPELL_HASTE
+local SPELL_HASTE_ABBR = SPELL_HASTE_ABBR
+local SPELL_HASTE_TOOLTIP = SPELL_HASTE_TOOLTIP
+
+local hasteRating
+local displayNumberString = ""
+local lastPanel
+
+local function OnEvent(self)
+ lastPanel = self
+
+ if E.Role == "Caster" then
+ hasteRating = GetCombatRating(CR_HASTE_SPELL)
+ elseif E.Role == "Ranged" then
+ hasteRating = GetCombatRating(CR_HASTE_RANGED)
+ else
+ hasteRating = GetCombatRating(CR_HASTE_MELEE)
+ end
+
+ self.text:SetFormattedText(displayNumberString, hasteRating)
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ local text, tooltip
+ if E.Role == "Caster" then
+ text = format("%s %d", SPELL_HASTE, hasteRating)
+ tooltip = format(SPELL_HASTE_TOOLTIP, GetCombatRatingBonus(CR_HASTE_SPELL))
+ elseif E.Role == "Ranged" then
+ text = format("%s %.2f", format(PAPERDOLLFRAME_TOOLTIP_FORMAT, ATTACK_SPEED), UnitRangedDamage("player"))
+ tooltip = format(CR_HASTE_RATING_TOOLTIP, hasteRating, GetCombatRatingBonus(CR_HASTE_RANGED))
+ else
+ local speed, offhandSpeed = UnitAttackSpeed("player")
+
+ if offhandSpeed then
+ text = format("%s %.2f / %.2f", format(PAPERDOLLFRAME_TOOLTIP_FORMAT, ATTACK_SPEED), speed, offhandSpeed)
+ else
+ text = format("%s %.2f", format(PAPERDOLLFRAME_TOOLTIP_FORMAT, ATTACK_SPEED), speed)
+ end
+
+ tooltip = format(CR_HASTE_RATING_TOOLTIP, hasteRating, GetCombatRatingBonus(CR_HASTE_MELEE))
+ end
+
+ DT.tooltip:AddLine(text, 1, 1, 1)
+ DT.tooltip:AddLine(tooltip, nil, nil, nil, 1)
+
+ DT.tooltip:Show()
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", SPELL_HASTE_ABBR, ": ", hex, "%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Haste", {"ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE", "UNIT_ATTACK_SPEED", "UNIT_SPELL_HASTE"}, OnEvent, nil, nil, OnEnter, nil, SPELL_HASTE)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Hit.lua b/ElvUI/Modules/DataTexts/Hit.lua
new file mode 100644
index 0000000..26f2418
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Hit.lua
@@ -0,0 +1,40 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local join = string.join
+--WoW API / Variables
+local GetCombatRatingBonus = GetCombatRatingBonus
+local CR_HIT_MELEE = CR_HIT_MELEE
+local CR_HIT_RANGED = CR_HIT_RANGED
+local CR_HIT_SPELL = CR_HIT_SPELL
+local STAT_HIT_CHANCE = STAT_HIT_CHANCE
+
+local hitRatingBonus
+local displayString = ""
+local lastPanel
+
+local function OnEvent(self)
+ lastPanel = self
+
+ if E.Role == "Caster" then
+ hitRatingBonus = GetCombatRatingBonus(CR_HIT_SPELL)
+ elseif E.Role == "Ranged" then
+ hitRatingBonus = GetCombatRatingBonus(CR_HIT_RANGED)
+ else
+ hitRatingBonus = GetCombatRatingBonus(CR_HIT_MELEE)
+ end
+
+ self.text:SetFormattedText(displayString, hitRatingBonus)
+end
+
+local function ValueColorUpdate(hex)
+ displayString = join("", L["Hit"], ": ", hex, "%.2f%%|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Hit", {"ACTIVE_TALENT_GROUP_CHANGED", "PLAYER_TALENT_UPDATE", "COMBAT_RATING_UPDATE"}, OnEvent, nil, nil, nil, nil, STAT_HIT_CHANCE)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/HonorableKills.lua b/ElvUI/Modules/DataTexts/HonorableKills.lua
new file mode 100644
index 0000000..a5c9227
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/HonorableKills.lua
@@ -0,0 +1,27 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local join = string.join
+--WoW API / Variables
+local GetPVPLifetimeStats = GetPVPLifetimeStats
+local KILLS = KILLS
+
+local lastPanel
+local displayNumberString = ""
+
+local function OnEvent(self)
+ lastPanel = self
+ self.text:SetFormattedText(displayNumberString, (GetPVPLifetimeStats()))
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", KILLS, ": ", hex, "%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Honorable Kills", {"PLAYER_PVP_KILLS_CHANGED", "PLAYER_PVP_RANK_CHANGED"}, OnEvent, nil, nil, nil, nil, HONORABLE_KILLS)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Load_DataTexts.xml b/ElvUI/Modules/DataTexts/Load_DataTexts.xml
new file mode 100644
index 0000000..a9ec3ce
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Load_DataTexts.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Regen.lua b/ElvUI/Modules/DataTexts/Regen.lua
new file mode 100644
index 0000000..05d3157
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Regen.lua
@@ -0,0 +1,35 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local join = string.join
+--WoW API / Variables
+local InCombatLockdown = InCombatLockdown
+local GetManaRegen = GetManaRegen
+local MANA_REGEN = MANA_REGEN
+
+local displayNumberString = ""
+local lastPanel
+
+local function OnEvent(self)
+ lastPanel = self
+
+ local baseMR, castingMR = GetManaRegen()
+
+ if InCombatLockdown() then
+ self.text:SetFormattedText(displayNumberString, castingMR * 5)
+ else
+ self.text:SetFormattedText(displayNumberString, baseMR * 5)
+ end
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", MANA_REGEN, ": ", hex, "%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Mana Regen", {"PLAYER_DAMAGE_DONE_MODS", "PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED"}, OnEvent, nil, nil, nil, nil, MANA_REGEN)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Resilience.lua b/ElvUI/Modules/DataTexts/Resilience.lua
new file mode 100644
index 0000000..7341d57
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Resilience.lua
@@ -0,0 +1,39 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local min = math.min
+local join = string.join
+--WoW API / Variables
+local GetCombatRating = GetCombatRating
+local CR_CRIT_TAKEN_MELEE = CR_CRIT_TAKEN_MELEE
+local CR_CRIT_TAKEN_RANGED = CR_CRIT_TAKEN_RANGED
+local CR_CRIT_TAKEN_SPELL = CR_CRIT_TAKEN_SPELL
+local STAT_RESILIENCE = STAT_RESILIENCE
+
+local displayNumberString = ""
+local lastPanel
+
+local function OnEvent(self)
+ lastPanel = self
+
+ local melee = GetCombatRating(CR_CRIT_TAKEN_MELEE)
+ local ranged = GetCombatRating(CR_CRIT_TAKEN_RANGED)
+ local spell = GetCombatRating(CR_CRIT_TAKEN_SPELL)
+
+ local minResilience = min(melee, ranged)
+ minResilience = min(minResilience, spell)
+
+ self.text:SetFormattedText(displayNumberString, minResilience)
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", STAT_RESILIENCE, ": ", hex, "%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Resilience", {"COMBAT_RATING_UPDATE"}, OnEvent, nil, nil, nil, nil, STAT_RESILIENCE)
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/SpellPower.lua b/ElvUI/Modules/DataTexts/SpellPower.lua
new file mode 100644
index 0000000..76ffb06
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/SpellPower.lua
@@ -0,0 +1,34 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local join = string.join
+--WoW API / Variables
+local GetSpellBonusDamage = GetSpellBonusDamage
+local GetSpellBonusHealing = GetSpellBonusHealing
+
+local displayNumberString = ""
+local lastPanel
+
+local function OnEvent(self)
+ local spellDamage = GetSpellBonusDamage(7)
+ local spellHealing = GetSpellBonusHealing()
+
+ if spellHealing > spellDamage then
+ self.text:SetFormattedText(displayNumberString, L["HP"], spellHealing)
+ else
+ self.text:SetFormattedText(displayNumberString, L["SP"], spellDamage)
+ end
+ lastPanel = self
+end
+
+local function ValueColorUpdate(hex)
+ displayNumberString = join("", "%s: ", hex, "%d|r")
+
+ if lastPanel ~= nil then
+ OnEvent(lastPanel)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Spell/Heal Power", {"PLAYER_DAMAGE_DONE_MODS"}, OnEvent, nil, nil, nil, nil, L["Spell/Heal Power"])
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/System.lua b/ElvUI/Modules/DataTexts/System.lua
new file mode 100644
index 0000000..9cf97be
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/System.lua
@@ -0,0 +1,231 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local collectgarbage = collectgarbage
+local floor = math.floor
+local format = string.format
+local tinsert, sort = table.insert, table.sort
+--WoW API / Variables
+local CopyTable = CopyTable
+local GetAddOnCPUUsage = GetAddOnCPUUsage
+local GetAddOnInfo = GetAddOnInfo
+local GetAddOnMemoryUsage = GetAddOnMemoryUsage
+local GetFramerate = GetFramerate
+local GetNetStats = GetNetStats
+local GetNumAddOns = GetNumAddOns
+local HideUIPanel = HideUIPanel
+local IsAddOnLoaded = IsAddOnLoaded
+local IsModifierKeyDown = IsModifierKeyDown
+local IsShiftKeyDown = IsShiftKeyDown
+local PlaySound = PlaySound
+local ResetCPUUsage = ResetCPUUsage
+local ShowUIPanel = ShowUIPanel
+local UpdateAddOnCPUUsage = UpdateAddOnCPUUsage
+local UpdateAddOnMemoryUsage = UpdateAddOnMemoryUsage
+
+local cpuProfiling = GetCVar("scriptProfile") == "1"
+
+local int = 5 -- initial delay
+local statusColors = {
+ "|cff0CD809",
+ "|cffE8DA0F",
+ "|cffFF9000",
+ "|cffD80909"
+}
+
+local enteredFrame
+local homeLatencyString = "%d ms"
+local kiloByteString = "%d kb"
+local megaByteString = "%.2f mb"
+
+local memoryTable = {}
+local cpuTable = {}
+local lodTable = {}
+local disabledTable = {}
+local initialized
+
+local function OnEvent(self, event, addonName)
+ if event == "ADDON_LOADED" then
+ if lodTable[addonName] then
+ tinsert(memoryTable, lodTable[addonName])
+
+ if cpuProfiling then
+ tinsert(cpuTable, CopyTable(lodTable[addonName]))
+ end
+
+ lodTable[addonName] = nil
+ elseif disabledTable[addonName] then
+ tinsert(memoryTable, disabledTable[addonName])
+
+ if cpuProfiling then
+ tinsert(cpuTable, CopyTable(disabledTable[addonName]))
+ end
+
+ disabledTable[addonName] = nil
+ end
+ elseif not initialized and (event == "PLAYER_ENTERING_WORLD" or event == "ELVUI_FORCE_RUN") then
+ local _, name, title, enabled, loadable
+
+ for i = 1, GetNumAddOns() do
+ name, title, _, enabled, loadable = GetAddOnInfo(i)
+
+ if IsAddOnLoaded(i) then
+ tinsert(memoryTable, {i, title, 0})
+
+ if cpuProfiling then
+ tinsert(cpuTable, {i, title, 0})
+ end
+ elseif loadable then
+ lodTable[name] = {i, title, 0}
+ elseif not enabled then
+ disabledTable[name] = {i, title, 0}
+ end
+ end
+
+ initialized = true
+ self:UnregisterEvent(event)
+ elseif initialized and event == "ELVUI_FORCE_RUN" then
+ local name
+
+ for i = 1, GetNumAddOns() do
+ name = GetAddOnInfo(i)
+
+ if (lodTable[name] or disabledTable[name]) and IsAddOnLoaded(i) then
+ OnEvent(self, "ADDON_LOADED", name)
+ end
+ end
+ end
+end
+
+local function formatMem(memory)
+ if memory > 999 then
+ return format(megaByteString, memory / 1024)
+ else
+ return format(kiloByteString, memory)
+ end
+end
+
+local function sortByMemoryOrCPU(a, b)
+ if a and b then
+ return (a[3] == b[3] and a[2] < b[2]) or a[3] > b[3]
+ end
+end
+
+local function UpdateMemory()
+ UpdateAddOnMemoryUsage()
+
+ local totalMemory = 0
+ for i = 1, #memoryTable do
+ memoryTable[i][3] = GetAddOnMemoryUsage(memoryTable[i][1])
+ totalMemory = totalMemory + memoryTable[i][3]
+ end
+
+ sort(memoryTable, sortByMemoryOrCPU)
+
+ return totalMemory
+end
+
+local function UpdateCPU()
+ UpdateAddOnCPUUsage()
+
+ local totalCPU = 0
+ for i = 1, #cpuTable do
+ cpuTable[i][3] = GetAddOnCPUUsage(cpuTable[i][1])
+ totalCPU = totalCPU + cpuTable[i][3]
+ end
+
+ sort(cpuTable, sortByMemoryOrCPU)
+
+ return totalCPU
+end
+
+local function ToggleGameMenuFrame()
+ if GameMenuFrame:IsShown() then
+ PlaySound("igMainMenuQuit")
+ HideUIPanel(GameMenuFrame)
+ else
+ PlaySound("igMainMenuOpen")
+ ShowUIPanel(GameMenuFrame)
+ end
+end
+
+local function OnClick(_, btn)
+ if IsModifierKeyDown() then
+ collectgarbage("collect")
+ ResetCPUUsage()
+ elseif btn == "LeftButton" then
+ ToggleGameMenuFrame()
+ end
+end
+
+local function OnEnter(self)
+ DT:SetupTooltip(self)
+
+ local totalMemory = UpdateMemory()
+ local _, _, homeLatency = GetNetStats()
+
+ DT.tooltip:AddDoubleLine(L["Home Latency:"], format(homeLatencyString, homeLatency), 0.69, 0.31, 0.31, 0.84, 0.75, 0.65)
+ DT.tooltip:AddDoubleLine(L["Total Memory:"], formatMem(totalMemory), 0.69, 0.31, 0.31, 0.84, 0.75, 0.65)
+
+ local totalCPU
+ if cpuProfiling then
+ totalCPU = UpdateCPU()
+ DT.tooltip:AddDoubleLine(L["Total CPU:"], format(homeLatencyString, totalCPU), 0.69, 0.31, 0.31, 0.84, 0.75, 0.65)
+ end
+
+ DT.tooltip:AddLine(" ")
+
+ local addon, red, green
+
+ if IsShiftKeyDown() or not cpuProfiling then
+ for i = 1, #memoryTable do
+ addon = memoryTable[i]
+ red = addon[3] / totalMemory
+ green = 1 - red
+ DT.tooltip:AddDoubleLine(addon[2], formatMem(addon[3]), 1, 1, 1, red, green + .5, 0)
+ end
+ else
+ for i = 1, #cpuTable do
+ addon = cpuTable[i]
+ red = addon[3] / totalCPU
+ green = 1 - red
+ DT.tooltip:AddDoubleLine(addon[2], format(homeLatencyString, addon[3]), 1, 1, 1, red, green + .5, 0)
+ end
+
+ DT.tooltip:AddLine(" ")
+ DT.tooltip:AddLine(L["(Hold Shift) Memory Usage"])
+ end
+
+ DT.tooltip:AddLine(L["(Modifer Click) Collect Garbage"])
+ DT.tooltip:Show()
+ enteredFrame = true
+end
+
+local function OnLeave()
+ enteredFrame = nil
+ DT.tooltip:Hide()
+end
+
+local function OnUpdate(self, t)
+ int = int - t
+
+ if int < 0 then
+ local framerate = floor(GetFramerate() + 0.5)
+ local _, _, homeLatency = GetNetStats()
+
+ self.text:SetFormattedText("FPS: %s%d|r MS: %s%d|r",
+ statusColors[framerate >= 30 and 1 or (framerate >= 20 and framerate < 30) and 2 or (framerate >= 10 and framerate < 20) and 3 or 4],
+ framerate,
+ statusColors[homeLatency < 150 and 1 or (homeLatency >= 150 and homeLatency < 300) and 2 or (homeLatency >= 300 and homeLatency < 500) and 3 or 4],
+ homeLatency)
+
+ int = 1
+
+ if enteredFrame then
+ OnEnter(self)
+ end
+ end
+end
+
+DT:RegisterDatatext("System", {"PLAYER_ENTERING_WORLD", "ADDON_LOADED"}, OnEvent, OnUpdate, OnClick, OnEnter, OnLeave, L["System"])
\ No newline at end of file
diff --git a/ElvUI/Modules/DataTexts/Time.lua b/ElvUI/Modules/DataTexts/Time.lua
new file mode 100644
index 0000000..01074d0
--- /dev/null
+++ b/ElvUI/Modules/DataTexts/Time.lua
@@ -0,0 +1,275 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local _G = _G
+local date = date
+local next = next
+local select = select
+local time = time
+local tonumber = tonumber
+local find, format, gsub, join, utf8sub = string.find, string.format, string.gsub, string.join, string.utf8sub
+local tinsert, wipe = table.insert, table.wipe
+--WoW API / Variables
+local GetGameTime = GetGameTime
+local GetNumSavedInstances = GetNumSavedInstances
+local GetSavedInstanceInfo = GetSavedInstanceInfo
+local GetWintergraspWaitTime = GetWintergraspWaitTime
+local IsInInstance = IsInInstance
+local RequestRaidInfo = RequestRaidInfo
+local SecondsToTime = SecondsToTime
+
+local QUEUE_TIME_UNAVAILABLE = QUEUE_TIME_UNAVAILABLE
+local TIMEMANAGER_AM = TIMEMANAGER_AM
+local TIMEMANAGER_PM = TIMEMANAGER_PM
+local TIMEMANAGER_TOOLTIP_LOCALTIME = TIMEMANAGER_TOOLTIP_LOCALTIME
+local TIMEMANAGER_TOOLTIP_REALMTIME = TIMEMANAGER_TOOLTIP_REALMTIME
+local WINTERGRASP_IN_PROGRESS = WINTERGRASP_IN_PROGRESS
+
+local timeDisplayFormat = ""
+local dateDisplayFormat = ""
+local lockoutInfoFormat = "%s%s %s |cffaaaaaa(%s)"
+local lockoutColorExtended, lockoutColorNormal = {r = 0.3, g = 1, b = 0.3}, {r = .8, g = .8, b = .8}
+local lockedInstances = {raids = {}, dungeons = {}}
+local timeFormat, realmDiffSeconds, showAMPM, showSecs
+local enteredFrame, fullUpdate
+local instanceIconByName
+local numSavedInstances = 0
+
+local locale = GetLocale()
+local krcntw = locale == "koKR" or locale == "zhCN" or locale == "zhTW"
+local difficultyTag = { -- Normal, Normal, Heroic, Heroic
+ (krcntw and PLAYER_DIFFICULTY1) or utf8sub(PLAYER_DIFFICULTY1, 1, 1), -- N
+ (krcntw and PLAYER_DIFFICULTY1) or utf8sub(PLAYER_DIFFICULTY1, 1, 1), -- N
+ (krcntw and PLAYER_DIFFICULTY2) or utf8sub(PLAYER_DIFFICULTY2, 1, 1), -- H
+ (krcntw and PLAYER_DIFFICULTY2) or utf8sub(PLAYER_DIFFICULTY2, 1, 1), -- H
+}
+
+local function getRealmTimeDiff()
+ local hours, minutes = GetGameTime()
+ local localTime = date("*t")
+
+ local diffHours = localTime.hour - hours
+ local diffMinutes = localTime.min - minutes
+
+ return (diffHours * 60 + diffMinutes) * 60
+end
+
+local function GetCurrentDate(formatString, forceLocalTime, forceRealmTime)
+ if timeFormat ~= E.db.datatexts.timeFormat then
+ timeFormat = E.db.datatexts.timeFormat
+ showAMPM = find(E.db.datatexts.timeFormat, "%%p") ~= nil
+ showSecs = find(E.db.datatexts.timeFormat, "%%S") ~= nil
+ end
+
+ if showAMPM then
+ local localizedAMPM = tonumber(date("%H")) >= 12 and TIMEMANAGER_PM or TIMEMANAGER_AM
+
+ formatString = gsub(formatString, "^%%p", localizedAMPM)
+ formatString = gsub(formatString, "([^%%])%%p", "%1"..localizedAMPM)
+ end
+
+ if realmDiffSeconds ~= 0 and (E.db.datatexts.realmTime or forceRealmTime) and not forceLocalTime then
+ return date(formatString, time() - realmDiffSeconds)
+ else
+ return date(formatString)
+ end
+end
+
+local function GetInstanceImages(...)
+ local numTextures = select("#", ...) / 4
+
+ local argn, title, texture = 1
+ for i = 1, numTextures do
+ title, texture = select(argn, ...)
+ if texture ~= "" then
+ instanceIconByName[title] = texture
+ end
+ argn = argn + 4
+ end
+end
+
+local function OnEvent(self, event)
+ if event == "UPDATE_INSTANCE_INFO" then
+ local num = GetNumSavedInstances()
+
+ if num ~= numSavedInstances then
+ numSavedInstances = num or 0
+
+ if enteredFrame then
+ fullUpdate = true
+ end
+ end
+
+ return
+ end
+
+ if not realmDiffSeconds then
+ realmDiffSeconds = getRealmTimeDiff()
+
+ if realmDiffSeconds < 900 then
+ realmDiffSeconds = 0
+ end
+ end
+end
+
+local function OnClick(_, btn)
+ if btn == "RightButton" then
+ if not IsAddOnLoaded("Blizzard_TimeManager") then
+ LoadAddOn("Blizzard_TimeManager")
+ end
+ TimeManagerClockButton_OnClick(TimeManagerClockButton)
+ else
+ GameTimeFrame:Click()
+ end
+end
+
+local function OnEnter(self, skipRequest)
+ DT:SetupTooltip(self)
+
+ if not skipRequest then
+ RequestRaidInfo()
+ end
+
+ if not instanceIconByName then
+ instanceIconByName = {}
+ GetInstanceImages(CalendarEventGetTextures(1))
+ GetInstanceImages(CalendarEventGetTextures(2))
+ end
+
+ local wgtime = GetWintergraspWaitTime()
+ local _, instanceType = IsInInstance()
+ if instanceType ~= "none" then
+ wgtime = QUEUE_TIME_UNAVAILABLE
+ elseif wgtime == nil then
+ wgtime = WINTERGRASP_IN_PROGRESS
+ else
+ wgtime = SecondsToTime(wgtime, false, nil, 3)
+ end
+
+ DT.tooltip:AddDoubleLine(L["Wintergrasp"], wgtime, 1, 1, 1, lockoutColorNormal.r, lockoutColorNormal.g, lockoutColorNormal.b)
+
+ if numSavedInstances > 0 then
+ wipe(lockedInstances.raids)
+ wipe(lockedInstances.dungeons)
+
+ local name, reset, difficulty, locked, extended, isRaid, maxPlayers, difficultyLetter, buttonImg
+
+ for i = 1, numSavedInstances do
+ name, _, reset, difficulty, locked, extended, _, isRaid, maxPlayers = GetSavedInstanceInfo(i)
+
+ if name and (locked or extended) then
+ difficultyLetter = difficultyTag[not isRaid and (difficulty == 2 and 3 or 1) or difficulty]
+ buttonImg = format("|T%s%s:22:22:0:0:96:96:0:64:0:64|t ", "Interface\\LFGFrame\\LFGIcon-", instanceIconByName[name] or "Raid")
+
+ if isRaid then
+ tinsert(lockedInstances.raids, {name, reset, extended, maxPlayers, difficultyLetter, buttonImg})
+ elseif difficulty == 2 then
+ tinsert(lockedInstances.dungeons, {name, reset, extended, maxPlayers, difficultyLetter, buttonImg})
+ end
+ end
+ end
+
+ local lockoutColor, info
+
+ if next(lockedInstances.raids) then
+ DT.tooltip:AddLine(" ")
+ DT.tooltip:AddLine(L["Saved Raid(s)"])
+
+ for i = 1, #lockedInstances.raids do
+ info = lockedInstances.raids[i]
+
+ lockoutColor = info[3] and lockoutColorExtended or lockoutColorNormal
+
+ DT.tooltip:AddDoubleLine(
+ format(lockoutInfoFormat, info[6], info[4], info[5], info[1]),
+ SecondsToTime(info[2], false, nil, 3),
+ 1, 1, 1,
+ lockoutColor.r, lockoutColor.g, lockoutColor.b
+ )
+ end
+ end
+
+ if next(lockedInstances.dungeons) then
+ DT.tooltip:AddLine(" ")
+ DT.tooltip:AddLine(L["Saved Dungeon(s)"])
+
+ for i = 1, #lockedInstances.dungeons do
+ info = lockedInstances.dungeons[i]
+
+ lockoutColor = info[3] and lockoutColorExtended or lockoutColorNormal
+
+ DT.tooltip:AddDoubleLine(
+ format(lockoutInfoFormat, info[6], info[4], info[5], info[1]),
+ SecondsToTime(info[2], false, nil, 3),
+ 1, 1, 1,
+ lockoutColor.r, lockoutColor.g, lockoutColor.b
+ )
+ end
+ end
+ end
+
+ DT.tooltip:AddLine(" ")
+
+ if E.db.datatexts.realmTime then
+ DT.tooltip:AddDoubleLine(TIMEMANAGER_TOOLTIP_LOCALTIME, GetCurrentDate(E.db.datatexts.timeFormat, true), 1, 1, 1, lockoutColorNormal.r, lockoutColorNormal.g, lockoutColorNormal.b)
+ else
+ DT.tooltip:AddDoubleLine(TIMEMANAGER_TOOLTIP_REALMTIME, GetCurrentDate(E.db.datatexts.timeFormat, nil, true), 1, 1, 1, lockoutColorNormal.r, lockoutColorNormal.g, lockoutColorNormal.b)
+ end
+
+ DT.tooltip:Show()
+ enteredFrame = true
+end
+
+local function OnLeave()
+ enteredFrame = nil
+ DT.tooltip:Hide()
+end
+
+local function updateTooltipTime()
+ if E.db.datatexts.realmTime then
+ _G["DatatextTooltipTextRight" .. DT.tooltip:NumLines()]:SetText(GetCurrentDate(E.db.datatexts.timeFormat, true))
+ else
+ _G["DatatextTooltipTextRight" .. DT.tooltip:NumLines()]:SetText(GetCurrentDate(E.db.datatexts.timeFormat, nil, true))
+ end
+end
+
+local lastPanel
+local int = 5
+local function OnUpdate(self, elapsed)
+ int = int - elapsed
+
+ if int > 0 then return end
+
+ int = 1
+ lastPanel = self
+
+ if GameTimeFrame.flashInvite then
+ E:Flash(self, 0.53)
+ else
+ E:StopFlash(self)
+ end
+
+ self.text:SetText(gsub(gsub(GetCurrentDate(E.db.datatexts.timeFormat.." "..E.db.datatexts.dateFormat), ":", timeDisplayFormat), "%s", dateDisplayFormat))
+
+ if enteredFrame then
+ if fullUpdate then
+ fullUpdate = nil
+ OnEnter(self, true)
+ elseif showSecs then
+ updateTooltipTime()
+ end
+ end
+end
+
+local function ValueColorUpdate(hex)
+ timeDisplayFormat = join("", hex, ":|r")
+ dateDisplayFormat = join("", hex, " ")
+
+ if lastPanel ~= nil then
+ OnUpdate(lastPanel, 20000)
+ end
+end
+E.valueColorUpdateFuncs[ValueColorUpdate] = true
+
+DT:RegisterDatatext("Time", {"UPDATE_INSTANCE_INFO"}, OnEvent, OnUpdate, OnClick, OnEnter, OnLeave)
\ No newline at end of file
diff --git a/ElvUI/Modules/Load_Modules.xml b/ElvUI/Modules/Load_Modules.xml
new file mode 100644
index 0000000..bf58647
--- /dev/null
+++ b/ElvUI/Modules/Load_Modules.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/Maps/Load_Maps.xml b/ElvUI/Modules/Maps/Load_Maps.xml
new file mode 100644
index 0000000..ffead1c
--- /dev/null
+++ b/ElvUI/Modules/Maps/Load_Maps.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/Maps/Minimap.lua b/ElvUI/Modules/Maps/Minimap.lua
new file mode 100644
index 0000000..7c7ce63
--- /dev/null
+++ b/ElvUI/Modules/Maps/Minimap.lua
@@ -0,0 +1,533 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local M = E:GetModule("Minimap")
+local Reminder = E:GetModule("ReminderBuffs")
+
+--Lua functions
+local match, utf8sub = string.match, string.utf8sub
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local ToggleCharacter = ToggleCharacter
+local ToggleFrame = ToggleFrame
+local ToggleAchievementFrame = ToggleAchievementFrame
+local ToggleFriendsFrame = ToggleFriendsFrame
+local IsAddOnLoaded = IsAddOnLoaded
+local ToggleHelpFrame = ToggleHelpFrame
+local GetZonePVPInfo = GetZonePVPInfo
+local IsShiftKeyDown = IsShiftKeyDown
+local ToggleDropDownMenu = ToggleDropDownMenu
+local Minimap_OnClick = Minimap_OnClick
+local GetMinimapZoneText = GetMinimapZoneText
+local InCombatLockdown = InCombatLockdown
+
+local menuFrame = CreateFrame("Frame", "MinimapRightClickMenu", E.UIParent, "UIDropDownMenuTemplate")
+local menuList = {
+ {
+ text = CHARACTER_BUTTON,
+ notCheckable = 1,
+ func = function()
+ ToggleCharacter("PaperDollFrame")
+ end
+ },
+ {
+ text = SPELLBOOK_ABILITIES_BUTTON,
+ notCheckable = 1,
+ func = function()
+ ToggleFrame(SpellBookFrame)
+ end
+ },
+ {
+ text = TALENTS_BUTTON,
+ notCheckable = 1,
+ func = ToggleTalentFrame
+ },
+ {
+ text = ACHIEVEMENT_BUTTON,
+ notCheckable = 1,
+ func = ToggleAchievementFrame
+ },
+ {
+ text = QUESTLOG_BUTTON,
+ notCheckable = 1,
+ func = function()
+ ToggleFrame(QuestLogFrame)
+ end
+ },
+ {
+ text = SOCIAL_BUTTON,
+ notCheckable = 1,
+ func = function()
+ ToggleFriendsFrame(1)
+ end
+ },
+ {
+ text = L["Calendar"],
+ notCheckable = 1,
+ func = function()
+ GameTimeFrame:Click()
+ end
+ },
+ {
+ text = L["Farm Mode"],
+ notCheckable = 1,
+ func = FarmMode
+ },
+ {
+ text = BATTLEFIELD_MINIMAP,
+ notCheckable = 1,
+ func = ToggleBattlefieldMinimap
+ },
+ {
+ text = TIMEMANAGER_TITLE,
+ notCheckable = 1,
+ func = ToggleTimeManager
+ },
+ {
+ text = PLAYER_V_PLAYER,
+ notCheckable = 1,
+ func = function()
+ ToggleFrame(PVPParentFrame)
+ end
+ },
+ {
+ text = LFG_TITLE,
+ notCheckable = 1,
+ func = function()
+ ToggleFrame(LFDParentFrame)
+ end
+ },
+ {
+ text = LOOKING_FOR_RAID,
+ notCheckable = 1,
+ func = function()
+ ToggleFrame(LFRParentFrame)
+ end
+ },
+ {
+ text = MAINMENU_BUTTON,
+ notCheckable = 1,
+ func = function()
+ if GameMenuFrame:IsShown() then
+ PlaySound("igMainMenuQuit")
+ HideUIPanel(GameMenuFrame)
+ else
+ PlaySound("igMainMenuOpen")
+ ShowUIPanel(GameMenuFrame)
+ end
+ end
+ },
+ {
+ text = HELP_BUTTON,
+ notCheckable = 1,
+ func = ToggleHelpFrame
+ }
+}
+
+function M:GetLocTextColor()
+ local pvpType = GetZonePVPInfo()
+ if pvpType == "sanctuary" then
+ return 0.035, 0.58, 0.84
+ elseif pvpType == "arena" then
+ return 0.84, 0.03, 0.03
+ elseif pvpType == "friendly" then
+ return 0.05, 0.85, 0.03
+ elseif pvpType == "hostile" then
+ return 0.84, 0.03, 0.03
+ elseif pvpType == "contested" then
+ return 0.9, 0.85, 0.05
+ else
+ return 0.84, 0.03, 0.03
+ end
+end
+
+function M:ADDON_LOADED(event, addon)
+ if addon == "Blizzard_TimeManager" then
+ self:UnregisterEvent(event)
+ TimeManagerClockButton:Kill()
+ end
+end
+
+function M:Minimap_OnMouseUp(btn)
+ local position = self:GetPoint()
+ if btn == "MiddleButton" or (btn == "RightButton" and IsShiftKeyDown()) then
+ if match(position, "LEFT") then
+ EasyMenu(menuList, menuFrame, "cursor", 0, 0, "MENU", 2)
+ else
+ EasyMenu(menuList, menuFrame, "cursor", -160, 0, "MENU", 2)
+ end
+ elseif btn == "RightButton" then
+ ToggleDropDownMenu(1, nil, MiniMapTrackingDropDown, "cursor")
+ else
+ Minimap_OnClick(self)
+ end
+end
+
+function M:Minimap_OnMouseWheel(d)
+ local zoomLevel = Minimap:GetZoom()
+
+ if d > 0 and zoomLevel < 5 then
+ Minimap:SetZoom(zoomLevel + 1)
+ elseif d < 0 and zoomLevel > 0 then
+ Minimap:SetZoom(zoomLevel - 1)
+ end
+end
+
+function M:Update_ZoneText()
+ if E.db.general.minimap.locationText == "HIDE" or not E.private.general.minimap.enable then return end
+ Minimap.location:SetText(utf8sub(GetMinimapZoneText(),1,46))
+ Minimap.location:SetTextColor(self:GetLocTextColor())
+ Minimap.location:FontTemplate(E.Libs.LSM:Fetch("font", E.db.general.minimap.locationFont), E.db.general.minimap.locationFontSize, E.db.general.minimap.locationFontOutline)
+end
+
+function M:PLAYER_REGEN_ENABLED()
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED")
+ self:UpdateSettings()
+end
+
+function M:CreateFarmModeMap()
+ local fm = CreateFrame("Minimap", "FarmModeMap", E.UIParent)
+ fm:Size(E.db.farmSize)
+ fm:Point("TOP", E.UIParent, "TOP", 0, -120)
+ fm:SetClampedToScreen(true)
+ fm:CreateBackdrop("Default")
+ fm:EnableMouseWheel(true)
+ fm:SetScript("OnMouseWheel", M.Minimap_OnMouseWheel)
+ fm:SetScript("OnMouseUp", M.Minimap_OnMouseUp)
+ fm:RegisterForDrag("LeftButton", "RightButton")
+ fm:SetMovable(true)
+ fm:SetScript("OnDragStart", function(self) self:StartMoving() end)
+ fm:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
+ fm:Hide()
+
+ self.farmModeMap = fm
+
+ fm:SetScript("OnShow", function()
+ if BuffsMover and not E:HasMoverBeenMoved("BuffsMover") then
+ BuffsMover:ClearAllPoints()
+ BuffsMover:Point("TOPRIGHT", E.UIParent, "TOPRIGHT", -3, -3)
+ end
+
+ if DebuffsMover and not E:HasMoverBeenMoved("DebuffsMover") then
+ DebuffsMover:ClearAllPoints()
+ DebuffsMover:Point("TOPRIGHT", ElvUIPlayerBuffs, "BOTTOMRIGHT", 0, -3)
+ end
+
+ MinimapCluster:ClearAllPoints()
+ MinimapCluster:SetAllPoints(fm)
+
+ if IsAddOnLoaded("Routes") then
+ LibStub("AceAddon-3.0"):GetAddon("Routes"):ReparentMinimap(fm)
+ end
+
+ if IsAddOnLoaded("GatherMate") then
+ LibStub("AceAddon-3.0"):GetAddon("GatherMate"):GetModule("Display"):ReparentMinimapPins(fm)
+ end
+
+ if IsAddOnLoaded("GatherMate2") then
+ LibStub("AceAddon-3.0"):GetAddon("GatherMate2"):GetModule("Display"):ReparentMinimapPins(fm)
+ end
+ end)
+
+ fm:SetScript("OnHide", function()
+ if BuffsMover and not E:HasMoverBeenMoved("BuffsMover") then
+ E:ResetMovers(L["Player Buffs"])
+ end
+
+ if DebuffsMover and not E:HasMoverBeenMoved("DebuffsMover") then
+ E:ResetMovers(L["Player Debuffs"])
+ end
+
+ MinimapCluster:ClearAllPoints()
+ MinimapCluster:SetAllPoints(Minimap)
+
+ if IsAddOnLoaded("Routes") then
+ LibStub("AceAddon-3.0"):GetAddon("Routes"):ReparentMinimap(Minimap)
+ end
+
+ if IsAddOnLoaded("GatherMate") then
+ LibStub("AceAddon-3.0"):GetAddon("GatherMate"):GetModule("Display"):ReparentMinimapPins(Minimap)
+ end
+
+ if IsAddOnLoaded("GatherMate2") then
+ LibStub("AceAddon-3.0"):GetAddon("GatherMate2"):GetModule("Display"):ReparentMinimapPins(Minimap)
+ end
+ end)
+end
+
+local isResetting
+local function ResetZoom()
+ Minimap:SetZoom(0)
+ isResetting = nil
+end
+local function SetupZoomReset(self, zoomLevel)
+ if not isResetting and zoomLevel > 0 and E.db.general.minimap.resetZoom.enable then
+ isResetting = true
+ E:Delay(E.db.general.minimap.resetZoom.time, ResetZoom)
+ end
+end
+
+function M:UpdateSettings()
+ if InCombatLockdown() then
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ end
+
+ E.MinimapSize = E.private.general.minimap.enable and E.db.general.minimap.size or Minimap:GetWidth() + 10
+ E.MinimapWidth, E.MinimapHeight = E.MinimapSize, E.MinimapSize
+
+ if E.db.general.reminder.enable then
+ E.RBRWidth = (E.MinimapHeight + ((E.Border - E.Spacing*3) * 5) + E.Border*2) / 8
+ else
+ E.RBRWidth = 0
+ end
+
+ if E.private.general.minimap.enable then
+ Minimap:Size(E.MinimapSize, E.MinimapSize)
+ end
+
+ if LeftMiniPanel and RightMiniPanel then
+ if E.db.datatexts.minimapPanels and E.private.general.minimap.enable then
+ LeftMiniPanel:Show()
+ RightMiniPanel:Show()
+ else
+ LeftMiniPanel:Hide()
+ RightMiniPanel:Hide()
+ end
+ end
+
+ if BottomMiniPanel then
+ if E.db.datatexts.minimapBottom and E.private.general.minimap.enable then
+ BottomMiniPanel:Show()
+ else
+ BottomMiniPanel:Hide()
+ end
+ end
+
+ if BottomLeftMiniPanel then
+ if E.db.datatexts.minimapBottomLeft and E.private.general.minimap.enable then
+ BottomLeftMiniPanel:Show()
+ else
+ BottomLeftMiniPanel:Hide()
+ end
+ end
+
+ if BottomRightMiniPanel then
+ if E.db.datatexts.minimapBottomRight and E.private.general.minimap.enable then
+ BottomRightMiniPanel:Show()
+ else
+ BottomRightMiniPanel:Hide()
+ end
+ end
+
+ if TopMiniPanel then
+ if E.db.datatexts.minimapTop and E.private.general.minimap.enable then
+ TopMiniPanel:Show()
+ else
+ TopMiniPanel:Hide()
+ end
+ end
+
+ if TopLeftMiniPanel then
+ if E.db.datatexts.minimapTopLeft and E.private.general.minimap.enable then
+ TopLeftMiniPanel:Show()
+ else
+ TopLeftMiniPanel:Hide()
+ end
+ end
+
+ if TopRightMiniPanel then
+ if E.db.datatexts.minimapTopRight and E.private.general.minimap.enable then
+ TopRightMiniPanel:Show()
+ else
+ TopRightMiniPanel:Hide()
+ end
+ end
+
+ if MMHolder then
+ MMHolder:Width((Minimap:GetWidth() + E.Border*2 + E.Spacing*3) + E.RBRWidth * 2 - 2)
+
+ if E.db.datatexts.minimapPanels then
+ MMHolder:Height(Minimap:GetHeight() + (LeftMiniPanel and (LeftMiniPanel:GetHeight() + E.Border) or 24) + E.Spacing*3)
+ else
+ MMHolder:Height(Minimap:GetHeight() + E.Border + E.Spacing*3)
+ end
+ end
+
+ if Minimap.location then
+ Minimap.location:Width(E.MinimapSize)
+
+ if E.db.general.minimap.locationText ~= "SHOW" or not E.private.general.minimap.enable then
+ Minimap.location:Hide()
+ else
+ Minimap.location:Show()
+ end
+ end
+
+ if MinimapMover then
+ MinimapMover:Size(MMHolder:GetSize())
+ end
+
+ if GameTimeFrame then
+ if E.private.general.minimap.hideCalendar then
+ GameTimeFrame:Hide()
+ else
+ local pos = E.db.general.minimap.icons.calendar.position or "TOPRIGHT"
+ local scale = E.db.general.minimap.icons.calendar.scale or 1
+ GameTimeFrame:ClearAllPoints()
+ GameTimeFrame:Point(pos, Minimap, pos, E.db.general.minimap.icons.calendar.xOffset or 0, E.db.general.minimap.icons.calendar.yOffset or 0)
+ GameTimeFrame:SetScale(scale)
+ GameTimeFrame:Show()
+ end
+ end
+
+ if MiniMapMailFrame then
+ local pos = E.db.general.minimap.icons.mail.position or "TOPRIGHT"
+ local scale = E.db.general.minimap.icons.mail.scale or 1
+ MiniMapMailFrame:ClearAllPoints()
+ MiniMapMailFrame:Point(pos, Minimap, pos, E.db.general.minimap.icons.mail.xOffset or 3, E.db.general.minimap.icons.mail.yOffset or 4)
+ MiniMapMailFrame:SetScale(scale)
+ end
+
+ if MiniMapLFGFrame then
+ local pos = E.db.general.minimap.icons.lfgEye.position or "BOTTOMRIGHT"
+ local scale = E.db.general.minimap.icons.lfgEye.scale or 1
+ MiniMapLFGFrame:ClearAllPoints()
+ MiniMapLFGFrame:Point(pos, Minimap, pos, E.db.general.minimap.icons.lfgEye.xOffset or 3, E.db.general.minimap.icons.lfgEye.yOffset or 0)
+ MiniMapLFGFrame:SetScale(scale)
+ LFDSearchStatus:SetScale(scale)
+ end
+
+ if MiniMapBattlefieldFrame then
+ local pos = E.db.general.minimap.icons.battlefield.position or "BOTTOMRIGHT"
+ local scale = E.db.general.minimap.icons.battlefield.scale or 1
+ MiniMapBattlefieldFrame:ClearAllPoints()
+ MiniMapBattlefieldFrame:Point(pos, Minimap, pos, E.db.general.minimap.icons.battlefield.xOffset or 3, E.db.general.minimap.icons.battlefield.yOffset or 0)
+ MiniMapBattlefieldFrame:SetScale(scale)
+ end
+
+ if MiniMapInstanceDifficulty then
+ local pos = E.db.general.minimap.icons.difficulty.position or "TOPLEFT"
+ local scale = E.db.general.minimap.icons.difficulty.scale or 1
+ local x = E.db.general.minimap.icons.difficulty.xOffset or 0
+ local y = E.db.general.minimap.icons.difficulty.yOffset or 0
+ MiniMapInstanceDifficulty:ClearAllPoints()
+ MiniMapInstanceDifficulty:Point(pos, Minimap, pos, x, y)
+ MiniMapInstanceDifficulty:SetScale(scale)
+ end
+
+ if ElvConfigToggle then
+ if E.db.general.reminder.enable and E.db.datatexts.minimapPanels and E.private.general.minimap.enable then
+ ElvConfigToggle:Show()
+ ElvConfigToggle:Width(E.RBRWidth * 2)
+ else
+ ElvConfigToggle:Hide()
+ end
+ end
+
+ if ElvUI_ReminderBuffs then
+ Reminder:UpdateSettings()
+ end
+end
+
+local function MinimapPostDrag()
+ MinimapCluster:ClearAllPoints()
+ MinimapCluster:SetAllPoints(Minimap)
+ MinimapBackdrop:ClearAllPoints()
+ MinimapBackdrop:SetAllPoints(Minimap)
+end
+
+function M:Initialize()
+ menuFrame:SetTemplate("Transparent", true)
+
+ self:UpdateSettings()
+
+ if not E.private.general.minimap.enable then
+ Minimap:SetMaskTexture("Textures\\MinimapMask")
+ return
+ end
+
+ --Support for other mods
+ function GetMinimapShape()
+ return "SQUARE"
+ end
+
+ local mmholder = CreateFrame("Frame", "MMHolder", Minimap)
+ mmholder:Point("TOPRIGHT", E.UIParent, "TOPRIGHT", -3, -3)
+ mmholder:Width((Minimap:GetWidth() + 29) + E.RBRWidth * 2 - 2)
+ mmholder:Height(Minimap:GetHeight() + 53)
+ Minimap:ClearAllPoints()
+ if E.db.general.reminder.position == "LEFT" then
+ Minimap:Point("TOPRIGHT", mmholder, "TOPRIGHT", -E.Border, -E.Border)
+ else
+ Minimap:Point("TOPLEFT", mmholder, "TOPLEFT", E.Border, -E.Border)
+ end
+ Minimap:SetMaskTexture("Interface\\ChatFrame\\ChatFrameBackground")
+ Minimap:CreateBackdrop()
+ Minimap:SetFrameLevel(Minimap:GetFrameLevel() + 2)
+ Minimap:HookScript("OnEnter", function(mm)
+ if E.db.general.minimap.locationText ~= "MOUSEOVER" or not E.private.general.minimap.enable then return end
+ mm.location:Show()
+ end)
+
+ Minimap:HookScript("OnLeave", function(self)
+ if E.db.general.minimap.locationText ~= "MOUSEOVER" or not E.private.general.minimap.enable then return end
+ self.location:Hide()
+ end)
+
+ Minimap.location = Minimap:CreateFontString(nil, "OVERLAY")
+ Minimap.location:FontTemplate(nil, nil, "OUTLINE")
+ Minimap.location:Point("TOP", Minimap, "TOP", 0, -2)
+ Minimap.location:SetJustifyH("CENTER")
+ Minimap.location:SetJustifyV("MIDDLE")
+ if E.db.general.minimap.locationText ~= "SHOW" or not E.private.general.minimap.enable then
+ Minimap.location:Hide()
+ end
+
+ MinimapBorder:Hide()
+ MinimapBorderTop:Hide()
+ MinimapZoomIn:Hide()
+ MinimapZoomOut:Hide()
+ MiniMapVoiceChatFrame:Hide()
+ MinimapNorthTag:Kill()
+ MinimapZoneTextButton:Hide()
+ MiniMapTracking:Kill()
+ MiniMapMailBorder:Hide()
+ MiniMapMailIcon:SetTexture(E.Media.Textures.Mail)
+
+ if MiniMapBattlefieldBorder then
+ MiniMapBattlefieldBorder:Hide()
+ end
+
+ MiniMapLFGFrameBorder:Hide()
+
+ MiniMapWorldMapButton:Hide()
+
+ MiniMapInstanceDifficulty:SetParent(Minimap)
+
+ if TimeManagerClockButton then
+ TimeManagerClockButton:Kill()
+ else
+ self:RegisterEvent("ADDON_LOADED")
+ end
+
+ E:CreateMover(MMHolder, "MinimapMover", L["Minimap"], nil, nil, MinimapPostDrag, nil, nil, "maps,minimap")
+
+ Minimap:EnableMouseWheel(true)
+ Minimap:SetScript("OnMouseWheel", M.Minimap_OnMouseWheel)
+ Minimap:SetScript("OnMouseUp", M.Minimap_OnMouseUp)
+
+ self:RegisterEvent("ZONE_CHANGED_NEW_AREA", "Update_ZoneText")
+ self:RegisterEvent("ZONE_CHANGED", "Update_ZoneText")
+ self:RegisterEvent("ZONE_CHANGED_INDOORS", "Update_ZoneText")
+ self:RegisterEvent("PLAYER_ENTERING_WORLD", "Update_ZoneText")
+
+ hooksecurefunc(Minimap, "SetZoom", SetupZoomReset)
+
+ self:CreateFarmModeMap()
+
+ self.Initialized = true
+end
+
+local function InitializeCallback()
+ M:Initialize()
+end
+
+E:RegisterInitialModule(M:GetName(), InitializeCallback)
diff --git a/ElvUI/Modules/Maps/Worldmap.lua b/ElvUI/Modules/Maps/Worldmap.lua
new file mode 100644
index 0000000..84470ba
--- /dev/null
+++ b/ElvUI/Modules/Maps/Worldmap.lua
@@ -0,0 +1,259 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local M = E:GetModule("WorldMap")
+
+--Lua functions
+local find = string.find
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetCVarBool = GetCVarBool
+local GetCursorPosition = GetCursorPosition
+local GetPlayerMapPosition = GetPlayerMapPosition
+local GetUnitSpeed = GetUnitSpeed
+
+local MOUSE_LABEL = MOUSE_LABEL
+local PLAYER = PLAYER
+local WORLDMAP_SETTINGS = WORLDMAP_SETTINGS
+
+local INVERTED_POINTS = {
+ ["TOPLEFT"] = "BOTTOMLEFT",
+ ["TOPRIGHT"] = "BOTTOMRIGHT",
+ ["BOTTOMLEFT"] = "TOPLEFT",
+ ["BOTTOMRIGHT"] = "TOPRIGHT",
+ ["TOP"] = "BOTTOM",
+ ["BOTTOM"] = "TOP"
+}
+
+local function BlobFrameHide()
+ M.blobWasVisible = nil
+end
+
+local function BlobFrameShow()
+ M.blobWasVisible = true
+end
+
+function M:PLAYER_REGEN_ENABLED()
+ WorldMapBlobFrame.SetFrameLevel = nil
+ WorldMapBlobFrame.SetScale = nil
+ WorldMapBlobFrame.Hide = nil
+ WorldMapBlobFrame.Show = nil
+
+ local frameLevel = WorldMapDetailFrame:GetFrameLevel() + 1
+
+ WorldMapBlobFrame:SetParent(WorldMapFrame)
+ WorldMapBlobFrame:ClearAllPoints()
+ WorldMapBlobFrame:SetPoint("TOPLEFT", WorldMapDetailFrame)
+ WorldMapBlobFrame:SetScale(self.blobNewScale or WORLDMAP_SETTINGS.size)
+ WorldMapBlobFrame:SetFrameLevel(frameLevel)
+ WorldMapBlobFrame:SetFrameLevel(frameLevel) -- called twice to set frame level above the default limit (256)
+
+ if self.blobWasVisible then
+ WorldMapBlobFrame:Show()
+ end
+
+ if WORLDMAP_SETTINGS.selectedQuest then
+ WorldMapBlobFrame:DrawQuestBlob(WORLDMAP_SETTINGS.selectedQuest.questId, false)
+ end
+
+ if self.blobWasVisible then
+ WorldMapBlobFrame_CalculateHitTranslations()
+
+ if WORLDMAP_SETTINGS.selectedQuest and not WORLDMAP_SETTINGS.selectedQuest.completed then
+ WorldMapBlobFrame:DrawQuestBlob(WORLDMAP_SETTINGS.selectedQuest.questId, true)
+ end
+ end
+end
+
+function M:PLAYER_REGEN_DISABLED()
+ self.blobWasVisible = WorldMapFrame:IsShown() and WorldMapBlobFrame:IsShown()
+
+ WorldMapBlobFrame:SetParent(nil)
+ WorldMapBlobFrame:ClearAllPoints()
+ WorldMapBlobFrame:SetPoint("TOP", UIParent, "BOTTOM")
+ WorldMapBlobFrame:Hide()
+ WorldMapBlobFrame.Hide = BlobFrameHide
+ WorldMapBlobFrame.Show = BlobFrameShow
+ WorldMapBlobFrame.SetFrameLevel = E.noop
+ WorldMapBlobFrame.SetScale = E.noop
+
+ self.blobNewScale = nil
+end
+
+local t = 0
+local function UpdateCoords(self, elapsed)
+ t = t + elapsed
+ if t < 0.03333 then return end
+ t = 0
+
+ local x, y = GetPlayerMapPosition("player")
+
+ if self.playerCoords.x ~= x or self.playerCoords.y ~= y then
+ if x ~= 0 or y ~= 0 then
+ self.playerCoords.x = x
+ self.playerCoords.y = y
+ self.playerCoords:SetFormattedText("%s: %.2f, %.2f", PLAYER, x * 100, y * 100)
+ else
+ self.playerCoords.x = nil
+ self.playerCoords.y = nil
+ self.playerCoords:SetFormattedText("%s: %s", PLAYER, "N/A")
+ end
+ end
+
+ if WorldMapDetailFrame:IsMouseOver() then
+ local curX, curY = GetCursorPosition()
+
+ if self.mouseCoords.x ~= curX or self.mouseCoords.y ~= curY then
+ local scale = WorldMapDetailFrame:GetEffectiveScale()
+ local width, height = WorldMapDetailFrame:GetSize()
+ local centerX, centerY = WorldMapDetailFrame:GetCenter()
+ local adjustedX = (curX / scale - (centerX - (width * 0.5))) / width
+ local adjustedY = (centerY + (height * 0.5) - curY / scale) / height
+
+ if adjustedX >= 0 and adjustedY >= 0 and adjustedX <= 1 and adjustedY <= 1 then
+ self.mouseCoords.x = curX
+ self.mouseCoords.y = curY
+ self.mouseCoords:SetFormattedText("%s: %.2f, %.2f", MOUSE_LABEL, adjustedX * 100, adjustedY * 100)
+ else
+ self.mouseCoords.x = nil
+ self.mouseCoords.y = nil
+ self.mouseCoords:SetText("")
+ end
+ end
+ elseif self.mouseCoords.x then
+ self.mouseCoords.x = nil
+ self.mouseCoords.y = nil
+ self.mouseCoords:SetText("")
+ end
+end
+
+function M:PositionCoords()
+ if not self.coordsHolder then return end
+
+ local db = E.global.general.WorldMapCoordinates
+ local position = db.position
+
+ local x = find(position, "RIGHT") and -5 or 5
+ local y = find(position, "TOP") and -5 or 5
+
+ self.coordsHolder.playerCoords:ClearAllPoints()
+ self.coordsHolder.playerCoords:Point(position, WorldMapDetailFrame, position, x + db.xOffset, y + db.yOffset)
+
+ self.coordsHolder.mouseCoords:ClearAllPoints()
+ self.coordsHolder.mouseCoords:Point(position, self.coordsHolder.playerCoords, INVERTED_POINTS[position], 0, y)
+end
+
+function M:ToggleMapFramerate()
+ if WORLDMAP_SETTINGS.size == WORLDMAP_FULLMAP_SIZE or WORLDMAP_SETTINGS.size == WORLDMAP_QUESTLIST_SIZE then
+ WorldMapFrame:SetAttribute("UIPanelLayout-area", "center")
+ WorldMapFrame:SetAttribute("UIPanelLayout-allowOtherPanels", true)
+
+ WorldMapFrame:SetScale(1)
+ end
+end
+
+function M:CheckMovement()
+ if not WorldMapFrame:IsShown() then return end
+
+ if GetUnitSpeed("player") ~= 0 and not WorldMapPositioningGuide:IsMouseOver() then
+ WorldMapFrame:SetAlpha(E.global.general.mapAlphaWhenMoving)
+ WorldMapBlobFrame:SetFillAlpha(128 * E.global.general.mapAlphaWhenMoving)
+ WorldMapBlobFrame:SetBorderAlpha(192 * E.global.general.mapAlphaWhenMoving)
+ else
+ WorldMapFrame:SetAlpha(1)
+ WorldMapBlobFrame:SetFillAlpha(128)
+ WorldMapBlobFrame:SetBorderAlpha(192)
+ end
+end
+
+function M:UpdateMapAlpha()
+ if (not E.global.general.fadeMapWhenMoving or E.global.general.mapAlphaWhenMoving >= 1) and self.MovingTimer then
+ self:CancelTimer(self.MovingTimer)
+ self.MovingTimer = nil
+
+ WorldMapFrame:SetAlpha(1)
+ WorldMapBlobFrame:SetFillAlpha(128)
+ WorldMapBlobFrame:SetBorderAlpha(192)
+ elseif E.global.general.fadeMapWhenMoving and E.global.general.mapAlphaWhenMoving < 1 and not self.MovingTimer then
+ self.MovingTimer = self:ScheduleRepeatingTimer("CheckMovement", 0.2)
+ end
+end
+
+function M:Initialize()
+ self:UpdateMapAlpha()
+
+ if not E.private.worldmap.enable then return end
+
+ if E.global.general.WorldMapCoordinates.enable then
+ local coordsHolder = CreateFrame("Frame", "ElvUI_CoordsHolder", WorldMapFrame)
+ coordsHolder:SetFrameLevel(WORLDMAP_POI_FRAMELEVEL + 100)
+ coordsHolder:SetFrameStrata(WorldMapDetailFrame:GetFrameStrata())
+
+ coordsHolder.playerCoords = coordsHolder:CreateFontString(nil, "OVERLAY")
+ coordsHolder.playerCoords:SetTextColor(1, 1, 0)
+ coordsHolder.playerCoords:SetFontObject(NumberFontNormal)
+ coordsHolder.playerCoords:SetPoint("BOTTOMLEFT", WorldMapDetailFrame, "BOTTOMLEFT", 5, 5)
+ coordsHolder.playerCoords:SetFormattedText("%s: 0, 0", PLAYER)
+
+ coordsHolder.mouseCoords = coordsHolder:CreateFontString(nil, "OVERLAY")
+ coordsHolder.mouseCoords:SetTextColor(1, 1, 0)
+ coordsHolder.mouseCoords:SetFontObject(NumberFontNormal)
+ coordsHolder.mouseCoords:SetPoint("BOTTOMLEFT", coordsHolder.playerCoords, "TOPLEFT", 0, 5)
+
+ coordsHolder:SetScript("OnUpdate", UpdateCoords)
+
+ self.coordsHolder = coordsHolder
+ self:PositionCoords()
+ end
+
+ if E.global.general.smallerWorldMap or (E.private.skins.blizzard.enable and E.private.skins.blizzard.worldmap) then
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ self:RegisterEvent("PLAYER_REGEN_DISABLED")
+ end
+
+ WorldMapFrame:EnableMouse(false)
+ WorldMapFrame.EnableMouse = E.noop
+
+ if E.global.general.smallerWorldMap then
+ BlackoutWorld:SetTexture(nil)
+
+ WorldMapFrame:SetParent(UIParent)
+ WorldMapFrame.SetParent = E.noop
+
+ WorldMapFrame:EnableKeyboard(false)
+ WorldMapFrame.EnableKeyboard = E.noop
+
+ if not GetCVarBool("miniWorldMap") then
+ ShowUIPanel(WorldMapFrame)
+ self:ToggleMapFramerate()
+ HideUIPanel(WorldMapFrame)
+ end
+
+ self:SecureHook("ToggleMapFramerate")
+
+ hooksecurefunc(WorldMapDetailFrame, "SetScale", function(_, scale)
+ self.blobNewScale = scale
+ end)
+
+ DropDownList1:HookScript("OnShow", function(self)
+ if self:GetScale() ~= UIParent:GetScale() then
+ self:SetScale(UIParent:GetScale())
+ end
+ end)
+
+ self:RawHook("WorldMapQuestPOI_OnLeave", function()
+ WorldMapPOIFrame.allowBlobTooltip = true
+ WorldMapTooltip:Hide()
+ end, true)
+
+ -- WorldMapTooltip:SetFrameLevel(WORLDMAP_POI_FRAMELEVEL + 110)
+ -- WorldMapCompareTooltip1:SetFrameLevel(WORLDMAP_POI_FRAMELEVEL + 110)
+ -- WorldMapCompareTooltip2:SetFrameLevel(WORLDMAP_POI_FRAMELEVEL + 110)
+ end
+
+ self.Initialized = true
+end
+
+local function InitializeCallback()
+ M:Initialize()
+end
+
+E:RegisterInitialModule(M:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Misc/AFK.lua b/ElvUI/Modules/Misc/AFK.lua
new file mode 100644
index 0000000..d106906
--- /dev/null
+++ b/ElvUI/Modules/Misc/AFK.lua
@@ -0,0 +1,348 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local mod = E:GetModule("AFK")
+local CH = E:GetModule("Chat")
+
+--Lua functions
+local _G = _G
+local tostring = tostring
+local floor = math.floor
+local format, gsub, sub, upper = string.format, string.gsub, string.sub, string.upper
+--WoW API / Variables
+local ChatHistory_GetAccessID = ChatHistory_GetAccessID
+local Chat_GetChatCategory = Chat_GetChatCategory
+local CinematicFrame = CinematicFrame
+local CreateFrame = CreateFrame
+local GetBattlefieldStatus = GetBattlefieldStatus
+local GetColoredName = GetColoredName
+local GetGuildInfo = GetGuildInfo
+local GetScreenHeight = GetScreenHeight
+local GetScreenWidth = GetScreenWidth
+local GetTime = GetTime
+local InCombatLockdown = InCombatLockdown
+local IsInGuild = IsInGuild
+local IsShiftKeyDown = IsShiftKeyDown
+local MoveViewLeftStart = MoveViewLeftStart
+local MoveViewLeftStop = MoveViewLeftStop
+local MovieFrame = MovieFrame
+local Screenshot = Screenshot
+local SetCVar = SetCVar
+local UnitCastingInfo = UnitCastingInfo
+local UnitIsAFK = UnitIsAFK
+
+local AFK, DND = AFK, DND
+local CHAT_BN_CONVERSATION_GET_LINK = CHAT_BN_CONVERSATION_GET_LINK
+local MAX_WOW_CHAT_CHANNELS = MAX_WOW_CHAT_CHANNELS
+
+local cameraSpeed = 0.035
+
+local ignoreKeys = {
+ ["LALT"] = true,
+ ["LSHIFT"] = true,
+ ["RSHIFT"] = true
+}
+local printKeys = {
+ ["PRINTSCREEN"] = true,
+}
+
+if E.isMacClient then
+ printKeys[_G["KEY_PRINTSCREEN_MAC"]] = true
+end
+
+function mod:UpdateTimer()
+ local time = GetTime() - self.startTime
+ self.AFKMode.bottom.time:SetFormattedText("%02d:%02d", floor(time / 60), time % 60)
+end
+
+local function StopAnimation(self)
+ self:SetSequenceTime(0, 0)
+ self:SetScript("OnUpdate", nil)
+ self:SetScript("OnAnimFinished", nil)
+end
+
+local function UpdateAnimation(self, elapsed)
+ self.animTime = self.animTime + (elapsed * 1000)
+ self:SetSequenceTime(67, self.animTime)
+
+ if self.animTime >= 3000 then
+ StopAnimation(self)
+ end
+end
+
+local function OnAnimFinished(self)
+ if self.animTime > 500 then
+ StopAnimation(self)
+ end
+end
+
+function mod:SetAFK(status)
+ if status and not self.isAFK then
+ if InspectFrame then
+ InspectFrame:Hide()
+ end
+
+ UIParent:Hide()
+ self.AFKMode:Show()
+
+ E.global.afkEnabled = true
+
+ MoveViewLeftStart(cameraSpeed)
+
+ if IsInGuild() then
+ local guildName, guildRankName = GetGuildInfo("player")
+ self.AFKMode.bottom.guild:SetFormattedText("%s - %s", guildName, guildRankName)
+ else
+ self.AFKMode.bottom.guild:SetText(L["No Guild"])
+ end
+
+ self.startTime = GetTime()
+ self.timer = self:ScheduleRepeatingTimer("UpdateTimer", 1)
+
+ self.AFKMode.chat:RegisterEvent("CHAT_MSG_WHISPER")
+ self.AFKMode.chat:RegisterEvent("CHAT_MSG_BN_WHISPER")
+ self.AFKMode.chat:RegisterEvent("CHAT_MSG_BN_CONVERSATION")
+ self.AFKMode.chat:RegisterEvent("CHAT_MSG_GUILD")
+
+ self.AFKMode.bottom.model:SetModelScale(1)
+ self.AFKMode.bottom.model:RefreshUnit()
+ self.AFKMode.bottom.model:SetModelScale(0.8)
+
+ self.AFKMode.bottom.model.animTime = 0
+ self.AFKMode.bottom.model:SetScript("OnUpdate", UpdateAnimation)
+ self.AFKMode.bottom.model:SetScript("OnAnimFinished", OnAnimFinished)
+
+ self.isAFK = true
+ elseif not status and self.isAFK then
+ self.AFKMode:Hide()
+ UIParent:Show()
+
+ E.global.afkEnabled = nil
+
+ MoveViewLeftStop()
+
+ self:CancelTimer(self.timer)
+ self.AFKMode.bottom.time:SetText("00:00")
+
+ self.AFKMode.chat:UnregisterEvent("CHAT_MSG_WHISPER")
+ self.AFKMode.chat:UnregisterEvent("CHAT_MSG_BN_WHISPER")
+ self.AFKMode.chat:UnregisterEvent("CHAT_MSG_BN_CONVERSATION")
+ self.AFKMode.chat:UnregisterEvent("CHAT_MSG_GUILD")
+ self.AFKMode.chat:Clear()
+
+ self.isAFK = false
+ end
+end
+
+function mod:OnEvent(event, ...)
+ if event == "PLAYER_REGEN_DISABLED" or event == "LFG_PROPOSAL_SHOW" or event == "UPDATE_BATTLEFIELD_STATUS" then
+ if event == "UPDATE_BATTLEFIELD_STATUS" then
+ local status = GetBattlefieldStatus(...)
+ if status == "confirm" then
+ self:SetAFK(false)
+ end
+ else
+ self:SetAFK(false)
+ end
+
+ if event == "PLAYER_REGEN_DISABLED" then
+ self:RegisterEvent("PLAYER_REGEN_ENABLED", "OnEvent")
+ end
+ return
+ end
+
+ if event == "PLAYER_REGEN_ENABLED" then
+ self:ScheduleTimer("OnEvent", 10)
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED")
+ return
+ end
+
+ if not E.db.general.afk then return end
+ if InCombatLockdown() or CinematicFrame:IsShown() or MovieFrame:IsShown() then return end
+ if UnitCastingInfo("player") ~= nil then
+ --Don't activate afk if player is crafting stuff, check back in 30 seconds
+ self:ScheduleTimer("OnEvent", 30)
+ return
+ end
+
+ self:SetAFK(UnitIsAFK("player"))
+end
+
+function mod:Toggle()
+ if E.db.general.afk then
+ self:RegisterEvent("PLAYER_FLAGS_CHANGED", "OnEvent")
+ self:RegisterEvent("PLAYER_REGEN_DISABLED", "OnEvent")
+ self:RegisterEvent("LFG_PROPOSAL_SHOW", "OnEvent")
+ self:RegisterEvent("UPDATE_BATTLEFIELD_STATUS", "OnEvent")
+
+ SetCVar("autoClearAFK", "1")
+ else
+ self:UnregisterEvent("PLAYER_FLAGS_CHANGED")
+ self:UnregisterEvent("PLAYER_REGEN_DISABLED")
+ self:UnregisterEvent("LFG_PROPOSAL_SHOW")
+ self:UnregisterEvent("UPDATE_BATTLEFIELD_STATUS")
+
+ self:CancelAllTimers()
+ end
+end
+
+local function OnKeyDown(_, key)
+ if ignoreKeys[key] then return end
+
+ if printKeys[key] then
+ Screenshot()
+ else
+ mod:SetAFK(false)
+ mod:ScheduleTimer("OnEvent", 60)
+ end
+end
+
+local function Chat_OnMouseWheel(self, delta)
+ if delta > 0 then
+ if IsShiftKeyDown() then
+ self:ScrollToTop()
+ else
+ self:ScrollUp()
+ end
+ elseif delta < 0 then
+ if IsShiftKeyDown() then
+ self:ScrollToBottom()
+ else
+ self:ScrollDown()
+ end
+ end
+end
+
+local function Chat_OnEvent(self, event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)
+ local coloredName = GetColoredName(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)
+ local chatType = sub(event, 10)
+ local info = ChatTypeInfo[chatType]
+
+ local chatGroup = Chat_GetChatCategory(chatType)
+ local chatTarget
+ if chatGroup == "BN_CONVERSATION" then
+ chatTarget = tostring(arg8)
+ elseif chatGroup == "WHISPER" or chatGroup == "BN_WHISPER" then
+ chatTarget = upper(arg2)
+ end
+
+ local playerLink
+ if chatType ~= "BN_WHISPER" and chatType ~= "BN_CONVERSATION" then
+ playerLink = "|Hplayer:"..arg2..":"..arg11..":"..chatGroup..(chatTarget and ":"..chatTarget or "").."|h"
+ else
+ playerLink = "|HBNplayer:"..arg2..":"..arg13..":"..arg11..":"..chatGroup..(chatTarget and ":"..chatTarget or "").."|h"
+ end
+
+ arg1 = gsub(arg1, "%%", "%%%%")
+
+ local body = format(_G["CHAT_"..chatType.."_GET"]..arg1, playerLink.."["..coloredName.."]".."|h")
+
+ if chatGroup == "BN_CONVERSATION" then
+ body = format(CHAT_BN_CONVERSATION_GET_LINK, arg8, MAX_WOW_CHAT_CHANNELS + arg8)..body
+ end
+
+ local accessID = ChatHistory_GetAccessID(chatGroup, chatTarget)
+ local typeID = ChatHistory_GetAccessID(chatType, chatTarget)
+
+ if E.db.chat.shortChannels then
+ body = gsub(body, "|Hchannel:(.-)|h%[(.-)%]|h", CH.ShortChannel)
+ body = gsub(body, "^(.-|h) "..L["whispers"], "%1")
+ body = gsub(body, "<"..AFK..">", "[|cffFF0000"..AFK.."|r] ")
+ body = gsub(body, "<"..DND..">", "[|cffE7E716"..DND.."|r] ")
+ body = gsub(body, "%[BN_CONVERSATION:", "%[".."")
+ end
+
+ if CH.db ~= nil and CH.db.timeStampFormat ~= "NONE" then
+ local timeStamp = BetterDate(CH.db.timeStampFormat, time())
+
+ if CH.db.useCustomTimeColor then
+ local color = CH.db.customTimeColor
+ local hexColor = E:RGBToHex(color.r, color.g, color.b)
+ body = format("%s[%s]|r %s", hexColor, timeStamp, body)
+ else
+ body = format("[%s] %s", timeStamp, body)
+ end
+ end
+
+ self:AddMessage(body, info.r, info.g, info.b, info.id, false, accessID, typeID)
+end
+
+function mod:Initialize()
+ self.AFKMode = CreateFrame("Frame", "ElvUIAFKFrame")
+ self.AFKMode:SetFrameLevel(1)
+ self.AFKMode:SetScale(UIParent:GetScale())
+ self.AFKMode:SetAllPoints(UIParent)
+ self.AFKMode:Hide()
+ self.AFKMode:EnableKeyboard(true)
+ self.AFKMode:SetScript("OnKeyDown", OnKeyDown)
+
+ self.AFKMode.chat = CreateFrame("ScrollingMessageFrame", "AFKChat", self.AFKMode)
+ self.AFKMode.chat:Size(500, 200)
+ self.AFKMode.chat:Point("TOPLEFT", self.AFKMode, "TOPLEFT", 4, -3)
+ self.AFKMode.chat:FontTemplate()
+ self.AFKMode.chat:SetJustifyH("LEFT")
+ self.AFKMode.chat:SetMaxLines(500)
+ self.AFKMode.chat:EnableMouseWheel(true)
+ self.AFKMode.chat:SetFading(false)
+ self.AFKMode.chat:SetMovable(true)
+ self.AFKMode.chat:EnableMouse(true)
+ self.AFKMode.chat:SetClampedToScreen(true)
+ self.AFKMode.chat:SetClampRectInsets(-4, 3, 3, -4)
+ self.AFKMode.chat:RegisterForDrag("LeftButton")
+ self.AFKMode.chat:SetScript("OnDragStart", self.AFKMode.chat.StartMoving)
+ self.AFKMode.chat:SetScript("OnDragStop", self.AFKMode.chat.StopMovingOrSizing)
+ self.AFKMode.chat:SetScript("OnMouseWheel", Chat_OnMouseWheel)
+ self.AFKMode.chat:SetScript("OnEvent", Chat_OnEvent)
+
+ self.AFKMode.bottom = CreateFrame("Frame", nil, self.AFKMode)
+ self.AFKMode.bottom:SetFrameLevel(0)
+ self.AFKMode.bottom:SetTemplate("Transparent")
+ self.AFKMode.bottom:Point("BOTTOM", self.AFKMode, "BOTTOM", 0, -E.Border)
+ self.AFKMode.bottom:Width(GetScreenWidth() + (E.Border*2))
+ self.AFKMode.bottom:Height(GetScreenHeight() * 0.1)
+
+ self.AFKMode.bottom.logo = self.AFKMode:CreateTexture(nil, "OVERLAY")
+ self.AFKMode.bottom.logo:Size(320, 150)
+ self.AFKMode.bottom.logo:Point("CENTER", self.AFKMode.bottom, "CENTER", 0, 50)
+ self.AFKMode.bottom.logo:SetTexture(E.Media.Textures.Logo)
+
+ self.AFKMode.bottom.faction = self.AFKMode.bottom:CreateTexture(nil, "OVERLAY")
+ self.AFKMode.bottom.faction:Point("BOTTOMLEFT", self.AFKMode.bottom, "BOTTOMLEFT", -20, -16)
+ self.AFKMode.bottom.faction:SetTexture("Interface\\AddOns\\ElvUI\\media\\textures\\"..E.myfaction.."-Logo")
+ self.AFKMode.bottom.faction:Size(140)
+
+ local classColor = E.media.herocolor
+ self.AFKMode.bottom.name = self.AFKMode.bottom:CreateFontString(nil, "OVERLAY")
+ self.AFKMode.bottom.name:FontTemplate(nil, 20)
+ self.AFKMode.bottom.name:SetFormattedText("%s - %s", E.myname, E.myrealm)
+ self.AFKMode.bottom.name:Point("TOPLEFT", self.AFKMode.bottom.faction, "TOPRIGHT", -10, -28)
+ self.AFKMode.bottom.name:SetTextColor(classColor.r, classColor.g, classColor.b)
+
+ self.AFKMode.bottom.guild = self.AFKMode.bottom:CreateFontString(nil, "OVERLAY")
+ self.AFKMode.bottom.guild:FontTemplate(nil, 20)
+ self.AFKMode.bottom.guild:SetText(L["No Guild"])
+ self.AFKMode.bottom.guild:Point("TOPLEFT", self.AFKMode.bottom.name, "BOTTOMLEFT", 0, -6)
+ self.AFKMode.bottom.guild:SetTextColor(0.7, 0.7, 0.7)
+
+ self.AFKMode.bottom.time = self.AFKMode.bottom:CreateFontString(nil, "OVERLAY")
+ self.AFKMode.bottom.time:FontTemplate(nil, 20)
+ self.AFKMode.bottom.time:SetText("00:00")
+ self.AFKMode.bottom.time:Point("TOPLEFT", self.AFKMode.bottom.guild, "BOTTOMLEFT", 0, -6)
+ self.AFKMode.bottom.time:SetTextColor(0.7, 0.7, 0.7)
+
+ self.AFKMode.bottom.model = CreateFrame("PlayerModel", "ElvUIAFKPlayerModel", self.AFKMode.bottom)
+ self.AFKMode.bottom.model:Point("BOTTOMRIGHT", self.AFKMode.bottom, "BOTTOMRIGHT", 120, -100)
+ self.AFKMode.bottom.model:Size(800)
+ self.AFKMode.bottom.model:SetFacing(6)
+ self.AFKMode.bottom.model:SetUnit("player")
+
+ if E.db.general.afk then
+ self:Toggle()
+ end
+
+ self.Initialized = true
+end
+
+local function InitializeCallback()
+ mod:Initialize()
+end
+
+E:RegisterModule(mod:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Misc/ChatBubbles.lua b/ElvUI/Modules/Misc/ChatBubbles.lua
new file mode 100644
index 0000000..e6419cd
--- /dev/null
+++ b/ElvUI/Modules/Misc/ChatBubbles.lua
@@ -0,0 +1,262 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local M = E:GetModule("Misc")
+local CH = E:GetModule("Chat")
+
+--Lua functions
+local select, unpack = select, unpack
+local format, gmatch, gsub, lower, match = string.format, string.gmatch, string.gsub, string.lower, string.match
+--WoW API / Variables
+local GetPlayerInfoByGUID = GetPlayerInfoByGUID
+local WorldFrame = WorldFrame
+local WorldGetChildren = WorldFrame.GetChildren
+local WorldGetNumChildren = WorldFrame.GetNumChildren
+
+--Message caches
+local messageToGUID = {}
+local messageToSender = {}
+
+function M:UpdateBubbleBorder()
+ if not self.text then return end
+
+ if E.private.general.chatBubbles == "backdrop" then
+ if E.PixelMode then
+ self:SetBackdropBorderColor(self.text:GetTextColor())
+ else
+ local r, g, b = self.text:GetTextColor()
+ self.bordertop:SetTexture(r, g, b)
+ self.borderbottom:SetTexture(r, g, b)
+ self.borderleft:SetTexture(r, g, b)
+ self.borderright:SetTexture(r, g, b)
+ end
+ end
+
+ local text = self.text:GetText()
+ if self.Name then
+ self.Name:SetText("") --Always reset it
+ if text and E.private.general.chatBubbleName then
+ M:AddChatBubbleName(self, messageToGUID[text], messageToSender[text])
+ end
+ end
+
+ if E.private.chat.enable and E.private.general.classColorMentionsSpeech then
+ if text and match(text, "%s-%S+%s*") then
+ local classColorTable, lowerCaseWord, isFirstWord, rebuiltString, tempWord, wordMatch, classMatch
+
+ for word in gmatch(text, "%s-%S+%s*") do
+ tempWord = gsub(word, "^[%s%p]-([^%s%p]+)([%-]?[^%s%p]-)[%s%p]*$", "%1%2")
+ lowerCaseWord = lower(tempWord)
+
+ classMatch = CH.ClassNames[lowerCaseWord]
+ wordMatch = classMatch and lowerCaseWord
+
+ if wordMatch and not E.global.chat.classColorMentionExcludedNames[wordMatch] then
+ classColorTable = E.media.herocolor
+ word = gsub(word, gsub(tempWord, "%-", "%%-"), format("\124cff%.2x%.2x%.2x%s\124r", classColorTable.r*255, classColorTable.g*255, classColorTable.b*255, tempWord))
+ end
+
+ if not isFirstWord then
+ rebuiltString = word
+ isFirstWord = true
+ else
+ rebuiltString = format("%s%s", rebuiltString, word)
+ end
+ end
+
+ if rebuiltString then
+ self.text:SetText(rebuiltString)
+ end
+ end
+ end
+end
+
+function M:AddChatBubbleName(chatBubble, guid, name)
+ if not name then return end
+
+ local color
+ if guid and guid ~= "" then
+ local _, class = GetPlayerInfoByGUID(guid)
+ if class then
+ color = E:RGBToHex(E.media.herocolor.r, E.media.herocolor.g, E.media.herocolor.b)
+ end
+ else
+ color = "|cffffffff"
+ end
+
+ chatBubble.Name:SetFormattedText("%s%s|r", color, name)
+end
+
+function M:SkinBubble(frame)
+ local mult = E.mult * UIParent:GetScale()
+ for i = 1, frame:GetNumRegions() do
+ local region = select(i, frame:GetRegions())
+ if region:IsObjectType("Texture") then
+ region:SetTexture(nil)
+ elseif region:IsObjectType("FontString") then
+ frame.text = region
+ end
+ end
+
+ local name = frame:CreateFontString(nil, "OVERLAY")
+ if E.private.general.chatBubbles == "backdrop" then
+ name:SetPoint("TOPLEFT", 5, E.PixelMode and 15 or 18)
+ else
+ name:SetPoint("TOPLEFT", 5, 6)
+ end
+ name:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", -5, -5)
+ name:SetJustifyH("LEFT")
+ name:FontTemplate(E.Libs.LSM:Fetch("font", E.private.general.chatBubbleFont), E.private.general.chatBubbleFontSize * 0.85, E.private.general.chatBubbleFontOutline)
+ frame.Name = name
+
+ if E.private.general.chatBubbles == "backdrop" then
+ if E.PixelMode then
+ frame:SetBackdrop({
+ bgFile = E.media.blankTex,
+ edgeFile = E.media.blankTex,
+ tile = false, tileSize = 0, edgeSize = mult,
+ insets = {left = 0, right = 0, top = 0, bottom = 0}
+ })
+ frame:SetBackdropColor(unpack(E.media.backdropfadecolor))
+ frame:SetBackdropBorderColor(0, 0, 0)
+ else
+ frame:SetBackdrop(nil)
+ end
+
+ local r, g, b = frame.text:GetTextColor()
+ if not E.PixelMode then
+ local mult2 = mult * 2
+ local mult3 = mult * 3
+
+ frame.backdrop = frame:CreateTexture(nil, "BACKGROUND")
+ frame.backdrop:SetAllPoints(frame)
+ frame.backdrop:SetTexture(unpack(E.media.backdropfadecolor))
+
+ frame.bordertop = frame:CreateTexture(nil, "ARTWORK")
+ frame.bordertop:SetPoint("TOPLEFT", frame, "TOPLEFT", -mult2, mult2)
+ frame.bordertop:SetPoint("TOPRIGHT", frame, "TOPRIGHT", mult2, mult2)
+ frame.bordertop:SetHeight(mult)
+ frame.bordertop:SetTexture(r, g, b)
+
+ frame.bordertop.backdrop = frame:CreateTexture(nil, "BORDER")
+ frame.bordertop.backdrop:SetPoint("TOPLEFT", frame.bordertop, "TOPLEFT", -mult, mult)
+ frame.bordertop.backdrop:SetPoint("TOPRIGHT", frame.bordertop, "TOPRIGHT", mult, mult)
+ frame.bordertop.backdrop:SetHeight(mult3)
+ frame.bordertop.backdrop:SetTexture(0, 0, 0)
+
+ frame.borderbottom = frame:CreateTexture(nil, "ARTWORK")
+ frame.borderbottom:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", -mult2, -mult2)
+ frame.borderbottom:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", mult2, -mult2)
+ frame.borderbottom:SetHeight(mult)
+ frame.borderbottom:SetTexture(r, g, b)
+
+ frame.borderbottom.backdrop = frame:CreateTexture(nil, "BORDER")
+ frame.borderbottom.backdrop:SetPoint("BOTTOMLEFT", frame.borderbottom, "BOTTOMLEFT", -mult, -mult)
+ frame.borderbottom.backdrop:SetPoint("BOTTOMRIGHT", frame.borderbottom, "BOTTOMRIGHT", mult, -mult)
+ frame.borderbottom.backdrop:SetHeight(mult3)
+ frame.borderbottom.backdrop:SetTexture(0, 0, 0)
+
+ frame.borderleft = frame:CreateTexture(nil, "ARTWORK")
+ frame.borderleft:SetPoint("TOPLEFT", frame, "TOPLEFT", -mult2, mult2)
+ frame.borderleft:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", mult2, -mult2)
+ frame.borderleft:SetWidth(mult)
+ frame.borderleft:SetTexture(r, g, b)
+
+ frame.borderleft.backdrop = frame:CreateTexture(nil, "BORDER")
+ frame.borderleft.backdrop:SetPoint("TOPLEFT", frame.borderleft, "TOPLEFT", -mult, mult)
+ frame.borderleft.backdrop:SetPoint("BOTTOMLEFT", frame.borderleft, "BOTTOMLEFT", -mult, -mult)
+ frame.borderleft.backdrop:SetWidth(mult3)
+ frame.borderleft.backdrop:SetTexture(0, 0, 0)
+
+ frame.borderright = frame:CreateTexture(nil, "ARTWORK")
+ frame.borderright:SetPoint("TOPRIGHT", frame, "TOPRIGHT", mult2, mult2)
+ frame.borderright:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -mult2, -mult2)
+ frame.borderright:SetWidth(mult)
+ frame.borderright:SetTexture(r, g, b)
+
+ frame.borderright.backdrop = frame:CreateTexture(nil, "BORDER")
+ frame.borderright.backdrop:SetPoint("TOPRIGHT", frame.borderright, "TOPRIGHT", mult, mult)
+ frame.borderright.backdrop:SetPoint("BOTTOMRIGHT", frame.borderright, "BOTTOMRIGHT", mult, -mult)
+ frame.borderright.backdrop:SetWidth(mult3)
+ frame.borderright.backdrop:SetTexture(0, 0, 0)
+ else
+ frame:SetBackdropColor(unpack(E.media.backdropfadecolor))
+ frame:SetBackdropBorderColor(r, g, b)
+ end
+
+ frame.text:FontTemplate(E.LSM:Fetch("font", E.private.general.chatBubbleFont), E.private.general.chatBubbleFontSize, E.private.general.chatBubbleFontOutline)
+ elseif E.private.general.chatBubbles == "backdrop_noborder" then
+ frame:SetBackdrop(nil)
+
+ if not frame.backdrop then
+ frame.backdrop = frame:CreateTexture(nil, "ARTWORK")
+ frame.backdrop:SetInside(frame, 4, 4)
+ frame.backdrop:SetTexture(unpack(E.media.backdropfadecolor))
+ end
+ frame.text:FontTemplate(E.LSM:Fetch("font", E.private.general.chatBubbleFont), E.private.general.chatBubbleFontSize, E.private.general.chatBubbleFontOutline)
+
+ frame:SetClampedToScreen(false)
+ elseif E.private.general.chatBubbles == "nobackdrop" then
+ frame:SetBackdrop(nil)
+ frame.text:FontTemplate(E.LSM:Fetch("font", E.private.general.chatBubbleFont), E.private.general.chatBubbleFontSize, E.private.general.chatBubbleFontOutline)
+ frame:SetClampedToScreen(false)
+ end
+
+ frame:HookScript("OnShow", M.UpdateBubbleBorder)
+ frame:SetFrameStrata("DIALOG")
+ M.UpdateBubbleBorder(frame)
+
+ frame.isSkinnedElvUI = true
+end
+
+function M:IsChatBubble(frame)
+ for i = 1, frame:GetNumRegions() do
+ local region = select(i, frame:GetRegions())
+ if region.GetTexture and region:GetTexture() and region:GetTexture() == [[Interface\Tooltips\ChatBubble-Background]] then
+ return true
+ end
+ end
+end
+
+local function ChatBubble_OnEvent(self, event, msg, sender, _, _, _, _, _, _, _, _, _, guid)
+ if not E.private.general.chatBubbleName then return end
+
+ messageToGUID[msg] = guid
+ messageToSender[msg] = sender
+end
+
+local lastChildern, numChildren = 0, 0
+local function findChatBubbles(...)
+ for i = lastChildern + 1, numChildren do
+ local frame = select(i, ...)
+ if not frame.isSkinnedElvUI and M:IsChatBubble(frame) then
+ M:SkinBubble(frame)
+ end
+ end
+end
+
+local function ChatBubble_OnUpdate(self, elapsed)
+ self.lastupdate = self.lastupdate + elapsed
+ if self.lastupdate < .1 then return end
+ self.lastupdate = 0
+
+ numChildren = WorldGetNumChildren(WorldFrame)
+ if lastChildern ~= numChildren then
+ findChatBubbles(WorldGetChildren(WorldFrame))
+ lastChildern = numChildren
+ end
+end
+
+function M:LoadChatBubbles()
+ if E.private.general.chatBubbles == "disabled" then return end
+
+ self.BubbleFrame = CreateFrame("Frame")
+ self.BubbleFrame.lastupdate = -2 -- wait 2 seconds before hooking frames
+
+ self.BubbleFrame:RegisterEvent("CHAT_MSG_SAY")
+ self.BubbleFrame:RegisterEvent("CHAT_MSG_YELL")
+ self.BubbleFrame:RegisterEvent("CHAT_MSG_PARTY")
+ self.BubbleFrame:RegisterEvent("CHAT_MSG_PARTY_LEADER")
+ self.BubbleFrame:RegisterEvent("CHAT_MSG_MONSTER_SAY")
+ self.BubbleFrame:RegisterEvent("CHAT_MSG_MONSTER_YELL")
+ self.BubbleFrame:SetScript("OnEvent", ChatBubble_OnEvent)
+ self.BubbleFrame:SetScript("OnUpdate", ChatBubble_OnUpdate)
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Misc/DebugTools.lua b/ElvUI/Modules/Misc/DebugTools.lua
new file mode 100644
index 0000000..6befb24
--- /dev/null
+++ b/ElvUI/Modules/Misc/DebugTools.lua
@@ -0,0 +1,162 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local D = E:GetModule("DebugTools")
+
+--Lua functions
+local format = string.format
+--WoW API / Variables
+local GetCVarBool = GetCVarBool
+local InCombatLockdown = InCombatLockdown
+
+function D:ModifyErrorFrame()
+ ScriptErrorsFrameScrollFrameText.cursorOffset = 0
+ ScriptErrorsFrameScrollFrameText.cursorHeight = 0
+ ScriptErrorsFrameScrollFrameText:SetScript("OnEditFocusGained", nil)
+
+ local Orig_ScriptErrorsFrame_Update = ScriptErrorsFrame_Update
+ ScriptErrorsFrame_Update = function(...)
+ if GetCVarBool("scriptErrors") ~= 1 then
+ Orig_ScriptErrorsFrame_Update(...)
+ return
+ end
+
+ -- Sometimes the locals table does not have an entry for an index, which can cause an argument #6 error
+ -- in Blizzard_DebugTools.lua:430 and then cause a C stack overflow, this will prevent that
+ local index = ScriptErrorsFrame.index
+ if not index or not ScriptErrorsFrame.order[index] then
+ index = #(ScriptErrorsFrame.order)
+ end
+
+ if index > 0 then
+ ScriptErrorsFrame.locals[index] = ScriptErrorsFrame.locals[index] or "No locals to dump"
+ end
+
+ Orig_ScriptErrorsFrame_Update(...)
+
+ -- Stop text highlighting again
+ ScriptErrorsFrameScrollFrameText:HighlightText(0, 0)
+ end
+
+ -- Unhighlight text when focus is hit
+ ScriptErrorsFrameScrollFrameText:HookScript("OnEscapePressed", function(self)
+ self:HighlightText(0, 0)
+ end)
+
+ ScriptErrorsFrame:Size(500, 300)
+ ScriptErrorsFrameScrollFrame:Size(ScriptErrorsFrame:GetWidth() - 45, ScriptErrorsFrame:GetHeight() - 71)
+
+ ScriptErrorsFrameScrollFrameText:Width(ScriptErrorsFrameScrollFrame:GetWidth())
+
+ local BUTTON_WIDTH = 75
+ local BUTTON_HEIGHT = 24
+ local BUTTON_SPACING = 2
+
+ -- Add a first button
+ local firstButton = CreateFrame("Button", nil, ScriptErrorsFrame, "UIPanelButtonTemplate")
+ firstButton:SetPoint("BOTTOM", -((BUTTON_WIDTH + BUTTON_WIDTH/2) + (BUTTON_SPACING * 4)), 8)
+ firstButton:SetText("First")
+ firstButton:SetHeight(BUTTON_HEIGHT)
+ firstButton:SetWidth(BUTTON_WIDTH)
+ firstButton:SetScript("OnClick", function()
+ ScriptErrorsFrame.index = 1
+ ScriptErrorsFrame_Update()
+ end)
+ ScriptErrorsFrame.firstButton = firstButton
+
+ -- Also add a Last button for errors
+ local lastButton = CreateFrame("Button", nil, ScriptErrorsFrame, "UIPanelButtonTemplate")
+ lastButton:SetPoint("BOTTOMLEFT", ScriptErrorsFrame.next, "BOTTOMRIGHT", BUTTON_SPACING, 0)
+ lastButton:SetHeight(BUTTON_HEIGHT)
+ lastButton:SetWidth(BUTTON_WIDTH)
+ lastButton:SetText("Last")
+ lastButton:SetScript("OnClick", function()
+ ScriptErrorsFrame.index = #(ScriptErrorsFrame.order)
+ ScriptErrorsFrame_Update()
+ end)
+ ScriptErrorsFrame.lastButton = lastButton
+
+ ScriptErrorsFrame.previous:ClearAllPoints()
+ ScriptErrorsFrame.previous:SetPoint("BOTTOMLEFT", firstButton, "BOTTOMRIGHT", BUTTON_SPACING, 0)
+ ScriptErrorsFrame.previous:SetWidth(BUTTON_WIDTH)
+ ScriptErrorsFrame.previous:SetHeight(BUTTON_HEIGHT)
+
+ ScriptErrorsFrame.next:ClearAllPoints()
+ ScriptErrorsFrame.next:SetPoint("BOTTOMLEFT", ScriptErrorsFrame.previous, "BOTTOMRIGHT", BUTTON_SPACING, 0)
+ ScriptErrorsFrame.next:SetWidth(BUTTON_WIDTH)
+ ScriptErrorsFrame.next:SetHeight(BUTTON_HEIGHT)
+
+ ScriptErrorsFrame.close:ClearAllPoints()
+ ScriptErrorsFrame.close:SetPoint("BOTTOMRIGHT", -8, 8)
+ ScriptErrorsFrame.close:SetSize(75, BUTTON_HEIGHT)
+
+ ScriptErrorsFrame.indexLabel:ClearAllPoints()
+ ScriptErrorsFrame.indexLabel:SetPoint("BOTTOMLEFT", 0, 12)
+end
+
+function D:ScriptErrorsFrame_UpdateButtons()
+ local numErrors = #ScriptErrorsFrame.order
+ local index = ScriptErrorsFrame.index
+ if index == 0 then
+ ScriptErrorsFrame.lastButton:Disable()
+ ScriptErrorsFrame.firstButton:Disable()
+ else
+ if numErrors == 1 then
+ ScriptErrorsFrame.lastButton:Disable()
+ ScriptErrorsFrame.firstButton:Disable()
+ else
+ ScriptErrorsFrame.lastButton:Enable()
+ ScriptErrorsFrame.firstButton:Enable()
+ end
+ end
+end
+
+function D:ScriptErrorsFrame_OnError(_, keepHidden)
+ if keepHidden or self.MessagePrinted or not InCombatLockdown() or GetCVarBool("scriptErrors") ~= 1 then return end
+
+ E:Print(L["|cFFE30000Lua error recieved. You can view the error message when you exit combat."])
+ self.MessagePrinted = true
+end
+
+function D:PLAYER_REGEN_ENABLED()
+ ScriptErrorsFrame:SetParent(UIParent)
+ self.MessagePrinted = nil
+end
+
+function D:PLAYER_REGEN_DISABLED()
+ ScriptErrorsFrame:SetParent(self.HideFrame)
+end
+
+function D:TaintError(event, addonName, addonFunc)
+ if GetCVarBool("scriptErrors") ~= 1 or E.db.general.taintLog ~= true then return end
+ ScriptErrorsFrame_OnError(format(L["%s: %s tried to call the protected function '%s'."], event, addonName or "", addonFunc or ""), false)
+end
+
+function D:StaticPopup_Show(name)
+ if name == "ADDON_ACTION_FORBIDDEN" and E.db.general.taintLog ~= true then
+ StaticPopup_Hide(name)
+ end
+end
+
+function D:Initialize()
+ self.Initialized = true
+ self.HideFrame = CreateFrame("Frame")
+ self.HideFrame:Hide()
+
+ if not IsAddOnLoaded("Blizzard_DebugTools") then
+ LoadAddOn("Blizzard_DebugTools")
+ end
+
+ self:ModifyErrorFrame()
+ self:SecureHook("ScriptErrorsFrame_UpdateButtons")
+ self:SecureHook("ScriptErrorsFrame_OnError")
+ self:SecureHook("StaticPopup_Show")
+ self:RegisterEvent("PLAYER_REGEN_DISABLED")
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ self:RegisterEvent("ADDON_ACTION_BLOCKED", "TaintError")
+ self:RegisterEvent("ADDON_ACTION_FORBIDDEN", "TaintError")
+end
+
+local function InitializeCallback()
+ D:Initialize()
+end
+
+E:RegisterModule(D:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Misc/Load_Misc.xml b/ElvUI/Modules/Misc/Load_Misc.xml
new file mode 100644
index 0000000..b96475d
--- /dev/null
+++ b/ElvUI/Modules/Misc/Load_Misc.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/Misc/Loot.lua b/ElvUI/Modules/Misc/Loot.lua
new file mode 100644
index 0000000..d80a2d7
--- /dev/null
+++ b/ElvUI/Modules/Misc/Loot.lua
@@ -0,0 +1,352 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local M = E:GetModule("Misc")
+
+--Lua functions
+local unpack, pairs = unpack, pairs
+local max = math.max
+local find, gsub = string.find, string.gsub
+local tinsert = table.insert
+--WoW API / Variables
+local CloseLoot = CloseLoot
+local CreateFrame = CreateFrame
+local CursorOnUpdate = CursorOnUpdate
+local CursorUpdate = CursorUpdate
+local GetCVar = GetCVar
+local GetCursorPosition = GetCursorPosition
+local GetLootSlotInfo = GetLootSlotInfo
+local GetLootSlotLink = GetLootSlotLink
+local GetNumLootItems = GetNumLootItems
+local GiveMasterLoot = GiveMasterLoot
+local HandleModifiedItemClick = HandleModifiedItemClick
+local IsFishingLoot = IsFishingLoot
+local IsModifiedClick = IsModifiedClick
+local LootSlot = LootSlot
+local LootSlotIsItem = LootSlotIsItem
+local ResetCursor = ResetCursor
+local StaticPopup_Hide = StaticPopup_Hide
+local ToggleDropDownMenu = ToggleDropDownMenu
+local UnitIsDead = UnitIsDead
+local UnitIsFriend = UnitIsFriend
+local UnitName = UnitName
+local ITEM_QUALITY_COLORS = ITEM_QUALITY_COLORS
+local TEXTURE_ITEM_QUEST_BANG = TEXTURE_ITEM_QUEST_BANG
+local LOOT = LOOT
+
+-- Credit Haste
+local lootFrame, lootFrameHolder
+local iconSize = 30
+
+local sq, ss, sn
+local OnEnter = function(self)
+ local slot = self:GetID()
+ if LootSlotIsItem(slot) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
+ GameTooltip:SetLootItem(slot)
+ CursorUpdate(self)
+ end
+
+ self.drop:Show()
+ self.drop:SetVertexColor(1, 1, 1)
+end
+
+local OnLeave = function(self)
+ if self.quality and (self.quality > 1) then
+ local color = ITEM_QUALITY_COLORS[self.quality]
+ self.drop:SetVertexColor(color.r, color.g, color.b)
+ else
+ self.drop:Hide()
+ end
+
+ GameTooltip:Hide()
+ ResetCursor()
+end
+
+local OnClick = function(self)
+ LootFrame.selectedQuality = self.quality
+ LootFrame.selectedItemName = self.name:GetText()
+ LootFrame.selectedSlot = self:GetID()
+ LootFrame.selectedLootButton = self:GetName()
+
+ if IsModifiedClick() then
+ HandleModifiedItemClick(GetLootSlotLink(self:GetID()))
+ else
+ StaticPopup_Hide("CONFIRM_LOOT_DISTRIBUTION")
+ ss = self:GetID()
+ sq = self.quality
+ sn = self.name:GetText()
+ LootSlot(ss)
+ end
+end
+
+local OnShow = function(self)
+ if GameTooltip:IsOwned(self) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
+ GameTooltip:SetLootItem(self:GetID())
+ CursorOnUpdate(self)
+ end
+end
+
+local function anchorSlots(self)
+ local shownSlots = 0
+ for i = 1, #self.slots do
+ local frame = self.slots[i]
+ if frame:IsShown() then
+ shownSlots = shownSlots + 1
+
+ frame:Point("TOP", lootFrame, 4, (-8 + iconSize) - (shownSlots * iconSize))
+ end
+ end
+
+ self:Height(max(shownSlots * iconSize + 16, 20))
+end
+
+local function createSlot(id)
+ local frame = CreateFrame("Button", "ElvLootSlot"..id, lootFrame)
+ frame:Point("LEFT", 8, 0)
+ frame:Point("RIGHT", -8, 0)
+ frame:Height(iconSize - 2)
+ frame:SetID(id)
+
+ frame:RegisterForClicks("LeftButtonUp", "RightButtonUp")
+
+ frame:SetScript("OnEnter", OnEnter)
+ frame:SetScript("OnLeave", OnLeave)
+ frame:SetScript("OnClick", OnClick)
+ frame:SetScript("OnShow", OnShow)
+
+ local iconFrame = CreateFrame("Frame", nil, frame)
+ iconFrame:Size(iconSize - 2)
+ iconFrame:Point("RIGHT", frame)
+ iconFrame:SetTemplate("Default")
+ frame.iconFrame = iconFrame
+ E.frames[iconFrame] = nil
+
+ local icon = iconFrame:CreateTexture(nil, "ARTWORK")
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetInside()
+ frame.icon = icon
+
+ local count = iconFrame:CreateFontString(nil, "OVERLAY")
+ count:SetJustifyH("RIGHT")
+ count:Point("BOTTOMRIGHT", iconFrame, -2, 2)
+ count:FontTemplate(nil, nil, "OUTLINE")
+ count:SetText(1)
+ frame.count = count
+
+ local name = frame:CreateFontString(nil, "OVERLAY")
+ name:SetJustifyH("LEFT")
+ name:Point("LEFT", frame)
+ name:Point("RIGHT", icon, "LEFT")
+ name:SetNonSpaceWrap(true)
+ name:FontTemplate(nil, nil, "OUTLINE")
+ frame.name = name
+
+ local drop = frame:CreateTexture(nil, "ARTWORK")
+ drop:SetTexture(1, 1, 1, 0.15)
+ drop:Point("LEFT", icon, "RIGHT", 0, 0)
+ drop:Point("RIGHT", frame)
+ drop:SetAllPoints(frame)
+ frame.drop = drop
+
+ local questTexture = iconFrame:CreateTexture(nil, "OVERLAY")
+ questTexture:SetInside()
+ questTexture:SetTexture(TEXTURE_ITEM_QUEST_BANG)
+ questTexture:SetTexCoord(unpack(E.TexCoords))
+ frame.questTexture = questTexture
+
+ lootFrame.slots[id] = frame
+ return frame
+end
+
+function M:LOOT_SLOT_CLEARED(_, slot)
+ if not lootFrame:IsShown() then return end
+
+ lootFrame.slots[slot]:Hide()
+ anchorSlots(lootFrame)
+end
+
+function M:LOOT_CLOSED()
+ StaticPopup_Hide("LOOT_BIND")
+ lootFrame:Hide()
+
+ for _, v in pairs(lootFrame.slots) do
+ v:Hide()
+ end
+end
+
+function M:OPEN_MASTER_LOOT_LIST()
+ ToggleDropDownMenu(1, nil, GroupLootDropDown, lootFrame.slots[ss], 0, 0)
+end
+
+function M:UPDATE_MASTER_LOOT_LIST()
+ UIDropDownMenu_Refresh(GroupLootDropDown)
+end
+
+function M:LOOT_OPENED(_, autoLoot)
+ lootFrame:Show()
+
+ if not lootFrame:IsShown() then
+ CloseLoot(autoLoot == 0)
+ end
+
+ local items = GetNumLootItems()
+
+ if IsFishingLoot() then
+ lootFrame.title:SetText(L["Fishy Loot"])
+ elseif not UnitIsFriend("player", "target") and UnitIsDead("target") then
+ lootFrame.title:SetText(UnitName("target"))
+ else
+ lootFrame.title:SetText(LOOT)
+ end
+
+ -- Blizzard uses strings here
+ if GetCVar("lootUnderMouse") == "1" then
+ local x, y = GetCursorPosition()
+ x = x / lootFrame:GetEffectiveScale()
+ y = y / lootFrame:GetEffectiveScale()
+
+ lootFrame:ClearAllPoints()
+ lootFrame:Point("TOPLEFT", UIParent, "BOTTOMLEFT", x - 40, y + 20)
+ lootFrame:GetCenter()
+ lootFrame:Raise()
+ E:DisableMover("LootFrameMover")
+ else
+ lootFrame:ClearAllPoints()
+ lootFrame:Point("TOPLEFT", lootFrameHolder, "TOPLEFT")
+ E:EnableMover("LootFrameMover")
+ end
+
+ local m, w, t = 0, 0, lootFrame.title:GetStringWidth()
+ if items > 0 then
+ for i = 1, items do
+ local slot = lootFrame.slots[i] or createSlot(i)
+ local texture, item, quantity, quality, _, isQuestItem, questId, isActive = GetLootSlotInfo(i)
+ local color = ITEM_QUALITY_COLORS[quality]
+
+ if texture and find(texture, "INV_Misc_Coin") then
+ item = gsub(item, "\n", ", ")
+ end
+
+ if quantity and (quantity > 1) then
+ slot.count:SetText(quantity)
+ slot.count:Show()
+ else
+ slot.count:Hide()
+ end
+
+ if quality and (quality > 1) then
+ slot.drop:SetVertexColor(color.r, color.g, color.b)
+ slot.drop:Show()
+ else
+ slot.drop:Hide()
+ end
+
+ slot.quality = quality
+ slot.name:SetText(item)
+ if color then
+ slot.name:SetTextColor(color.r, color.g, color.b)
+ end
+ slot.icon:SetTexture(texture)
+
+ if quality then
+ m = max(m, quality)
+ end
+ w = max(w, slot.name:GetStringWidth())
+
+ local questTexture = slot.questTexture
+ if questId and not isActive then
+ questTexture:SetTexture(TEXTURE_ITEM_QUEST_BANG)
+ questTexture:Show()
+ elseif questId or isQuestItem then
+ questTexture:SetTexture(TEXTURE_ITEM_QUEST_BORDER)
+ questTexture:Show()
+ else
+ questTexture:Hide()
+ end
+
+ -- Check for FasterLooting scripts or w/e (if bag is full)
+ if texture then
+ slot:Enable()
+ slot:Show()
+ end
+ end
+ else
+ local slot = lootFrame.slots[1] or createSlot(1)
+ local color = ITEM_QUALITY_COLORS[0]
+
+ slot.name:SetText(L["Empty Slot"])
+ if color then
+ slot.name:SetTextColor(color.r, color.g, color.b)
+ end
+ slot.icon:SetTexture[[Interface\Icons\INV_Misc_Herb_AncientLichen]]
+
+ w = max(w, slot.name:GetStringWidth())
+
+ slot.count:Hide()
+ slot.drop:Hide()
+ slot:Disable()
+ slot:Show()
+ end
+ anchorSlots(lootFrame)
+
+ w = w + 60
+ t = t + 5
+
+ local color = ITEM_QUALITY_COLORS[m]
+ lootFrame:SetBackdropBorderColor(color.r, color.g, color.b, .8)
+ lootFrame:Width(max(w, t))
+end
+
+function M:LoadLoot()
+ if not E.private.general.loot then return end
+
+ lootFrameHolder = CreateFrame("Frame", "ElvLootFrameHolder", E.UIParent)
+ lootFrameHolder:Point("TOP", 0, -50)
+ lootFrameHolder:Size(150, 22)
+
+ lootFrame = CreateFrame("Button", "ElvLootFrame", lootFrameHolder)
+ lootFrame:SetClampedToScreen(true)
+ lootFrame:SetPoint("TOPLEFT")
+ lootFrame:Size(256, 64)
+ lootFrame:SetTemplate("Transparent")
+ lootFrame:SetFrameStrata("DIALOG")
+ lootFrame:SetToplevel(true)
+ lootFrame.title = lootFrame:CreateFontString(nil, "OVERLAY")
+ lootFrame.title:FontTemplate(nil, nil, "OUTLINE")
+ lootFrame.title:Point("BOTTOMLEFT", lootFrame, "TOPLEFT", 0, 1)
+ lootFrame.slots = {}
+ lootFrame:SetScript("OnHide", function()
+ StaticPopup_Hide("CONFIRM_LOOT_DISTRIBUTION")
+ CloseLoot()
+ end)
+ E.frames[lootFrame] = nil
+
+ self:RegisterEvent("LOOT_OPENED")
+ self:RegisterEvent("LOOT_SLOT_CLEARED")
+ self:RegisterEvent("LOOT_CLOSED")
+ self:RegisterEvent("OPEN_MASTER_LOOT_LIST")
+ self:RegisterEvent("UPDATE_MASTER_LOOT_LIST")
+
+ E:CreateMover(lootFrameHolder, "LootFrameMover", L["Loot Frame"], nil, nil, nil, nil, nil, "general,blizzUIImprovements")
+
+ -- Fuzz
+ LootFrame:UnregisterAllEvents()
+ tinsert(UISpecialFrames, "ElvLootFrame")
+
+ function _G.GroupLootDropDown_GiveLoot(self)
+ if sq >= MASTER_LOOT_THREHOLD then
+ local dialog = StaticPopup_Show("CONFIRM_LOOT_DISTRIBUTION", ITEM_QUALITY_COLORS[sq].hex..sn..FONT_COLOR_CODE_CLOSE, self:GetText())
+ if dialog then
+ dialog.data = self.value
+ end
+ else
+ GiveMasterLoot(ss, self.value)
+ end
+ CloseDropDownMenus()
+ end
+
+ E.PopupDialogs.CONFIRM_LOOT_DISTRIBUTION.OnAccept = function(_, data)
+ GiveMasterLoot(ss, data)
+ end
+ StaticPopupDialogs.CONFIRM_LOOT_DISTRIBUTION.preferredIndex = 3
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Misc/LootRoll.lua b/ElvUI/Modules/Misc/LootRoll.lua
new file mode 100644
index 0000000..7d22d55
--- /dev/null
+++ b/ElvUI/Modules/Misc/LootRoll.lua
@@ -0,0 +1,474 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local M = E:GetModule("Misc")
+
+--Lua functions
+local pairs, ipairs, unpack = pairs, ipairs, unpack
+local find, format = string.find, string.format
+local tinsert, twipe = table.insert, table.wipe
+--WoW API / Variables
+local ChatEdit_InsertLink = ChatEdit_InsertLink
+local CreateFrame = CreateFrame
+local CursorOnUpdate = CursorOnUpdate
+local CursorUpdate = CursorUpdate
+local DressUpItemLink = DressUpItemLink
+local GetLootRollItemInfo = GetLootRollItemInfo
+local GetLootRollItemLink = GetLootRollItemLink
+local GetLootRollTimeLeft = GetLootRollTimeLeft
+local IsModifiedClick = IsModifiedClick
+local ResetCursor = ResetCursor
+local RollOnLoot = RollOnLoot
+local SetDesaturation = SetDesaturation
+local UnitClass = UnitClass
+
+local ITEM_QUALITY_COLORS = ITEM_QUALITY_COLORS
+local ROLL_DISENCHANT = ROLL_DISENCHANT
+
+local POSITION = "TOP"
+local FRAME_WIDTH, FRAME_HEIGHT = 328, 28
+
+M.RollBars = {}
+
+local locale = GetLocale()
+local rollMessages = locale == "deDE" and {
+ ["(.*) passt automatisch bei (.+), weil [ersi]+ den Gegenstand nicht benutzen kann.$"] = 0,
+ ["(.*) würfelt nicht für: (.+|r)$"] = 0,
+ ["(.*) hat für (.+) 'Bedarf' ausgewählt"] = 1,
+ ["(.*) hat für (.+) 'Gier' ausgewählt"] = 2,
+ ["(.*) hat für '(.+)' Entzauberung gewählt."] = 3,
+} or locale == "frFR" and {
+ ["(.*) a passé pour : (.+) parce qu'((il)|(elle)) ne peut pas ramasser cette objet.$"] = 0,
+ ["(.*) a passé pour : (.+)"] = 0,
+ ["(.*) a choisi Besoin pour : (.+)"] = 1,
+ ["(.*) a choisi Cupidité pour : (.+)"] = 2,
+ ["(.*) a choisi Désenchantement pour : (.+)"] = 3,
+} or locale == "zhCN" and {
+ ["(.*)自动放弃了:(.+),因为他无法拾取该物品$"] = 0,
+ ["(.*)自动放弃了:(.+),因为她无法拾取该物品$"] = 0,
+ ["(.*)放弃了:(.+)"] = 0,
+ ["(.*)选择了需求取向:(.+)"] = 1,
+ ["(.*)选择了贪婪取向:(.+)"] = 2,
+ ["(.*)选择了分解取向:(.+)"] = 3,
+} or locale == "zhTW" and {
+ ["(.*)自動放棄:(.+),因為他無法拾取該物品$"] = 0,
+ ["(.*)自動放棄:(.+),因為她無法拾取該物品$"] = 0,
+ ["(.*)放棄了:(.+)"] = 0,
+ ["(.*)選擇了需求:(.+)"] = 1,
+ ["(.*)選擇了貪婪:(.+)"] = 2,
+ ["(.*)選擇了分解:(.+)"] = 3,
+} or locale == "ruRU" and {
+ ["(.*) автоматически передает предмет (.+), поскольку не может его забрать"] = 0,
+ ["(.*) пропускает розыгрыш предмета \"(.+)\", поскольку не может его забрать"] = 0,
+ ["(.*) отказывается от предмета (.+)%."] = 0,
+ ["Разыгрывается: (.+)%. (.*): \"Мне это нужно\""] = 1,
+ ["Разыгрывается: (.+)%. (.*): \"Не откажусь\""] = 2,
+ ["Разыгрывается: (.+)%. (.*): \"Распылить\""] = 3,
+} or locale == "koKR" and {
+ ["(.*)님이 획득할 수 없는 아이템이어서 자동으로 주사위 굴리기를 포기했습니다: (.+)"] = 0,
+ ["(.*)님이 주사위 굴리기를 포기했습니다: (.+)"] = 0,
+ ["(.*)님이 입찰을 선택했습니다: (.+)"] = 1,
+ ["(.*)님이 차비를 선택했습니다: (.+)"] = 2,
+ ["(.*)님이 마력 추출을 선택했습니다: (.+)"] = 3,
+} or locale == "esES" and {
+ ["^(.*) pasó automáticamente de: (.+) porque no puede despojar este objeto.$"] = 0,
+ ["^(.*) pasó de: (.+|r)$"] = 0,
+ ["(.*) eligió Necesidad para: (.+)"] = 1,
+ ["(.*) eligió Codicia para: (.+)"] = 2,
+ ["(.*) eligió Desencantar para: (.+)"] = 3,
+} or locale == "esMX" and {
+ ["^(.*) pasó automáticamente de: (.+) porque no puede despojar este objeto.$"] = 0,
+ ["^(.*) pasó de: (.+|r)$"] = 0,
+ ["(.*) eligió Necesidad para: (.+)"] = 1,
+ ["(.*) eligió Codicia para: (.+)"] = 2,
+ ["(.*) eligió Desencantar para: (.+)"] = 3,
+} or {
+ ["^(.*) automatically passed on: (.+) because s?he cannot loot that item.$"] = 0,
+ ["^(.*) passed on: (.+|r)$"] = 0,
+ ["(.*) has selected Need for: (.+)"] = 1,
+ ["(.*) has selected Greed for: (.+)"] = 2,
+ ["(.*) has selected Disenchant for: (.+)"] = 3
+}
+
+local rollTypes = {
+ [0] = {
+ tooltipText = PASS,
+ normalTexture = "Interface\\Buttons\\UI-GroupLoot-Pass-Up",
+ pushedTexture = "Interface\\Buttons\\UI-GroupLoot-Pass-Down",
+ highlightTexture = nil,
+ },
+ [1] = {
+ tooltipText = NEED,
+ newbieText = NEED_NEWBIE,
+ normalTexture = "Interface\\Buttons\\UI-GroupLoot-Dice-Up",
+ pushedTexture = "Interface\\Buttons\\UI-GroupLoot-Dice-Down",
+ highlightTexture = "Interface\\Buttons\\UI-GroupLoot-Dice-Highlight",
+ },
+ [2] = {
+ tooltipText = GREED,
+ newbieText = GREED_NEWBIE,
+ normalTexture = "Interface\\Buttons\\UI-GroupLoot-Coin-Up",
+ pushedTexture = "Interface\\Buttons\\UI-GroupLoot-Coin-Down",
+ highlightTexture = "Interface\\Buttons\\UI-GroupLoot-Coin-Highlight",
+ },
+ [3] = {
+ tooltipText = ROLL_DISENCHANT,
+ newbieText = ROLL_DISENCHANT_NEWBIE,
+ normalTexture = "Interface\\Buttons\\UI-GroupLoot-DE-Up",
+ pushedTexture = "Interface\\Buttons\\UI-GroupLoot-DE-Down",
+ highlightTexture = "Interface\\Buttons\\UI-GroupLoot-DE-Highlight",
+ },
+}
+
+local reasons = {
+ LOOT_ROLL_INELIGIBLE_REASON1,
+ LOOT_ROLL_INELIGIBLE_REASON2,
+ LOOT_ROLL_INELIGIBLE_REASON3,
+ LOOT_ROLL_INELIGIBLE_REASON4,
+ LOOT_ROLL_INELIGIBLE_REASON5,
+}
+
+local function buttonOnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
+
+ GameTooltip:SetText(self.tooltipText)
+
+ if self.newbieText and SHOW_NEWBIE_TIPS == "1" then
+ GameTooltip:AddLine(self.newbieText, 1, 0.82, 0, true)
+ end
+
+ if self:IsEnabled() == 0 then
+ GameTooltip:AddLine(self.reason, 1, 0.1, 0.1, true)
+ end
+
+ for playerName, rollData in pairs(self.parent.rollResults) do
+ if self.rollType == rollData[1] and rollData[2] then
+ local classColor = E.media.herocolor
+ GameTooltip:AddLine(playerName, classColor.r, classColor.g, classColor.b)
+ end
+ end
+
+ GameTooltip:Show()
+end
+
+local function buttonOnLeave()
+ GameTooltip:Hide()
+end
+
+local function buttonOnClick(self)
+ RollOnLoot(self.parent.rollID, self.rollType)
+end
+
+local function toggleLootButton(self, state, reason, reasonValue)
+ if state then
+ self:Enable()
+ self:SetAlpha(1)
+ self.reason = nil
+ SetDesaturation(self:GetNormalTexture(), false)
+ else
+ self:Disable()
+ self:SetAlpha(0.2)
+ self.reason = reasonValue and format(reasons[reason], reasonValue) or reasons[reason]
+ SetDesaturation(self:GetNormalTexture(), true)
+ end
+end
+
+local function increaseRollCount(self, count)
+ local text = self.text:GetText()
+ if not text or text == "" then
+ self.text:SetText(count or 1)
+ else
+ self.text:SetText(self.text:GetText() + (count or 1))
+ end
+end
+
+function M:CreateRollButton(parent, rollType)
+ local data = rollTypes[rollType]
+
+ local button = CreateFrame("Button", nil, parent)
+ button:Size(FRAME_HEIGHT - 4)
+ button:SetNormalTexture(data.normalTexture)
+ button:SetPushedTexture(data.highlightTexture)
+ button:SetHighlightTexture(data.pushedTexture)
+
+ button:SetMotionScriptsWhileDisabled(true)
+ button:SetScript("OnEnter", buttonOnEnter)
+ button:SetScript("OnLeave", buttonOnLeave)
+ button:SetScript("OnClick", buttonOnClick)
+
+ button.ToggleLootButton = toggleLootButton
+ button.IncreaseRollCount = increaseRollCount
+ button.parent = parent
+ button.rollType = rollType
+ button.tooltipText = data.tooltipText
+ button.newbieText = data.newbieText
+
+ button.text = button:CreateFontString(nil, nil)
+ button.text:FontTemplate(E.Media.Fonts.Homespun, nil, "MONOCHROMEOUTLINE")
+
+ return button
+end
+
+local function itemOnEnter(self)
+ GameTooltip:SetOwner(self, POSITION == "TOP" and "ANCHOR_BOTTOMLEFT" or "ANCHOR_TOPLEFT")
+ GameTooltip:SetLootRollItem(self.rollID)
+
+ CursorUpdate(self)
+end
+
+local function itemOnLeave()
+ GameTooltip:Hide()
+ ResetCursor()
+end
+
+local function itemOnUpdate(self)
+ if GameTooltip:IsOwned(self) then
+ GameTooltip:SetOwner(self, POSITION == "TOP" and "ANCHOR_BOTTOMLEFT" or "ANCHOR_TOPLEFT")
+ GameTooltip:SetLootRollItem(self.rollID)
+ end
+
+ CursorOnUpdate(self)
+end
+
+local function itemOnClick(self)
+ if IsModifiedClick("CHATLINK") then
+ ChatEdit_InsertLink(self.link)
+ elseif IsModifiedClick("DRESSUP") then
+ DressUpItemLink(self.link)
+ end
+end
+
+local function statusbarOnUpdate(self)
+ local timeLeft = GetLootRollTimeLeft(self.parent.rollID)
+ if timeLeft < 0 or timeLeft > self.parent.rollTime then
+ timeLeft = 0
+ else
+ self.spark:Point("CENTER", self, "LEFT", (timeLeft / self.parent.rollTime) * self:GetWidth(), 0)
+ end
+
+ self:SetValue(timeLeft)
+end
+
+function M:CreateRollFrame()
+ self.numFrames = self.numFrames + 1
+
+ local frame = CreateFrame("Frame", format("ElvUI_GroupLootFrame%d", self.numFrames), E.UIParent)
+ frame:Size(FRAME_WIDTH, FRAME_HEIGHT)
+ frame:SetTemplate()
+ frame:SetFrameStrata("DIALOG")
+ frame:Hide()
+
+ if POSITION == "TOP" then
+ frame:Point("TOP", self.numFrames > 1 and self.RollBars[self.numFrames - 1] or AlertFrameHolder, "BOTTOM", 0, -4)
+ else
+ frame:Point("BOTTOM", self.numFrames > 1 and self.RollBars[self.numFrames - 1] or AlertFrameHolder, "TOP", 0, 4)
+ end
+
+ local itemButton = CreateFrame("Button", "$parentIconFrame", frame)
+ itemButton:Size(FRAME_HEIGHT - (E.Border * 2))
+ itemButton:Point("RIGHT", frame, "LEFT", -(E.Spacing * 3), 0)
+ itemButton:CreateBackdrop()
+ itemButton:SetScript("OnEnter", itemOnEnter)
+ itemButton:SetScript("OnLeave", itemOnLeave)
+ itemButton:SetScript("OnUpdate", itemOnUpdate)
+ itemButton:SetScript("OnClick", itemOnClick)
+ itemButton.hasItem = 1
+ frame.itemButton = itemButton
+
+ itemButton.icon = itemButton:CreateTexture(nil, "OVERLAY")
+ itemButton.icon:SetAllPoints()
+ itemButton.icon:SetTexCoord(unpack(E.TexCoords))
+
+ local fade = frame:CreateTexture(nil, "BORDER")
+ fade:Point("TOPLEFT", frame, "TOPLEFT", 4, 0)
+ fade:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -4, 0)
+ fade:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
+ fade:SetBlendMode("ADD")
+ fade:SetGradientAlpha("VERTICAL", 0.1, 0.1, 0.1, 0, 0.1, 0.1, 0.1, 0)
+ frame.fade = fade
+
+ local status = CreateFrame("StatusBar", "$parentStatusBar", frame)
+ status:SetInside()
+ status:SetFrameLevel(status:GetFrameLevel() - 1)
+ status:SetStatusBarTexture(E.media.normTex)
+ status:SetStatusBarColor(0.8, 0.8, 0.8, 0.9)
+ status.parent = frame
+ E:RegisterStatusBar(status)
+ status:SetScript("OnUpdate", statusbarOnUpdate)
+ frame.status = status
+
+ status.bg = status:CreateTexture(nil, "BACKGROUND")
+ status.bg:SetAlpha(0.1)
+ status.bg:SetAllPoints()
+
+ local spark = frame:CreateTexture(nil, "OVERLAY")
+ spark:Size(14, FRAME_HEIGHT)
+ spark:SetTexture("Interface\\CastingBar\\UI-CastingBar-Spark")
+ spark:SetBlendMode("ADD")
+ status.spark = spark
+
+ frame.passButton = self:CreateRollButton(frame, 0)
+ frame.needButton = self:CreateRollButton(frame, 1)
+ frame.greedButton = self:CreateRollButton(frame, 2)
+ frame.disenchantButton = self:CreateRollButton(frame, 3)
+
+ frame.needButton:SetHitRectInsets(0, 0, -2, 0)
+ frame.greedButton:SetHitRectInsets(0, 0, -3, 1)
+ frame.disenchantButton:SetHitRectInsets(0, 0, -2, 0)
+ frame.passButton:SetHitRectInsets(0, 0, 0, -2)
+
+ frame.needButton:Point("LEFT", frame.itemButton, "RIGHT", 4, -1)
+ frame.greedButton:Point("LEFT", frame.needButton, "RIGHT", 1, -1)
+ frame.disenchantButton:Point("LEFT", frame.greedButton, "RIGHT", 0, 1)
+ frame.passButton:Point("LEFT", frame.disenchantButton, "RIGHT", 0, 2)
+
+ frame.needButton.text:Point("CENTER", -1, 4)
+ frame.greedButton.text:Point("CENTER", 1, 5)
+ frame.disenchantButton.text:Point("CENTER", 1, 4)
+ frame.passButton.text:Point("CENTER", 1, 2)
+
+ frame.bindText = frame:CreateFontString()
+ frame.bindText:Point("LEFT", frame.passButton, "RIGHT", 2, 0)
+ frame.bindText:FontTemplate(nil, nil, "OUTLINE")
+
+ local itemName = frame:CreateFontString(nil, "ARTWORK")
+ itemName:FontTemplate(nil, nil, "OUTLINE")
+ itemName:Point("LEFT", frame.bindText, "RIGHT", 1, 0)
+ itemName:Point("RIGHT", frame, "RIGHT", -5, 0)
+ itemName:Size(200, 10)
+ itemName:SetJustifyH("LEFT")
+ frame.itemName = itemName
+
+ frame.rollResults = {}
+ frame.rollButtons = {
+ [0] = frame.passButton,
+ [1] = frame.needButton,
+ [2] = frame.greedButton,
+ [3] = frame.disenchantButton,
+ }
+
+ tinsert(self.RollBars, frame)
+
+ return frame
+end
+
+function M:ReleaseFrame(frame)
+ frame:Hide()
+ frame.rollID = nil
+ frame.rollTime = nil
+
+ for i = 0, 3 do
+ frame.rollButtons[i].text:SetText("")
+ end
+
+ twipe(frame.rollResults)
+end
+
+function M:GetFrame()
+ for _, frame in ipairs(M.RollBars) do
+ if not frame.rollID then
+ return frame
+ end
+ end
+
+ return self:CreateRollFrame()
+end
+
+function M:START_LOOT_ROLL(_, rollID, rollTime)
+ local f = self:GetFrame()
+ f.rollID = rollID
+ f.rollTime = rollTime
+
+ local texture, name, count, quality, bindOnPickUp, canNeed, canGreed, canDisenchant, reasonNeed, reasonGreed, reasonDisenchant, deSkillRequired = GetLootRollItemInfo(rollID)
+
+ f.itemButton.icon:SetTexture(texture)
+ f.itemButton.rollID = rollID
+ f.itemButton.link = GetLootRollItemLink(rollID)
+
+ if count > 1 then
+ f.itemName:SetFormattedText("%dx %s", count, name)
+ else
+ f.itemName:SetText(name)
+ end
+
+ f.status:SetMinMaxValues(0, rollTime)
+ f.status:SetValue(rollTime)
+
+ local color = ITEM_QUALITY_COLORS[quality]
+ f.status:SetStatusBarColor(color.r, color.g, color.b, 0.7)
+ f.status.bg:SetTexture(color.r, color.g, color.b)
+
+ f.bindText:SetText(bindOnPickUp and "BoP" or "BoE")
+ f.bindText:SetVertexColor(bindOnPickUp and 1 or 0.3, bindOnPickUp and 0.3 or 1, bindOnPickUp and 0.1 or 0.3)
+
+ f.needButton:ToggleLootButton(canNeed, reasonNeed)
+ f.greedButton:ToggleLootButton(canGreed, reasonGreed)
+ f.disenchantButton:ToggleLootButton(canDisenchant, reasonDisenchant, deSkillRequired)
+
+ f:Show()
+
+ AlertFrame_FixAnchors()
+
+ if E.db.general.autoRoll and E.mylevel == MAX_PLAYER_LEVEL and quality == 2 and not bindOnPickUp then
+ if canDisenchant then
+ RollOnLoot(rollID, 3)
+ else
+ RollOnLoot(rollID, 2)
+ end
+ end
+end
+
+function M:CANCEL_LOOT_ROLL(_, rollID)
+ for _, frame in ipairs(self.RollBars) do
+ if frame.rollID == rollID then
+ self:ReleaseFrame(frame)
+ E:StaticPopup_Hide("CONFIRM_LOOT_ROLL", self.rollID)
+ break
+ end
+ end
+end
+
+function M:ParseRollChoice(msg)
+ for regex, rollType in pairs(rollMessages) do
+ local _, _, playerName, itemName = find(msg, regex)
+
+ if playerName and itemName and playerName ~= "Everyone" then
+ if locale == "ruRU" and rollType ~= 0 then
+ playerName, itemName = itemName, playerName
+ end
+
+ return playerName, itemName, rollType
+ end
+ end
+end
+
+function M:CHAT_MSG_LOOT(_, msg)
+ local playerName, itemName, rollType = self:ParseRollChoice(msg)
+
+ if playerName and itemName then
+ local _, class = UnitClass(playerName)
+
+ for _, frame in ipairs(self.RollBars) do
+ if frame.rollID and frame.itemButton.link == itemName and not frame.rollResults[playerName] then
+ frame.rollResults[playerName] = {rollType, class}
+ frame.rollButtons[rollType]:IncreaseRollCount()
+ break
+ end
+ end
+ end
+end
+
+function M:LoadLootRoll()
+ if not E.private.general.lootRoll then return end
+
+ self.numFrames = 0
+
+ self:RegisterEvent("CHAT_MSG_LOOT")
+ self:RegisterEvent("START_LOOT_ROLL")
+ self:RegisterEvent("CANCEL_LOOT_ROLL")
+
+ UIParent:UnregisterEvent("START_LOOT_ROLL")
+ UIParent:UnregisterEvent("CANCEL_LOOT_ROLL")
+
+ for i = 1, NUM_GROUP_LOOT_FRAMES do
+ _G["GroupLootFrame"..i]:UnregisterEvent("CANCEL_LOOT_ROLL")
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Misc/Misc.lua b/ElvUI/Modules/Misc/Misc.lua
new file mode 100644
index 0000000..9a6a6ff
--- /dev/null
+++ b/ElvUI/Modules/Misc/Misc.lua
@@ -0,0 +1,355 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local M = E:GetModule("Misc")
+local Bags = E:GetModule("Bags")
+
+--Lua functions
+local ipairs = ipairs
+local format = string.format
+--WoW API / Variables
+local AcceptGroup = AcceptGroup
+local CanGuildBankRepair = CanGuildBankRepair
+local CanMerchantRepair = CanMerchantRepair
+local GetCVarBool, SetCVar = GetCVarBool, SetCVar
+local GetFriendInfo = GetFriendInfo
+local GetGuildBankMoney = GetGuildBankMoney
+local GetGuildBankWithdrawMoney = GetGuildBankWithdrawMoney
+local GetGuildRosterInfo = GetGuildRosterInfo
+local GetMoney = GetMoney
+local GetNumFriends = GetNumFriends
+local GetNumGuildMembers = GetNumGuildMembers
+local GetNumPartyMembers = GetNumPartyMembers
+local GetNumRaidMembers = GetNumRaidMembers
+local GetPartyMember = GetPartyMember
+local GetRaidRosterInfo = GetRaidRosterInfo
+local GetRepairAllCost = GetRepairAllCost
+local GuildRoster = GuildRoster
+local HideRepairCursor = HideRepairCursor
+local InCombatLockdown = InCombatLockdown
+local IsInGuild = IsInGuild
+local IsInInstance = IsInInstance
+local IsShiftKeyDown = IsShiftKeyDown
+local LeaveParty = LeaveParty
+local PickupInventoryItem = PickupInventoryItem
+local RaidNotice_AddMessage = RaidNotice_AddMessage
+local RepairAllItems = RepairAllItems
+local SendChatMessage = SendChatMessage
+local ShowFriends = ShowFriends
+local ShowRepairCursor = ShowRepairCursor
+local StaticPopup_Hide = StaticPopup_Hide
+local UninviteUnit = UninviteUnit
+local UnitGUID = UnitGUID
+local UnitName = UnitName
+
+local MAX_PARTY_MEMBERS = MAX_PARTY_MEMBERS
+
+do
+ local function EventHandler(event)
+ if event == "PLAYER_REGEN_DISABLED" then
+ UIErrorsFrame:UnregisterEvent("UI_ERROR_MESSAGE")
+ else
+ UIErrorsFrame:RegisterEvent("UI_ERROR_MESSAGE")
+ end
+ end
+
+ function M:ToggleErrorHandling()
+ if E.db.general.hideErrorFrame then
+ self:RegisterEvent("PLAYER_REGEN_ENABLED", EventHandler)
+ self:RegisterEvent("PLAYER_REGEN_DISABLED", EventHandler)
+ else
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED", EventHandler)
+ self:UnregisterEvent("PLAYER_REGEN_DISABLED", EventHandler)
+ end
+ end
+end
+
+do
+ local interruptMsg = INTERRUPTED.." %s's \124cff71d5ff\124Hspell:%d\124h[%s]\124h\124r!"
+
+ function M:ToggleInterruptAnnounce()
+ if E.db.general.interruptAnnounce == "NONE" then
+ self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+ else
+ self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
+ end
+ end
+
+ function M:COMBAT_LOG_EVENT_UNFILTERED(_, _, event, sourceGUID, _, _, _, destName, _, _, _, _, spellID, spellName)
+ if not (event == "SPELL_INTERRUPT" and (sourceGUID == E.myguid or sourceGUID == UnitGUID("pet"))) then return end
+
+ if E.db.general.interruptAnnounce == "SAY" then
+ SendChatMessage(format(interruptMsg, destName, spellID, spellName), "SAY")
+ elseif E.db.general.interruptAnnounce == "EMOTE" then
+ SendChatMessage(format(interruptMsg, destName, spellID, spellName), "EMOTE")
+ else
+ local _, instanceType = IsInInstance()
+ local battleground = instanceType == "pvp"
+
+ if E.db.general.interruptAnnounce == "PARTY" then
+ if GetNumPartyMembers() > 0 then
+ SendChatMessage(format(interruptMsg, destName, spellID, spellName), battleground and "BATTLEGROUND" or "PARTY")
+ end
+ elseif E.db.general.interruptAnnounce == "RAID" then
+ if GetNumRaidMembers() > 0 then
+ SendChatMessage(format(interruptMsg, destName, spellID, spellName), battleground and "BATTLEGROUND" or "RAID")
+ elseif GetNumPartyMembers() > 0 then
+ SendChatMessage(format(interruptMsg, destName, spellID, spellName), battleground and "BATTLEGROUND" or "PARTY")
+ end
+ elseif E.db.general.interruptAnnounce == "RAID_ONLY" then
+ if GetNumRaidMembers() > 0 then
+ SendChatMessage(format(interruptMsg, destName, spellID, spellName), battleground and "BATTLEGROUND" or "RAID")
+ end
+ end
+ end
+ end
+end
+
+do
+ local repairInventoryPriority = {
+ 16, -- MainHandSlot
+ 17, -- SecondaryHandSlot
+ 18, -- RangedSlot
+ 1, -- HeadSlot
+ 5, -- ChestSlot
+ 7, -- LegsSlot
+ 3, -- ShoulderSlot
+ 10, -- HandsSlot
+ 6, -- WaistSlot
+ 8, -- FeetSlot
+ 9, -- WristSlot
+ }
+
+ local function RepairInventoryByPriority(playerMoney)
+ local money = playerMoney
+
+ ShowRepairCursor()
+
+ for _, slotID in ipairs(repairInventoryPriority) do
+ local hasItem, _, repairCost = GameTooltip:SetInventoryItem("player", slotID)
+
+ if hasItem and repairCost and repairCost > 0 and repairCost <= money then
+ PickupInventoryItem(slotID)
+ money = money - repairCost
+ end
+ end
+
+ HideRepairCursor()
+ GameTooltip:Hide()
+
+ return playerMoney - money
+ end
+
+ local function FullRepairMessage(repairAllCost)
+ E:Print(format("%s%s", L["Your items have been repaired for: "], E:FormatMoney(repairAllCost, "SMART", true)))
+ end
+
+ function M:AutoRepair(repairMode, greyValue)
+ if not CanMerchantRepair() or IsShiftKeyDown() then return end
+
+ local repairAllCost, canRepair = GetRepairAllCost()
+ if not canRepair or repairAllCost <= 0 then return end
+
+ if repairMode == "GUILD" then
+ if not CanGuildBankRepair() then
+ repairMode = "PLAYER"
+ else
+ local guildWithdrawMoney = GetGuildBankWithdrawMoney()
+ local guildMoney = GetGuildBankMoney()
+ local availableGuildMoney
+
+ if guildWithdrawMoney == -1 or guildMoney < guildWithdrawMoney then
+ availableGuildMoney = guildMoney
+ else
+ availableGuildMoney = guildWithdrawMoney
+ end
+
+ if repairAllCost > availableGuildMoney then
+ repairMode = "PLAYER"
+ end
+ end
+ end
+
+ if repairMode == "GUILD" then
+ RepairAllItems(true)
+
+ E:Print(format("%s%s", L["Your items have been repaired using guild bank funds for: "], E:FormatMoney(repairAllCost, "SMART", true)))
+ else
+ local playerMoney = GetMoney()
+
+ if playerMoney >= repairAllCost then
+ RepairAllItems()
+ FullRepairMessage(repairAllCost)
+ elseif greyValue and playerMoney + greyValue >= repairAllCost then
+ self.playerMoney = playerMoney
+ self.repairAllCost = repairAllCost
+
+ self:RegisterEvent("MERCHANT_CLOSED")
+ E.RegisterCallback(M, "VendorGreys_ItemSold")
+ elseif playerMoney > 0 then
+ local spent = RepairInventoryByPriority(playerMoney)
+
+ if spent > 0 then
+ E:Print(format("%s%s", L["Your items have been repaired for: "], E:FormatMoney(spent, "SMART", true)))
+ E:Print(L["You don't have enough money to repair all items."])
+ else
+ E:Print(L["You don't have enough money to repair."])
+ end
+ else
+ E:Print(L["You don't have enough money to repair."])
+ end
+ end
+ end
+
+ function M:VendorGreys_ItemSold(_, moneyGained)
+ self.playerMoney = self.playerMoney + moneyGained
+
+ if self.playerMoney >= self.repairAllCost then
+ if self.playerMoney > GetMoney() then
+ self:RegisterEvent("PLAYER_MONEY")
+ E.UnregisterCallback(M, "VendorGreys_ItemSold")
+ else
+ RepairAllItems()
+ FullRepairMessage(self.repairAllCost)
+ end
+ end
+ end
+
+ function M:PLAYER_MONEY()
+ if self.playerMoney <= GetMoney() then
+ RepairAllItems()
+ FullRepairMessage(self.repairAllCost)
+
+ self:MERCHANT_CLOSED()
+ end
+ end
+
+ function M:MERCHANT_CLOSED()
+ self.playerMoney = nil
+ self.repairAllCost = nil
+
+ self:UnregisterEvent("PLAYER_MONEY")
+ self:UnregisterEvent("MERCHANT_CLOSED")
+ E.UnregisterCallback(M, "VendorGreys_ItemSold")
+ end
+end
+
+function M:MERCHANT_SHOW()
+ local greyValue
+
+ if E.db.bags.vendorGrays.enable then
+ local itemCount
+ itemCount, greyValue = Bags:GetGraysInfo()
+
+ if itemCount > 0 then
+ Bags:VendorGrays()
+ end
+ end
+
+ local repairMode = E.db.general.autoRepair
+ if repairMode ~= "NONE" then
+ E:Delay(0.03, self.AutoRepair, self, repairMode, greyValue)
+ end
+end
+
+function M:DisbandRaidGroup()
+ if InCombatLockdown() then return end -- Prevent user error in combat
+
+ local numRaid = GetNumRaidMembers()
+
+ if numRaid > 0 then
+ for i = 1, numRaid do
+ local name, _, _, _, _, _, _, online = GetRaidRosterInfo(i)
+ if online and name ~= E.myname then
+ UninviteUnit(name)
+ end
+ end
+ else
+ for i = MAX_PARTY_MEMBERS, 1, -1 do
+ if GetPartyMember(i) then
+ UninviteUnit(UnitName("party"..i))
+ end
+ end
+ end
+
+ LeaveParty()
+end
+
+function M:PVPMessageEnhancement(_, msg)
+ if not E.db.general.enhancedPvpMessages then return end
+
+ local _, instanceType = IsInInstance()
+ if instanceType == "pvp" or instanceType == "arena" then
+ RaidNotice_AddMessage(RaidBossEmoteFrame, msg, ChatTypeInfo.RAID_BOSS_EMOTE)
+ end
+end
+
+function M:AutoInvite(event, leaderName)
+ if not E.db.general.autoAcceptInvite then return end
+
+ if MiniMapLFGFrame:IsShown() then return end
+ if GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0 then return end
+
+ local numFriends = GetNumFriends()
+
+ if numFriends > 0 then
+ ShowFriends()
+
+ for i = 1, numFriends do
+ if GetFriendInfo(i) == leaderName then
+ AcceptGroup()
+ StaticPopup_Hide("PARTY_INVITE")
+ return
+ end
+ end
+ end
+
+ if not IsInGuild() then return end
+
+ GuildRoster()
+
+ for i = 1, GetNumGuildMembers() do
+ if GetGuildRosterInfo(i) == leaderName then
+ AcceptGroup()
+ StaticPopup_Hide("PARTY_INVITE")
+ return
+ end
+ end
+end
+
+function M:ForceCVars(event)
+ if not GetCVarBool("lockActionBars") then
+ SetCVar("lockActionBars", 1)
+ end
+
+ if event == "PLAYER_ENTERING_WORLD" then
+ self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+ end
+end
+
+function M:Initialize()
+ self:LoadRaidMarker()
+ self:LoadLoot()
+ self:LoadLootRoll()
+ self:LoadChatBubbles()
+
+ self:ToggleErrorHandling()
+ self:ToggleInterruptAnnounce()
+
+ self:RegisterEvent("CHAT_MSG_BG_SYSTEM_HORDE", "PVPMessageEnhancement")
+ self:RegisterEvent("CHAT_MSG_BG_SYSTEM_ALLIANCE", "PVPMessageEnhancement")
+ self:RegisterEvent("CHAT_MSG_BG_SYSTEM_NEUTRAL", "PVPMessageEnhancement")
+ self:RegisterEvent("PARTY_INVITE_REQUEST", "AutoInvite")
+ self:RegisterEvent("MERCHANT_SHOW")
+
+ if E.private.actionbar.enable then
+ self:RegisterEvent("CVAR_UPDATE", "ForceCVars")
+ self:RegisterEvent("PLAYER_ENTERING_WORLD", "ForceCVars")
+ end
+
+ self.Initialized = true
+end
+
+local function InitializeCallback()
+ M:Initialize()
+end
+
+E:RegisterModule(M:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Misc/RaidBuffReminder.lua b/ElvUI/Modules/Misc/RaidBuffReminder.lua
new file mode 100644
index 0000000..ee1cf62
--- /dev/null
+++ b/ElvUI/Modules/Misc/RaidBuffReminder.lua
@@ -0,0 +1,395 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local RB = E:GetModule("ReminderBuffs")
+local LSM = E.Libs.LSM
+
+--Lua functions
+local ipairs, unpack = ipairs, unpack
+--WoW API / Variables
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local CreateFrame = CreateFrame
+local GetSpellInfo = GetSpellInfo
+local GetTime = GetTime
+local UnitAura = UnitAura
+
+RB.Spell1Buffs = {
+ 67016, -- Flask of the North (SP)
+ 67017, -- Flask of the North (AP)
+ 67018, -- Flask of the North (STR)
+ 53755, -- Flask of the Frost Wyrm
+ 53758, -- Flask of Stoneblood
+ 53760, -- Flask of Endless Rage
+ 54212, -- Flask of Pure Mojo
+ 53752, -- Lesser Flask of Toughness (50 Resilience)
+ 17627, -- Flask of Distilled Wisdom
+
+ 33721, -- Spellpower Elixir
+ 53746, -- Wrath Elixir
+ 28497, -- Elixir of Mighty Agility
+ 53748, -- Elixir of Mighty Strength
+ 60346, -- Elixir of Lightning Speed
+ 60344, -- Elixir of Expertise
+ 60341, -- Elixir of Deadly Strikes
+ 60345, -- Elixir of Armor Piercing
+ 60340, -- Elixir of Accuracy
+ 53749, -- Guru's Elixir
+
+ 60343, -- Elixir of Mighty Defense
+ 53751, -- Elixir of Mighty Fortitude
+ 53764, -- Elixir of Mighty Mageblood
+ 60347, -- Elixir of Mighty Thoughts
+ 53763, -- Elixir of Protection
+ 53747, -- Elixir of Spirit
+}
+
+RB.Spell2Buffs = {
+ 57325, -- 80 AP
+ 57327, -- 46 SP
+ 57329, -- 40 Critical Strike Rating
+ 57332, -- 40 Haste Rating
+ 57334, -- 20 MP5
+ 57356, -- 40 Expertise Rating
+ 57358, -- 40 ARP
+ 57360, -- 40 Hit Rating
+ 57363, -- Tracking Humanoids
+ 57365, -- 40 Spirit
+ 57367, -- 40 AGI
+ 57371, -- 40 STR
+ 57373, -- Tracking Beasts
+ 57399, -- 80 AP, 46 SP
+ 59230, -- 40 Dodge Rating
+ 65247, -- 20 STR
+}
+
+RB.Spell3Buffs = {
+ 72588, -- Gift of the Wild
+ 48469, -- Mark of the Wild
+}
+
+RB.Spell4Buffs = {
+ 25898, -- Greater Blessing of Kings
+ 20217, -- Blessing of Kings
+ 72586, -- Blessing of Forgotten Kings
+}
+
+RB.Spell5Buffs = {
+ 48162, -- Prayer of Fortitude
+ 48161, -- Power Word: Fortitude
+ 72590, -- Fortitude
+}
+
+RB.Spell6Buffs = {
+ 20911, -- Blessing of Sanctuary
+ 25899, -- Greater Blessing of Sanctuary
+}
+
+RB.CasterSpell7Buffs = {
+ 61316, -- Dalaran Brilliance
+ 43002, -- Arcane Brilliance
+ 42995, -- Arcane Intellect
+}
+
+RB.AttackSpell7Buffs = {
+ 48934, -- Greater Blessing of Might
+ 48932, -- Blessing of Might
+ 47436, -- Battle Shout
+}
+
+RB.Spell8Buffs = {
+ 6307, -- Blood Pact
+ 469, -- Commanding Shout
+}
+
+-- Armor buffs
+RB.Spell9Buffs = {
+ 25506, -- Stoneskin Totem
+ 465, -- Devotion Aura
+}
+
+-- Concentration / Thorns
+RB.CasterSpell10Buffs = {
+ 19746, -- Concentration Aura
+}
+RB.AttackSpell10Buffs = {
+ 467, -- Thorns
+ 7294, -- Retribution Aura
+}
+
+-- SP / Str+Dex totems
+RB.CasterSpell11Buffs = {
+ 30706, -- Totem of Wrath
+ 8227, -- Flametongue Totem
+ 47236, -- Demonic Pact
+}
+RB.AttackSpell11Buffs = {
+ 25527, -- Strength of Earth Totem
+}
+
+-- Mana regen
+RB.Spell12Buffs = {
+ 48938, -- Greater Blessing of Wisdom
+ 48936, -- Blessing of Wisdom
+ 58777, -- Mana Spring
+}
+
+-- Crit % Increase
+RB.CasterSpell13Buffs = {
+ 51471, -- Elemental Oath
+ 24907, -- Moonkin Aura
+}
+RB.AttackSpell13Buffs = {
+ 17007, -- Leader of the Pack
+ 29801, -- Rampage
+}
+
+-- Haste % Increase
+RB.CasterSpell14Buffs = {
+ 50172, -- Moonkin's Presence
+ 2895, -- Wrath of Air
+ 853648, -- Swift Retribution
+}
+RB.AttackSpell14Buffs = {
+ 8512, -- Windfury Totem
+}
+
+-- Spirit Buff
+RB.CasterSpell15Buffs = {
+ 14752, -- Divine Spirit
+ 27681, -- Prayer of Spirit
+}
+-- Percent AP
+RB.AttackSpell15Buffs = {
+ 19506, -- Trueshot Aura
+ 30802, -- Unleashed Rage
+ 53137, -- Abomination's Might
+}
+
+-- Percent Damage
+RB.Spell16Buffs = {
+ 31579, -- Arcane Empowerment
+ 31869, -- Sanctified Retribution
+ 34455, -- Ferocious Inspiration
+}
+
+function RB:CheckFilterForActiveBuff(filter)
+ for _, spell in ipairs(filter) do
+ local spellName = GetSpellInfo(spell)
+ local name, _, texture, _, _, duration, expirationTime = UnitAura("player", spellName)
+
+ if name then
+ return texture, duration, expirationTime
+ end
+ end
+end
+
+function RB:UpdateReminderTime(elapsed)
+ self.expiration = self.expiration - elapsed
+
+ if self.nextUpdate > 0 then
+ self.nextUpdate = self.nextUpdate - elapsed
+ return
+ end
+
+ if self.expiration <= 0 then
+ self.timer:SetText("")
+ self:SetScript("OnUpdate", nil)
+ return
+ end
+
+ local value, id, nextUpdate, remainder = E:GetTimeInfo(self.expiration, 4)
+ self.nextUpdate = nextUpdate
+
+ local style = E.TimeFormats[id]
+ if style then
+ self.timer:SetFormattedText(style[1], value, remainder)
+ end
+end
+
+function RB:UpdateReminder(event, unit)
+ if event == "UNIT_AURA" and unit ~= "player" then return end
+
+ for i = 1, 16 do
+ local texture, duration, expirationTime = self:CheckFilterForActiveBuff(self["Spell"..i.."Buffs"])
+ local button = self.frame[i]
+
+ if texture then
+ button.t:SetTexture(texture)
+
+ if (duration == 0 and expirationTime == 0) or E.db.general.reminder.durations ~= true then
+ button.t:SetAlpha(E.db.general.reminder.reverse and 1 or 0.3)
+ button:SetScript("OnUpdate", nil)
+ button.timer:SetText(nil)
+ CooldownFrame_SetTimer(button.cd, 0, 0, 0)
+ else
+ button.expiration = expirationTime - GetTime()
+ button.nextUpdate = 0
+ button.t:SetAlpha(1)
+ CooldownFrame_SetTimer(button.cd, expirationTime - duration, duration, 1)
+ button.cd:SetReverse(E.db.general.reminder.reverse)
+ button:SetScript("OnUpdate", self.UpdateReminderTime)
+ end
+ else
+ CooldownFrame_SetTimer(button.cd, 0, 0, 0)
+ button.t:SetAlpha(E.db.general.reminder.reverse and 0.3 or 1)
+ button:SetScript("OnUpdate", nil)
+ button.timer:SetText(nil)
+ button.t:SetTexture(self.DefaultIcons[i])
+ end
+ end
+end
+
+function RB:CreateButton()
+ local button = CreateFrame("Button", nil, ElvUI_ReminderBuffs)
+ button:SetTemplate("Default")
+
+ button.t = button:CreateTexture(nil, "OVERLAY")
+ button.t:SetTexCoord(unpack(E.TexCoords))
+ button.t:SetInside()
+ button.t:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
+
+ button.cd = CreateFrame("Cooldown", nil, button, "CooldownFrameTemplate")
+ button.cd:SetInside()
+ button.cd.noOCC = true
+ button.cd.noCooldownCount = true
+
+ button.timer = button.cd:CreateFontString(nil, "OVERLAY")
+ button.timer:SetPoint("CENTER")
+
+ return button
+end
+
+function RB:EnableRB()
+ ElvUI_ReminderBuffs:Show()
+ self:RegisterEvent("UNIT_AURA", "UpdateReminder")
+ self:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED", "UpdateReminder")
+ self:RegisterEvent("CHARACTER_POINTS_CHANGED", "UpdateReminder")
+ E.RegisterCallback(self, "RoleChanged", "UpdateSettings")
+ self:UpdateReminder()
+end
+
+function RB:DisableRB()
+ ElvUI_ReminderBuffs:Hide()
+ self:UnregisterEvent("UNIT_AURA")
+ self:UnregisterEvent("ACTIVE_TALENT_GROUP_CHANGED")
+ self:UnregisterEvent("CHARACTER_POINTS_CHANGED")
+ E.UnregisterCallback(self, "RoleChanged", "UpdateSettings")
+end
+
+function RB:UpdateSettings(isCallback)
+ local frame = self.frame
+ frame:Width(E.RBRWidth * 2)
+
+ self:UpdateDefaultIcons()
+
+ for i = 1, 16 do
+ local button = frame[i]
+ button:ClearAllPoints()
+ button:SetWidth(E.RBRWidth)
+ button:SetHeight(E.RBRWidth)
+
+ if i == 1 then
+ button:SetPoint("TOPLEFT", ElvUI_ReminderBuffs, "TOPLEFT", 0, -1)
+ elseif i == 9 then
+ button:SetPoint("TOPRIGHT", ElvUI_ReminderBuffs, "TOPRIGHT", 0, -1)
+ else
+ button:Point("TOP", frame[i - 1], "BOTTOM", 0, E.Border - E.Spacing*3)
+ end
+
+ if E.db.general.reminder.durations then
+ button.cd:SetAlpha(1)
+ else
+ button.cd:SetAlpha(0)
+ end
+
+ button.timer:FontTemplate(LSM:Fetch("font", E.db.general.reminder.font), E.db.general.reminder.fontSize, E.db.general.reminder.fontOutline)
+ end
+
+ if not isCallback then
+ if E.db.general.reminder.enable then
+ RB:EnableRB()
+ else
+ RB:DisableRB()
+ end
+ else
+ self:UpdateReminder()
+ end
+end
+
+function RB:UpdatePosition()
+ Minimap:ClearAllPoints()
+ ElvConfigToggle:ClearAllPoints()
+ ElvUI_ReminderBuffs:ClearAllPoints()
+ if E.db.general.reminder.position == "LEFT" then
+ Minimap:Point("TOPRIGHT", MMHolder, "TOPRIGHT", -E.Border, -E.Border)
+ ElvConfigToggle:SetPoint("TOPRIGHT", LeftMiniPanel, "TOPLEFT", E.Border - E.Spacing*3, 0)
+ ElvConfigToggle:SetPoint("BOTTOMRIGHT", LeftMiniPanel, "BOTTOMLEFT", E.Border - E.Spacing*3, 0)
+ ElvUI_ReminderBuffs:SetPoint("TOPRIGHT", Minimap.backdrop, "TOPLEFT", E.Border - E.Spacing*3, 0)
+ ElvUI_ReminderBuffs:SetPoint("BOTTOMRIGHT", Minimap.backdrop, "BOTTOMLEFT", E.Border - E.Spacing*3, 0)
+ else
+ Minimap:Point("TOPLEFT", MMHolder, "TOPLEFT", E.Border, -E.Border)
+ ElvConfigToggle:SetPoint("TOPLEFT", RightMiniPanel, "TOPRIGHT", -E.Border + E.Spacing*3, 0)
+ ElvConfigToggle:SetPoint("BOTTOMLEFT", RightMiniPanel, "BOTTOMRIGHT", -E.Border + E.Spacing*3, 0)
+ ElvUI_ReminderBuffs:SetPoint("TOPLEFT", Minimap.backdrop, "TOPRIGHT", -E.Border + E.Spacing*3, 0)
+ ElvUI_ReminderBuffs:SetPoint("BOTTOMLEFT", Minimap.backdrop, "BOTTOMRIGHT", -E.Border + E.Spacing*3, 0)
+ end
+end
+
+function RB:UpdateDefaultIcons()
+ local isCaster = E.private.general.reminder.classtype == "Caster"
+ self.DefaultIcons = {
+ [1] = "Interface\\Icons\\INV_Potion_97",
+ [2] = "Interface\\Icons\\Spell_Misc_Food",
+ [3] = "Interface\\Icons\\Spell_Nature_Regeneration",
+ [4] = "Interface\\Icons\\Spell_Magic_GreaterBlessingofKings",
+ [5] = "Interface\\Icons\\Spell_Holy_WordFortitude",
+ [6] = "Interface\\Icons\\spell_nature_lightningshield",
+ [7] = (isCaster and "Interface\\Icons\\Spell_Holy_MagicalSentry") or "Interface\\Icons\\spell_holy_fistofjustice",
+ [8] = "Interface\\Icons\\ability_warrior_rallyingcry",
+ [9] = "Interface\\Icons\\spell_nature_stoneskintotem",
+ [10] = (isCaster and "Interface\\Icons\\spell_holy_mindsooth") or "Interface\\Icons\\spell_nature_thorns",
+ [11] = (isCaster and "Interface\\Icons\\spell_fire_totemofwrath") or "Interface\\Icons\\spell_nature_earthbindtotem",
+ [12] = "Interface\\Icons\\Spell_Holy_GreaterBlessingofWisdom",
+ [13] = (isCaster and "Interface\\Icons\\spell_nature_moonglow") or "Interface\\Icons\\spell_nature_unyeildingstamina",
+ [14] = (isCaster and "Interface\\Icons\\spell_nature_forceofnature") or "Interface\\Icons\\spell_nature_windfury",
+ [15] = (isCaster and "Interface\\Icons\\spell_holy_prayerofspirit") or "Interface\\Icons\\ability_trueshot",
+ [16] = "Interface\\Icons\\spell_nature_starfall",
+ }
+
+ self.Spell7Buffs = isCaster and self.CasterSpell7Buffs or self.AttackSpell7Buffs
+
+ self.Spell10Buffs = isCaster and self.CasterSpell10Buffs or self.AttackSpell10Buffs
+ self.Spell11Buffs = isCaster and self.CasterSpell11Buffs or self.AttackSpell11Buffs
+
+ self.Spell13Buffs = isCaster and self.CasterSpell13Buffs or self.AttackSpell13Buffs
+ self.Spell14Buffs = isCaster and self.CasterSpell14Buffs or self.AttackSpell14Buffs
+ self.Spell15Buffs = isCaster and self.CasterSpell15Buffs or self.AttackSpell15Buffs
+end
+
+function RB:Initialize()
+ if not E.private.general.minimap.enable then return end
+
+ self.db = E.db.general.reminder
+
+ local frame = CreateFrame("Frame", "ElvUI_ReminderBuffs", Minimap)
+ frame:Width(E.RBRWidth)
+ if E.db.general.reminder.position == "LEFT" then
+ frame:Point("TOPRIGHT", Minimap.backdrop, "TOPLEFT", E.Border - E.Spacing*3, 0)
+ frame:Point("BOTTOMRIGHT", Minimap.backdrop, "BOTTOMLEFT", E.Border - E.Spacing*3, 0)
+ else
+ frame:Point("TOPLEFT", Minimap.backdrop, "TOPRIGHT", -E.Border + E.Spacing*3, 0)
+ frame:Point("BOTTOMLEFT", Minimap.backdrop, "BOTTOMRIGHT", -E.Border + E.Spacing*3, 0)
+ end
+ self.frame = frame
+
+ for i = 1, 16 do
+ frame[i] = self:CreateButton()
+ frame[i]:SetID(i)
+ end
+
+ self:UpdateSettings()
+end
+
+local function InitializeCallback()
+ RB:Initialize()
+end
+
+E:RegisterModule(RB:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Misc/RaidMarker.lua b/ElvUI/Modules/Misc/RaidMarker.lua
new file mode 100644
index 0000000..347f450
--- /dev/null
+++ b/ElvUI/Modules/Misc/RaidMarker.lua
@@ -0,0 +1,104 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local M = E:GetModule("Misc")
+
+--Lua functions
+local sin, cos, pi = math.sin, math.cos, math.pi
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetNumPartyMembers = GetNumPartyMembers
+local UnitInRaid = UnitInRaid
+local UnitIsPartyLeader = UnitIsPartyLeader
+local UnitIsRaidOfficer = UnitIsRaidOfficer
+local UnitExists, UnitIsDead = UnitExists, UnitIsDead
+local GetCursorPosition = GetCursorPosition
+local PlaySound = PlaySound
+local SetRaidTarget = SetRaidTarget
+local SetRaidTargetIconTexture = SetRaidTargetIconTexture
+local UIErrorsFrame = UIErrorsFrame
+
+local ButtonIsDown
+
+function M:RaidMarkCanMark()
+ if not self.RaidMarkFrame then return false end
+
+ if GetNumPartyMembers() > 0 then
+ if UnitIsPartyLeader("player") or (UnitInRaid("player") and UnitIsRaidOfficer("player") and not UnitIsPartyLeader("player")) then
+ return true
+ else
+ UIErrorsFrame:AddMessage(L["You don't have permission to mark targets."], 1.0, 0.1, 0.1, 1.0)
+ return false
+ end
+ else
+ return true
+ end
+end
+
+function M:RaidMarkShowIcons()
+ if not UnitExists("target") or UnitIsDead("target") then return end
+
+ local x, y = GetCursorPosition()
+ local scale = E.UIParent:GetEffectiveScale()
+ self.RaidMarkFrame:Point("CENTER", E.UIParent, "BOTTOMLEFT", x / scale, y / scale)
+ self.RaidMarkFrame:Show()
+end
+
+function RaidMark_HotkeyPressed(keystate)
+ ButtonIsDown = (keystate == "down") and M:RaidMarkCanMark()
+ if ButtonIsDown and M.RaidMarkFrame then
+ M:RaidMarkShowIcons()
+ elseif M.RaidMarkFrame then
+ M.RaidMarkFrame:Hide()
+ end
+end
+
+function M:RaidMark_OnEvent()
+ if ButtonIsDown and self.RaidMarkFrame then
+ self:RaidMarkShowIcons()
+ end
+end
+M:RegisterEvent("PLAYER_TARGET_CHANGED", "RaidMark_OnEvent")
+
+function M:RaidMarkButton_OnEnter()
+ self.Texture:ClearAllPoints()
+ self.Texture:Point("TOPLEFT", -10, 10)
+ self.Texture:Point("BOTTOMRIGHT", 10, -10)
+end
+
+function M:RaidMarkButton_OnLeave()
+ self.Texture:SetAllPoints()
+end
+
+function M:RaidMarkButton_OnClick(button)
+ PlaySound("UChatScrollButton")
+ SetRaidTarget("target", (button ~= "RightButton") and self:GetID() or 0)
+ self:GetParent():Hide()
+end
+
+function M:LoadRaidMarker()
+ local marker = CreateFrame("Frame", nil, E.UIParent)
+ marker:EnableMouse(true)
+ marker:Size(100)
+ marker:SetFrameStrata("DIALOG")
+
+ for i = 1, 8 do
+ local button = CreateFrame("Button", "RaidMarkIconButton"..i, marker)
+ button:Size(40)
+ button:SetID(i)
+ button.Texture = button:CreateTexture(button:GetName().."NormalTexture", "ARTWORK")
+ button.Texture:SetTexture([[Interface\TargetingFrame\UI-RaidTargetingIcons]])
+ button.Texture:SetAllPoints()
+ SetRaidTargetIconTexture(button.Texture, i)
+ button:RegisterForClicks("LeftbuttonUp","RightbuttonUp")
+ button:SetScript("OnClick", M.RaidMarkButton_OnClick)
+ button:SetScript("OnEnter", M.RaidMarkButton_OnEnter)
+ button:SetScript("OnLeave", M.RaidMarkButton_OnLeave)
+ if i == 8 then
+ button:Point("CENTER")
+ else
+ local angle = pi / 0.7 * i
+ button:Point("CENTER", sin(angle) * 60, cos(angle) * 60)
+ end
+ end
+
+ M.RaidMarkFrame = marker
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Misc/RaidUtility.lua b/ElvUI/Modules/Misc/RaidUtility.lua
new file mode 100644
index 0000000..84ebd6b
--- /dev/null
+++ b/ElvUI/Modules/Misc/RaidUtility.lua
@@ -0,0 +1,225 @@
+local E, L = unpack(select(2, ...)); --Import: Engine, Locales
+local RU = E:GetModule("RaidUtility")
+local S = E:GetModule("Skins")
+
+--Lua functions
+local find = string.find
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local IsInInstance = IsInInstance
+local GetNumRaidMembers = GetNumRaidMembers
+local GetNumPartyMembers = GetNumPartyMembers
+local IsPartyLeader = IsPartyLeader
+local IsRaidLeader = IsRaidLeader
+local IsRaidOfficer = IsRaidOfficer
+local InCombatLockdown = InCombatLockdown
+local DoReadyCheck = DoReadyCheck
+local ToggleFriendsFrame = ToggleFriendsFrame
+
+local PANEL_HEIGHT = 100
+
+local function CheckRaidStatus()
+ local inInstance, instanceType = IsInInstance()
+ if (((IsRaidLeader() or IsRaidOfficer()) and GetNumRaidMembers() > 0) or (IsPartyLeader() and GetNumPartyMembers() > 0)) and not (inInstance and (instanceType == "pvp" or instanceType == "arena")) then
+ return true
+ else
+ return false
+ end
+end
+
+-- Function to create buttons in this module
+function RU:CreateUtilButton(name, parent, template, width, height, point, relativeto, point2, xOfs, yOfs, text, texture)
+ local button = CreateFrame("Button", name, parent, template)
+ button:Width(width)
+ button:Height(height)
+ button:Point(point, relativeto, point2, xOfs, yOfs)
+ S:HandleButton(button)
+
+ if text then
+ button.text = button:CreateFontString(nil, "OVERLAY", button)
+ button.text:FontTemplate()
+ button.text:Point("CENTER", button, "CENTER", 0, -1)
+ button.text:SetJustifyH("CENTER")
+ button.text:SetText(text)
+ button:SetFontString(button.text)
+ elseif texture then
+ button.texture = button:CreateTexture(nil, "OVERLAY", nil)
+ button.texture:SetTexture(texture)
+ button.texture:Point("TOPLEFT", button, "TOPLEFT", E.mult, -E.mult)
+ button.texture:Point("BOTTOMRIGHT", button, "BOTTOMRIGHT", -E.mult, E.mult)
+ end
+end
+
+function RU:ToggleRaidUtil(event)
+ if InCombatLockdown() then
+ self:RegisterEvent("PLAYER_REGEN_ENABLED", "ToggleRaidUtil")
+ return
+ end
+
+ if CheckRaidStatus() then
+ if RaidUtilityPanel.toggled == true then
+ RaidUtility_ShowButton:Hide()
+ RaidUtilityPanel:Show()
+ else
+ RaidUtility_ShowButton:Show()
+ RaidUtilityPanel:Hide()
+ end
+ else
+ RaidUtility_ShowButton:Hide()
+ RaidUtilityPanel:Hide()
+ end
+
+ if event == "PLAYER_REGEN_ENABLED" then
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED", "ToggleRaidUtil")
+ end
+end
+
+function RU:Initialize()
+ if not E.private.general.raidUtility then return end
+ self.Initialized = true
+
+ --Create main frame
+ local RaidUtilityPanel = CreateFrame("Frame", "RaidUtilityPanel", E.UIParent, "SecureHandlerClickTemplate")
+ RaidUtilityPanel:SetTemplate("Transparent")
+ RaidUtilityPanel:Width(230)
+ RaidUtilityPanel:Height(PANEL_HEIGHT)
+ RaidUtilityPanel:Point("TOP", E.UIParent, "TOP", -400, 1)
+ RaidUtilityPanel:SetFrameLevel(3)
+ RaidUtilityPanel.toggled = false
+ RaidUtilityPanel:SetFrameStrata("HIGH")
+
+ self:CreateUtilButton("RaidUtility_ShowButton", E.UIParent, "SecureHandlerClickTemplate", 136, 18, "TOP", E.UIParent, "TOP", -400, E.Border, RAID_CONTROL, nil)
+ RaidUtility_ShowButton:SetFrameRef("RaidUtilityPanel", RaidUtilityPanel)
+ RaidUtility_ShowButton:SetAttribute("_onclick", ([=[
+ local raidUtil = self:GetFrameRef("RaidUtilityPanel")
+ local closeButton = raidUtil:GetFrameRef("RaidUtility_CloseButton")
+
+ self:Hide()
+ raidUtil:Show()
+
+ local point = self:GetPoint()
+ local raidUtilPoint, closeButtonPoint, yOffset
+
+ if string.find(point, "BOTTOM") then
+ raidUtilPoint = "BOTTOM"
+ closeButtonPoint = "TOP"
+ yOffset = 1
+ else
+ raidUtilPoint = "TOP"
+ closeButtonPoint = "BOTTOM"
+ yOffset = -1
+ end
+
+ yOffset = yOffset * (tonumber(%d))
+
+ raidUtil:ClearAllPoints()
+ closeButton:ClearAllPoints()
+ raidUtil:SetPoint(raidUtilPoint, self, raidUtilPoint)
+ closeButton:SetPoint(raidUtilPoint, raidUtil, closeButtonPoint, 0, yOffset)
+ ]=]):format(-E.Border + E.Spacing * 3))
+ RaidUtility_ShowButton:SetScript("OnMouseUp", function()
+ RaidUtilityPanel.toggled = true
+ end)
+ RaidUtility_ShowButton:SetMovable(true)
+ RaidUtility_ShowButton:SetClampedToScreen(true)
+ RaidUtility_ShowButton:SetClampRectInsets(0, 0, -1, 1)
+ RaidUtility_ShowButton:RegisterForDrag("RightButton")
+ RaidUtility_ShowButton:SetFrameStrata("HIGH")
+ RaidUtility_ShowButton:SetScript("OnDragStart", function(self)
+ if InCombatLockdown() then E:Print(ERR_NOT_IN_COMBAT) return end
+ self:StartMoving()
+ end)
+
+ RaidUtility_ShowButton:SetScript("OnDragStop", function(self)
+ self:StopMovingOrSizing()
+ local point = self:GetPoint()
+ local xOffset = self:GetCenter()
+ local screenWidth = E.UIParent:GetWidth() / 2
+ xOffset = xOffset - screenWidth
+ self:ClearAllPoints()
+ if find(point, "BOTTOM") then
+ self:Point("BOTTOM", E.UIParent, "BOTTOM", xOffset, -1)
+ else
+ self:Point("TOP", E.UIParent, "TOP", xOffset, 1)
+ end
+ end)
+
+ self:CreateUtilButton("RaidUtility_CloseButton", RaidUtilityPanel, "SecureHandlerClickTemplate", 136, 18, "TOP", RaidUtilityPanel, "BOTTOM", 0, -1, CLOSE, nil)
+ RaidUtility_CloseButton:SetFrameRef("RaidUtility_ShowButton", RaidUtility_ShowButton)
+ RaidUtility_CloseButton:SetAttribute("_onclick", [=[self:GetParent():Hide(); self:GetFrameRef("RaidUtility_ShowButton"):Show();]=])
+ RaidUtility_CloseButton:SetScript("OnMouseUp", function() RaidUtilityPanel.toggled = false end)
+ RaidUtilityPanel:SetFrameRef("RaidUtility_CloseButton", RaidUtility_CloseButton)
+
+ self:CreateUtilButton("DisbandRaidButton", RaidUtilityPanel, nil, RaidUtilityPanel:GetWidth() * 0.8, 18, "TOP", RaidUtilityPanel, "TOP", 0, -5, L["Disband Group"], nil)
+ DisbandRaidButton:SetScript("OnMouseUp", function()
+ if CheckRaidStatus() then
+ E:StaticPopup_Show("DISBAND_RAID")
+ end
+ end)
+
+ self:CreateUtilButton("MainTankButton", RaidUtilityPanel, "SecureActionButtonTemplate", (DisbandRaidButton:GetWidth() / 2) - 2, 18, "TOPLEFT", DisbandRaidButton, "BOTTOMLEFT", 0, -5, MAINTANK, nil)
+ MainTankButton:SetAttribute("type", "maintank")
+ MainTankButton:SetAttribute("unit", "target")
+ MainTankButton:SetAttribute("action", "toggle")
+
+ self:CreateUtilButton("MainAssistButton", RaidUtilityPanel, "SecureActionButtonTemplate", (DisbandRaidButton:GetWidth() / 2) - 2, 18, "TOPRIGHT", DisbandRaidButton, "BOTTOMRIGHT", 0, -5, MAINASSIST, nil)
+ MainAssistButton:SetAttribute("type", "mainassist")
+ MainAssistButton:SetAttribute("unit", "target")
+ MainAssistButton:SetAttribute("action", "toggle")
+
+ self:CreateUtilButton("ReadyCheckButton", RaidUtilityPanel, nil, RaidUtilityPanel:GetWidth() * 0.8, 18, "TOPLEFT", MainTankButton, "BOTTOMLEFT", 0, -5, READY_CHECK, nil)
+ ReadyCheckButton:SetScript("OnMouseUp", function()
+ if CheckRaidStatus() then
+ DoReadyCheck()
+ end
+ end)
+ ReadyCheckButton:SetScript("OnEvent", function(btn)
+ if not (IsRaidLeader("player") or IsRaidOfficer("player")) then
+ btn:Disable()
+ else
+ btn:Enable()
+ end
+ end)
+ ReadyCheckButton:RegisterEvent("RAID_ROSTER_UPDATE")
+ ReadyCheckButton:RegisterEvent("PARTY_MEMBERS_CHANGED")
+ ReadyCheckButton:RegisterEvent("PLAYER_ENTERING_WORLD")
+
+ self:CreateUtilButton("RaidControlButton", RaidUtilityPanel, nil, MainTankButton:GetWidth(), 18, "TOPLEFT", ReadyCheckButton, "BOTTOMLEFT", 0, -5, L["Raid Menu"], nil)
+ RaidControlButton:SetScript("OnMouseUp", function()
+ if InCombatLockdown() then E:Print(ERR_NOT_IN_COMBAT) return end
+ ToggleFriendsFrame(5)
+ end)
+
+ self:CreateUtilButton("ConvertRaidButton", RaidUtilityPanel, nil, MainAssistButton:GetWidth(), 18, "TOPRIGHT", ReadyCheckButton, "BOTTOMRIGHT", 0, -5, CONVERT_TO_RAID, nil)
+ ConvertRaidButton:SetScript("OnMouseUp", function()
+ if CheckRaidStatus() then
+ ConvertToRaid()
+ SetLootMethod("master", "player")
+ end
+ end)
+ ConvertRaidButton:SetScript("OnEvent", function(btn)
+ if GetNumRaidMembers() == 0 and GetNumPartyMembers() > 0 and IsPartyLeader() then
+ if not btn:IsShown() then
+ RaidControlButton:Width(MainAssistButton:GetWidth())
+ btn:Show()
+ end
+ elseif btn:IsShown() then
+ RaidControlButton:Width(DisbandRaidButton:GetWidth())
+ btn:Hide()
+ end
+ end)
+ ConvertRaidButton:RegisterEvent("RAID_ROSTER_UPDATE")
+ ConvertRaidButton:RegisterEvent("PARTY_MEMBERS_CHANGED")
+ ConvertRaidButton:RegisterEvent("PLAYER_ENTERING_WORLD")
+
+ --Automatically show/hide the frame if we have RaidLeader or RaidOfficer
+ self:RegisterEvent("RAID_ROSTER_UPDATE", "ToggleRaidUtil")
+ self:RegisterEvent("PLAYER_ENTERING_WORLD", "ToggleRaidUtil")
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED", "ToggleRaidUtil")
+end
+
+local function InitializeCallback()
+ RU:Initialize()
+end
+
+E:RegisterInitialModule(RU:GetName(), InitializeCallback)
diff --git a/ElvUI/Modules/Misc/Threat.lua b/ElvUI/Modules/Misc/Threat.lua
new file mode 100644
index 0000000..47c3d46
--- /dev/null
+++ b/ElvUI/Modules/Misc/Threat.lua
@@ -0,0 +1,176 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local THREAT = E:GetModule("Threat")
+local DT = E:GetModule("DataTexts")
+
+--Lua functions
+local pairs, select = pairs, select
+local wipe = table.wipe
+--WoW API / Variables
+local GetNumPartyMembers = GetNumPartyMembers
+local GetNumRaidMembers = GetNumRaidMembers
+local GetThreatStatusColor = GetThreatStatusColor
+local UnitDetailedThreatSituation = UnitDetailedThreatSituation
+local UnitExists = UnitExists
+local UnitIsPlayer = UnitIsPlayer
+local UnitIsUnit = UnitIsUnit
+local UnitName = UnitName
+local UnitReaction = UnitReaction
+
+local UNKNOWN = UNKNOWN
+
+local partyUnits, raidUnits = {}, {}
+for i = 1, 4 do partyUnits[i] = "party"..i end
+for i = 1, 40 do raidUnits[i] = "raid"..i end
+
+function THREAT:UpdatePosition()
+ if self.db.position == "RIGHTCHAT" then
+ self.bar:SetInside(RightChatDataPanel)
+ self.bar:SetParent(RightChatDataPanel)
+ else
+ self.bar:SetInside(LeftChatDataPanel)
+ self.bar:SetParent(LeftChatDataPanel)
+ end
+
+ self.bar.text:FontTemplate(nil, self.db.textSize)
+ self.bar:SetFrameStrata("MEDIUM")
+end
+
+function THREAT:GetLargestThreatOnList(percent)
+ local largestValue, largestUnit = 0
+ for unit, threatPercent in pairs(self.list) do
+ if threatPercent > largestValue then
+ largestValue = threatPercent
+ largestUnit = unit
+ end
+ end
+
+ return (percent - largestValue), largestUnit
+end
+
+function THREAT:GetColor(unit)
+ if UnitIsPlayer(unit) then
+ local class = E.media.herocolor
+ if not class then
+ return 194, 194, 194
+ end
+
+ return class.r*255, class.g*255, class.b*255
+ end
+
+ local unitReaction = UnitReaction(unit, "player")
+ if unitReaction then
+ local reaction = ElvUF.colors.reaction[unitReaction]
+ return reaction[1]*255, reaction[2]*255, reaction[3]*255
+ else
+ return 194, 194, 194
+ end
+end
+
+function THREAT:Update()
+ if not UnitExists("target") or (DT and DT.ShowingBGStats) then
+ if self.bar:IsShown() then
+ self.bar:Hide()
+ end
+
+ return
+ end
+
+ local _, status, percent = UnitDetailedThreatSituation("player", "target")
+ local petExists = HasPetUI()
+
+ if percent and percent > 0 and (GetNumPartyMembers() > 0 or petExists == 1) then
+ local name = UnitName("target")
+ self.bar:Show()
+
+ if percent == 100 then
+ if petExists == 1 then
+ self.list.pet = select(3, UnitDetailedThreatSituation("pet", "target"))
+ end
+
+ if GetNumRaidMembers() > 0 then
+ for i = 1, 40 do
+ if UnitExists(raidUnits[i]) and not UnitIsUnit(raidUnits[i], "player") then
+ self.list[raidUnits[i]] = select(3, UnitDetailedThreatSituation(raidUnits[i], "target"))
+ end
+ end
+ else
+ for i = 1, 4 do
+ if UnitExists(partyUnits[i]) then
+ self.list[partyUnits[i]] = select(3, UnitDetailedThreatSituation(partyUnits[i], "target"))
+ end
+ end
+ end
+
+ local leadPercent, largestUnit = self:GetLargestThreatOnList(percent)
+ if leadPercent > 0 and largestUnit then
+ local r, g, b = self:GetColor(largestUnit)
+ self.bar.text:SetFormattedText(L["ABOVE_THREAT_FORMAT"], name, percent, leadPercent, r, g, b, UnitName(largestUnit) or UNKNOWN)
+
+ if E.Role == "Tank" then
+ self.bar:SetStatusBarColor(0, 0.839, 0)
+ self.bar:SetValue(leadPercent)
+ else
+ self.bar:SetStatusBarColor(GetThreatStatusColor(status))
+ self.bar:SetValue(percent)
+ end
+ else
+ self.bar:SetStatusBarColor(GetThreatStatusColor(status))
+ self.bar:SetValue(percent)
+ self.bar.text:SetFormattedText("%s: %.0f%%", name, percent)
+ end
+ else
+ self.bar:SetStatusBarColor(GetThreatStatusColor(status))
+ self.bar:SetValue(percent)
+ self.bar.text:SetFormattedText("%s: %.0f%%", name, percent)
+ end
+ else
+ self.bar:Hide()
+ end
+
+ wipe(self.list)
+end
+
+function THREAT:ToggleEnable()
+ if self.db.enable then
+ self:RegisterEvent("PLAYER_TARGET_CHANGED", "Update")
+ self:RegisterEvent("UNIT_THREAT_LIST_UPDATE", "Update")
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED", "Update")
+ self:RegisterEvent("RAID_ROSTER_UPDATE", "Update")
+ self:RegisterEvent("UNIT_PET", "Update")
+ self:Update()
+ else
+ self.bar:Hide()
+ self:UnregisterEvent("PLAYER_TARGET_CHANGED")
+ self:UnregisterEvent("UNIT_THREAT_LIST_UPDATE")
+ self:UnregisterEvent("PARTY_MEMBERS_CHANGED")
+ self:UnregisterEvent("RAID_ROSTER_UPDATE")
+ self:UnregisterEvent("UNIT_PET")
+ end
+end
+
+function THREAT:Initialize()
+ self.db = E.db.general.threat
+
+ self.bar = CreateFrame("StatusBar", "ElvUI_ThreatBar", E.UIParent)
+ self.bar:CreateBackdrop("Default")
+ self.bar:SetMinMaxValues(0, 100)
+ self.bar:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(self.bar)
+
+ self.bar.text = self.bar:CreateFontString(nil, "OVERLAY")
+ self.bar.text:FontTemplate(nil, self.db.textSize)
+ self.bar.text:Point("CENTER", self.bar, "CENTER")
+
+ self.list = {}
+
+ self:UpdatePosition()
+ self:ToggleEnable()
+
+ self.Initialized = true
+end
+
+local function InitializeCallback()
+ THREAT:Initialize()
+end
+
+E:RegisterModule(THREAT:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Misc/TotemBar.lua b/ElvUI/Modules/Misc/TotemBar.lua
new file mode 100644
index 0000000..a7f7846
--- /dev/null
+++ b/ElvUI/Modules/Misc/TotemBar.lua
@@ -0,0 +1,181 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local TOTEMS = E:GetModule("Totems")
+
+--Lua functions
+local unpack = unpack
+--WoW API / Variables
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local CreateFrame = CreateFrame
+local DestroyTotem = DestroyTotem
+local GetTotemInfo = GetTotemInfo
+
+local MAX_TOTEMS = MAX_TOTEMS
+local TOTEM_PRIORITIES = TOTEM_PRIORITIES
+
+local SLOT_BORDER_COLORS = {
+ [EARTH_TOTEM_SLOT] = {r = 0.23, g = 0.45, b = 0.13}, -- [2]
+ [FIRE_TOTEM_SLOT] = {r = 0.58, g = 0.23, b = 0.10}, -- [1]
+ [WATER_TOTEM_SLOT] = {r = 0.19, g = 0.48, b = 0.60}, -- [3]
+ [AIR_TOTEM_SLOT] = {r = 0.42, g = 0.18, b = 0.74} -- [4]
+}
+
+function TOTEMS:UpdateAllTotems()
+ for i = 1, MAX_TOTEMS do
+ self:UpdateTotem(nil, i)
+ end
+end
+
+function TOTEMS:UpdateTotem(event, slot)
+ local slotID = TOTEM_PRIORITIES[slot]
+ local _, _, startTime, duration, icon = GetTotemInfo(slot)
+
+ if icon ~= "" then
+ local color = SLOT_BORDER_COLORS[slot]
+ self.bar[slotID].iconTexture:SetTexture(icon)
+ self.bar[slotID]:SetBackdropBorderColor(color.r, color.g, color.b)
+
+ CooldownFrame_SetTimer(self.bar[slotID].cooldown, startTime, duration, 1)
+
+ self.bar[slotID]:Show()
+ else
+ self.bar[slotID]:Hide()
+ end
+end
+
+function TOTEMS:ToggleEnable()
+ if E.db.general.totems.enable then
+ if self.Initialized then
+ self.bar:Show()
+ self:RegisterEvent("PLAYER_TOTEM_UPDATE", "UpdateTotem")
+ self:RegisterEvent("PLAYER_ENTERING_WORLD", "UpdateAllTotems")
+ self:UpdateAllTotems()
+ E:EnableMover("TotemBarMover")
+ else
+ self:Initialize()
+ self:UpdateAllTotems()
+ end
+ elseif self.Initialized then
+ self.bar:Hide()
+ self:UnregisterEvent("PLAYER_TOTEM_UPDATE")
+ self:UnregisterEvent("PLAYER_ENTERING_WORLD")
+ E:DisableMover("TotemBarMover")
+ end
+end
+
+function TOTEMS:PositionAndSize()
+ if not self.Initialized then return end
+
+ for i = 1, MAX_TOTEMS do
+ local button = self.bar[i]
+ local prevButton = self.bar[i - 1]
+
+ button:Size(self.db.size)
+ button:ClearAllPoints()
+
+ if self.db.growthDirection == "HORIZONTAL" and self.db.sortDirection == "ASCENDING" then
+ if i == 1 then
+ button:Point("LEFT", self.bar, "LEFT", self.db.spacing, 0)
+ elseif prevButton then
+ button:Point("LEFT", prevButton, "RIGHT", self.db.spacing, 0)
+ end
+ elseif self.db.growthDirection == "VERTICAL" and self.db.sortDirection == "ASCENDING" then
+ if i == 1 then
+ button:Point("TOP", self.bar, "TOP", 0, -self.db.spacing)
+ elseif prevButton then
+ button:Point("TOP", prevButton, "BOTTOM", 0, -self.db.spacing)
+ end
+ elseif self.db.growthDirection == "HORIZONTAL" and self.db.sortDirection == "DESCENDING" then
+ if i == 1 then
+ button:Point("RIGHT", self.bar, "RIGHT", -self.db.spacing, 0)
+ elseif prevButton then
+ button:Point("RIGHT", prevButton, "LEFT", -self.db.spacing, 0)
+ end
+ else
+ if i == 1 then
+ button:Point("BOTTOM", self.bar, "BOTTOM", 0, self.db.spacing)
+ elseif prevButton then
+ button:Point("BOTTOM", prevButton, "TOP", 0, self.db.spacing)
+ end
+ end
+ end
+
+ if self.db.growthDirection == "HORIZONTAL" then
+ self.bar:Width(self.db.size*(MAX_TOTEMS) + self.db.spacing*(MAX_TOTEMS) + self.db.spacing)
+ self.bar:Height(self.db.size + self.db.spacing * 2)
+ else
+ self.bar:Height(self.db.size*(MAX_TOTEMS) + self.db.spacing*(MAX_TOTEMS) + self.db.spacing)
+ self.bar:Width(self.db.size + self.db.spacing * 2)
+ end
+end
+
+local function Button_OnClick(self)
+ DestroyTotem(self.slot)
+end
+local function Button_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT")
+ self:UpdateTooltip()
+end
+local function Button_OnLeave(self)
+ GameTooltip:Hide()
+end
+local function UpdateTooltip(self)
+ if GameTooltip:IsOwned(self) then
+ GameTooltip:SetTotem(self.slot)
+ end
+end
+
+function TOTEMS:Initialize()
+ if not E.db.general.totems.enable then return end
+
+ self.db = E.db.general.totems
+
+ local bar = CreateFrame("Frame", "ElvUI_TotemBar", E.UIParent)
+ bar:Point("TOPLEFT", LeftChatPanel, "TOPRIGHT", 14, 0)
+ self.bar = bar
+
+ for i = 1, MAX_TOTEMS do
+ local frame = CreateFrame("Button", "$parentTotem"..i, bar)
+ frame.slot = TOTEM_PRIORITIES[i]
+ frame:SetTemplate("Default")
+ frame:StyleButton()
+ frame.ignoreBorderColors = true
+ frame:Hide()
+
+ frame.UpdateTooltip = UpdateTooltip
+
+ frame:RegisterForClicks("RightButtonUp")
+ frame:SetScript("OnClick", Button_OnClick)
+ frame:SetScript("OnEnter", Button_OnEnter)
+ frame:SetScript("OnLeave", Button_OnLeave)
+
+ frame.holder = CreateFrame("Frame", nil, frame)
+ frame.holder:SetAlpha(0)
+ frame.holder:SetAllPoints()
+
+ frame.iconTexture = frame:CreateTexture(nil, "ARTWORK")
+ frame.iconTexture:SetTexCoord(unpack(E.TexCoords))
+ frame.iconTexture:SetInside()
+
+ frame.cooldown = CreateFrame("Cooldown", "$parentCooldown", frame, "CooldownFrameTemplate")
+ frame.cooldown:SetReverse(true)
+ frame.cooldown:SetInside()
+ E:RegisterCooldown(frame.cooldown)
+
+ self.bar[i] = frame
+ end
+
+ self.Initialized = true
+
+ self:PositionAndSize()
+
+ E:CreateMover(bar, "TotemBarMover", TUTORIAL_TITLE47, nil, nil, nil, nil, nil, "general,totems")
+
+ self:RegisterEvent("PLAYER_TOTEM_UPDATE", "UpdateTotem")
+ self:RegisterEvent("PLAYER_ENTERING_WORLD", "UpdateAllTotems")
+end
+
+local function InitializeCallback()
+ TOTEMS:Initialize()
+end
+
+E:RegisterModule(TOTEMS:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/Auras.lua b/ElvUI/Modules/Nameplates/Elements/Auras.lua
new file mode 100644
index 0000000..f324cc3
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/Auras.lua
@@ -0,0 +1,463 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+local LSM = E.Libs.LSM
+local LAI = E.Libs.LAI
+
+--Lua functions
+local select, unpack, pairs = select, unpack, pairs
+local band = bit.band
+local tinsert = table.insert
+local floor = math.floor
+local split = string.split
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetSpellInfo = GetSpellInfo
+local GetTime = GetTime
+
+local CREATED, VISIBLE, HIDDEN = 2, 1, 0
+
+local positionValues = {
+ BOTTOMLEFT = "TOP",
+ BOTTOMRIGHT = "TOP",
+ LEFT = "RIGHT",
+ RIGHT = "LEFT",
+ TOPLEFT = "BOTTOM",
+ TOPRIGHT = "BOTTOM"
+}
+
+local positionValues2 = {
+ BOTTOMLEFT = "BOTTOM",
+ BOTTOMRIGHT = "BOTTOM",
+ LEFT = "LEFT",
+ RIGHT = "RIGHT",
+ TOPLEFT = "TOP",
+ TOPRIGHT = "TOP"
+}
+
+
+local RaidIconBit = {
+ ["STAR"] = 0x00100000,
+ ["CIRCLE"] = 0x00200000,
+ ["DIAMOND"] = 0x00400000,
+ ["TRIANGLE"] = 0x00800000,
+ ["MOON"] = 0x01000000,
+ ["SQUARE"] = 0x02000000,
+ ["CROSS"] = 0x04000000,
+ ["SKULL"] = 0x08000000
+}
+
+local ByRaidIcon = {}
+
+function NP:LibAuraInfo_AURA_APPLIED(event, destGUID)
+ self:UpdateElement_AurasByGUID(destGUID, event)
+end
+
+function NP:LibAuraInfo_AURA_REMOVED(event, destGUID)
+ self:UpdateElement_AurasByGUID(destGUID, event)
+end
+
+function NP:LibAuraInfo_AURA_REFRESH(event, destGUID)
+ self:LibAuraInfo_AURA_APPLIED(event, destGUID)
+end
+
+function NP:LibAuraInfo_AURA_APPLIED_DOSE(event, destGUID)
+ self:LibAuraInfo_AURA_APPLIED(event, destGUID)
+end
+
+function NP:LibAuraInfo_AURA_CLEAR(event, destGUID)
+ self:UpdateElement_AurasByGUID(destGUID, event)
+end
+
+function NP:LibAuraInfo_UNIT_AURA(event, destGUID)
+ self:UpdateElement_AurasByGUID(destGUID, event)
+end
+
+function NP:UpdateTime(elapsed)
+ self.timeLeft = self.timeLeft - elapsed
+ self:SetValue(self.timeLeft)
+
+ if self.nextUpdate > 0 then
+ self.nextUpdate = self.nextUpdate - elapsed
+ return
+ end
+
+ if self.timeLeft < 0 then
+ self:SetScript("OnUpdate", nil)
+ self:Hide()
+ return
+ end
+
+ local value, id, nextUpdate, remainder = E:GetTimeInfo(self.timeLeft, self.threshold, self.hhmmThreshold, self.mmssThreshold)
+ self.nextUpdate = nextUpdate
+
+ local style = E.TimeFormats[id]
+ if style then
+ local which = (self.textColors and 2 or 1) + (self.showSeconds and 0 or 2)
+ if self.textColors then
+ self.text:SetFormattedText(style[which], value, self.textColors[id], remainder)
+ else
+ self.text:SetFormattedText(style[which], value, remainder)
+ end
+ end
+
+ local color = self.timeColors[id]
+ if color then
+ self.text:SetTextColor(color.r, color.g, color.b)
+ end
+end
+
+local unstableAffliction = GetSpellInfo(30108)
+local vampiricTouch = GetSpellInfo(34914)
+function NP:SetAura(frame, guid, index, filter, isDebuff, visible)
+ local isAura, name, texture, count, debuffType, duration, expiration, caster, spellID, _ = LAI:GUIDAura(guid, index, filter)
+
+ if frame.forceShow or frame.forceCreate then
+ spellID = 47540
+ name, _, texture = GetSpellInfo(spellID)
+ if frame.forceShow then
+ isAura, count, debuffType, duration, expiration = true, 5, "Magic", 0, 0
+ end
+ end
+
+ if isAura then
+ local position = visible + 1
+ local button = frame[position] or NP:Construct_AuraIcon(frame, position)
+
+ button.caster = caster
+ button.filter = filter
+ button.isDebuff = isDebuff
+
+ local filterCheck = not frame.forceCreate
+ if not (frame.forceShow or frame.forceCreate) then
+ filterCheck = NP:AuraFilter(guid, button, name, texture, count, debuffType, duration, expiration, caster, spellID)
+ end
+
+ if filterCheck then
+ if button.icon then button.icon:SetTexture(texture) end
+ if button.count then button.count:SetText(count > 1 and count) end
+
+ if duration > 0 and expiration ~= 0 then
+ local timeLeft = expiration - GetTime()
+ if timeLeft > 0 then
+ button.timeLeft = timeLeft
+ button.nextUpdate = 0
+
+ button:SetMinMaxValues(0, duration)
+ button:SetValue(timeLeft)
+
+ button:SetScript("OnUpdate", NP.UpdateTime)
+-- else
+-- return HIDDEN
+ end
+ else
+ button.timeLeft = nil
+ button.text:SetText("")
+ button:SetScript("OnUpdate", nil)
+ button:SetMinMaxValues(0, 1)
+ button:SetValue(0)
+ end
+
+ button:SetID(index)
+ button:Show()
+
+ if isDebuff then
+ local color = (debuffType and DebuffTypeColor[debuffType]) or DebuffTypeColor.none
+ if button.name and (button.name == unstableAffliction or button.name == vampiricTouch) then
+ self:StyleFrameColor(button, 0.05, 0.85, 0.94)
+ else
+ self:StyleFrameColor(button, color.r * 0.6, color.g * 0.6, color.b * 0.6)
+ end
+ end
+
+ return VISIBLE
+ elseif frame.forceCreate then
+ button:Hide()
+
+ return CREATED
+ else
+ return HIDDEN
+ end
+ end
+end
+
+function NP:Update_AurasPosition(frame, db)
+ local size = db.size + db.spacing
+ local anchor = E.InversePoints[db.anchorPoint]
+ local growthx = (db.growthX == "LEFT" and -1) or 1
+ local growthy = (db.growthY == "DOWN" and -1) or 1
+ local cols = db.perrow
+
+ for i = frame.anchoredIcons + 1, #frame do
+ local button = frame[i]
+ if not button then break end
+
+ local col = (i - 1) % cols
+ local row = floor((i - 1) / cols)
+
+ button:SetSize(db.size, db.size)
+ button:ClearAllPoints()
+ button:SetPoint(anchor, frame, anchor, col * size * growthx, row * size * growthy)
+
+ button.count:FontTemplate(LSM:Fetch("font", db.countFont), db.countFontSize, db.countFontOutline)
+ button.count:ClearAllPoints()
+ button.count:SetPoint(db.countPosition, db.countXOffset, db.countYOffset)
+
+ button.text:FontTemplate(LSM:Fetch("font", db.durationFont), db.durationFontSize, db.durationFontOutline)
+ button.text:ClearAllPoints()
+ button.text:SetPoint(db.durationPosition, db.durationXOffset, db.durationYOffset)
+
+ button:SetOrientation(db.cooldownOrientation)
+
+ button.bg:ClearAllPoints()
+ if db.cooldownOrientation == "VERTICAL" then
+ button.bg:SetPoint("TOPLEFT", button)
+ button.bg:SetPoint("BOTTOMRIGHT", button:GetStatusBarTexture(), "TOPRIGHT")
+ else
+ button.bg:SetPoint("TOPRIGHT", button)
+ button.bg:SetPoint("BOTTOMLEFT", button:GetStatusBarTexture(), "BOTTOMRIGHT")
+ end
+
+ if db.reverseCooldown then
+ button:SetStatusBarColor(0, 0, 0, 0.5)
+ button.bg:SetTexture(0, 0, 0, 0)
+ else
+ button:SetStatusBarColor(0, 0, 0, 0)
+ button.bg:SetTexture(0, 0, 0, 0.5)
+ end
+ end
+end
+
+function NP:UpdateElement_AuraIcons(frame, guid, filter, limit, isDebuff)
+ local index, visible, hidden, created = 1, 0, 0, 0
+
+ while visible < limit do
+ local result = NP:SetAura(frame, guid, index, filter, isDebuff, visible)
+ if not result then
+ break
+ elseif result == HIDDEN then
+ hidden = hidden + 1
+ elseif result == VISIBLE then
+ visible = visible + 1
+ elseif result == CREATED then
+ visible = visible + 1
+ created = created + 1
+ end
+ index = index + 1
+ end
+
+ visible = visible - created
+
+ for i = visible + 1, #frame do
+ frame[i].timeLeft = nil
+ frame[i]:SetScript("OnUpdate", nil)
+ frame[i]:Hide()
+ end
+ return visible
+end
+
+function NP:UpdateElement_Auras(frame)
+ if not frame.Health:IsShown() then return end
+
+ local guid = frame.guid
+
+ if not guid then
+ if frame.UnitClass == "HERO" then
+ local name = frame.UnitName
+ guid = self.GUIDByName[name]
+ elseif frame.RaidIcon:IsShown() then
+ guid = ByRaidIcon[frame.RaidIconType]
+ end
+
+ if guid then
+ frame.guid = guid
+ elseif not frame.Buffs.forceShow and not frame.Debuffs.forceShow then
+ return
+ end
+ end
+
+ local db = NP.db.units[frame.UnitType].buffs
+ if db.enable then
+ local buffs = frame.Buffs
+ buffs.visibleBuffs = NP:UpdateElement_AuraIcons(buffs, guid, buffs.filter or "HELPFUL", db.perrow * db.numrows)
+
+ if #buffs > buffs.anchoredIcons then
+ self:Update_AurasPosition(buffs, db)
+
+ buffs.anchoredIcons = #buffs
+ end
+ end
+
+ db = NP.db.units[frame.UnitType].debuffs
+ if db.enable then
+ local debuffs = frame.Debuffs
+ debuffs.visibleDebuffs = NP:UpdateElement_AuraIcons(debuffs, guid, debuffs.filter or "HARMFUL", db.perrow * db.numrows, true)
+
+ if #debuffs > debuffs.anchoredIcons then
+ self:Update_AurasPosition(debuffs, db)
+
+ debuffs.anchoredIcons = #debuffs
+ end
+ end
+
+ self:StyleFilterUpdate(frame, "UNIT_AURA")
+end
+
+function NP:UpdateElement_AurasByGUID(guid, event)
+ local destName, destFlags = LAI:GetGUIDInfo(guid)
+
+ if destName then
+ destName = split("-", destName)
+ end
+
+ local raidIcon
+ if destFlags then
+ for iconName, bitmask in pairs(RaidIconBit) do
+ if band(destFlags, bitmask) > 0 then
+ ByRaidIcon[iconName] = guid
+ raidIcon = iconName
+ break
+ end
+ end
+ end
+
+ local frame = self:SearchForFrame(guid, raidIcon, destName)
+ if frame then
+ frame.guid = guid
+ self.GUIDByName[destName] = guid
+ self:UpdateElement_Auras(frame)
+ end
+end
+
+function NP:Construct_AuraIcon(parent, index)
+ local db = NP.db.units[parent:GetParent().UnitType][parent.type]
+
+ local button = CreateFrame("StatusBar", "$parentButton"..index, parent)
+ NP:StyleFrame(button, true)
+
+ button:SetStatusBarTexture(E.media.blankTex)
+ button:SetStatusBarColor(0, 0, 0, 0)
+ button:SetOrientation("VERTICAL")
+
+ button.bg = button:CreateTexture()
+ button.bg:SetTexture(0, 0, 0, 0.5)
+
+ button.bg:SetPoint("TOPLEFT", button)
+ button.bg:SetPoint("BOTTOMRIGHT", button:GetStatusBarTexture(), "TOPRIGHT")
+
+ button.icon = button:CreateTexture(nil, "BORDER")
+ button.icon:SetTexCoord(unpack(E.TexCoords))
+ button.icon:SetAllPoints()
+
+ button.count = button:CreateFontString(nil, "OVERLAY")
+ button.count:SetJustifyH("RIGHT")
+ button.count:FontTemplate(LSM:Fetch("font", db.countFont), db.countFontSize, db.countFontOutline)
+
+ button.text = button:CreateFontString(nil, "OVERLAY")
+
+ -- support cooldown override
+ if not button.isRegisteredCooldown then
+ button.CooldownOverride = "nameplates"
+ button.isRegisteredCooldown = true
+ button.forceEnabled = true
+
+ if not E.RegisteredCooldowns.nameplates then E.RegisteredCooldowns.nameplates = {} end
+ tinsert(E.RegisteredCooldowns.nameplates, button)
+ end
+
+ button.text:FontTemplate(LSM:Fetch("font", db.durationFont), db.durationFontSize, db.durationFontOutline)
+
+ NP:Update_CooldownOptions(button)
+
+ tinsert(parent, button)
+
+ return button
+end
+
+function NP:Update_CooldownOptions(button)
+ E:Cooldown_Options(button, self.db.cooldown, button)
+end
+
+function NP:Configure_Auras(frame, auraType)
+ local auras = frame[auraType]
+ local db = self.db.units[frame.UnitType][auras.type]
+
+ auras:SetWidth(db.perrow * db.size + ((db.perrow - 1) * db.spacing))
+ auras:SetHeight(db.numrows * db.size + ((db.numrows - 1) * db.spacing))
+ auras:ClearAllPoints()
+ auras:SetPoint(positionValues[db.anchorPoint], db.attachTo == "BUFFS" and frame.Buffs or frame.Health, positionValues2[db.anchorPoint], db.xOffset, db.yOffset)
+end
+
+function NP:ConstructElement_Auras(frame, auraType)
+ local auras = CreateFrame("Frame", "$parent"..auraType, frame)
+ auras:Show()
+ auras:SetSize(150, 27)
+ auras:SetPoint("TOP", 0, 22)
+ auras.anchoredIcons = 0
+ auras.type = string.lower(auraType)
+
+ return auras
+end
+
+function NP:CheckFilter(name, spellID, isPlayer, allowDuration, noDuration, ...)
+ for i = 1, select("#", ...) do
+ local filterName = select(i, ...)
+ if not filterName then return true end
+ if G.nameplates.specialFilters[filterName] or E.global.unitframe.aurafilters[filterName] then
+ local filter = E.global.unitframe.aurafilters[filterName]
+ if filter then
+ local filterType = filter.type
+ local spellList = filter.spells
+ local spell = spellList and (spellList[spellID] or spellList[name])
+
+ if filterType and (filterType == "Whitelist") and (spell and spell.enable) and allowDuration then
+ return true
+ elseif filterType and (filterType == "Blacklist") and (spell and spell.enable) then
+ return false
+ end
+ elseif filterName == "Personal" and isPlayer and allowDuration then
+ return true
+ elseif filterName == "nonPersonal" and (not isPlayer) and allowDuration then
+ return true
+ elseif filterName == "blockNoDuration" and noDuration then
+ return false
+ elseif filterName == "blockNonPersonal" and (not isPlayer) then
+ return false
+ end
+ end
+ end
+end
+
+function NP:AuraFilter(guid, button, name, texture, count, debuffType, duration, expiration, caster, spellID)
+ local parent = button:GetParent()
+ local parentType = parent.type
+ local db = NP.db.units[parent:GetParent().UnitType][parentType]
+ if not db then return true end
+
+ local isPlayer = caster == E.myguid
+
+ -- keep these same as in `UF:AuraFilter`
+ button.isPlayer = isPlayer
+ button.dtype = debuffType
+ button.duration = duration
+ button.expiration = expiration
+ button.stackCount = count
+ button.name = name
+ button.spellID = spellID
+ button.spell = name
+ button.priority = 0
+
+ if not db.filters then return true end
+
+ local priority = db.filters.priority
+ local noDuration = (not duration or duration == 0)
+ local allowDuration = noDuration or (duration and (duration > 0) and db.filters.maxDuration == 0 or duration <= db.filters.maxDuration) and (db.filters.minDuration == 0 or duration >= db.filters.minDuration)
+ local filterCheck
+
+ if priority ~= "" then
+ filterCheck = NP:CheckFilter(name, spellID, isPlayer, allowDuration, noDuration, split(",", priority))
+ else
+ filterCheck = allowDuration and true -- Allow all auras to be shown when the filter list is empty, while obeying duration sliders
+ end
+
+ return filterCheck
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/CastBar.lua b/ElvUI/Modules/Nameplates/Elements/CastBar.lua
new file mode 100644
index 0000000..85a14a0
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/CastBar.lua
@@ -0,0 +1,358 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+local LSM = E.Libs.LSM
+
+--Lua functions
+local unpack = unpack
+local abs = math.abs
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetTime = GetTime
+local UnitCastingInfo = UnitCastingInfo
+local UnitChannelInfo = UnitChannelInfo
+local FAILED = FAILED
+local INTERRUPTED = INTERRUPTED
+
+local function resetAttributes(self)
+ self.casting = nil
+ self.channeling = nil
+ self.notInterruptible = nil
+ self.spellName = nil
+end
+
+function NP:Update_CastBarOnUpdate(elapsed)
+ if self.casting or self.channeling then
+ local isCasting = self.casting
+ if isCasting then
+ self.value = self.value + elapsed
+ if self.value >= self.max then
+ resetAttributes(self)
+ self:Hide()
+ NP:StyleFilterUpdate(self:GetParent(), "FAKE_Casting")
+ return
+ end
+ else
+ self.value = self.value - elapsed
+ if self.value <= 0 then
+ resetAttributes(self)
+ self:Hide()
+ NP:StyleFilterUpdate(self:GetParent(), "FAKE_Casting")
+ return
+ end
+ end
+
+ if self.delay ~= 0 then
+ if self.channeling then
+ if self.channelTimeFormat == "CURRENT" then
+ self.Time:SetFormattedText("%.1f |cffaf5050%.2f|r", abs(self.value - self.max), self.delay)
+ elseif self.channelTimeFormat == "CURRENTMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%.2f|r", abs(self.value - self.max), self.max, self.delay)
+ elseif self.channelTimeFormat == "REMAINING" then
+ self.Time:SetFormattedText("%.1f |cffaf5050%.2f|r", self.value, self.delay)
+ elseif self.channelTimeFormat == "REMAININGMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%.2f|r", self.value, self.max, self.max, self.delay)
+ end
+ else
+ if self.castTimeFormat == "CURRENT" then
+ self.Time:SetFormattedText("%.1f |cffaf5050%s %.2f|r", self.value, "+", self.delay)
+ elseif self.castTimeFormat == "CURRENTMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%s %.2f|r", self.value, self.max, "+", self.delay)
+ elseif self.castTimeFormat == "REMAINING" then
+ self.Time:SetFormattedText("%.1f |cffaf5050%s %.2f|r", abs(self.value - self.max), "+", self.delay)
+ elseif self.castTimeFormat == "REMAININGMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%s %.2f|r", abs(self.value - self.max), self.max, "+", self.delay)
+ end
+ end
+ else
+ if self.channeling then
+ if self.channelTimeFormat == "CURRENT" then
+ self.Time:SetFormattedText("%.1f", abs(self.value - self.max))
+ elseif self.channelTimeFormat == "CURRENTMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f", abs(self.value - self.max), self.max)
+ elseif self.channelTimeFormat == "REMAINING" then
+ self.Time:SetFormattedText("%.1f", self.value)
+ elseif self.channelTimeFormat == "REMAININGMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f", self.value, self.max)
+ end
+ else
+ if self.castTimeFormat == "CURRENT" then
+ self.Time:SetFormattedText("%.1f", self.value)
+ elseif self.castTimeFormat == "CURRENTMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f", self.value, self.max)
+ elseif self.castTimeFormat == "REMAINING" then
+ self.Time:SetFormattedText("%.1f", abs(self.value - self.max))
+ elseif self.castTimeFormat == "REMAININGMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f", abs(self.value - self.max), self.max)
+ end
+ end
+ end
+
+ self:SetValue(self.value)
+ elseif self.holdTime > 0 then
+ self.holdTime = self.holdTime - elapsed
+ else
+ resetAttributes(self)
+ self:Hide()
+ NP:StyleFilterUpdate(self:GetParent(), "FAKE_Casting")
+ end
+end
+
+function NP:Update_CastBar(frame, event, unit)
+ local castBar = frame.CastBar
+ if unit then
+ if not event then
+ if UnitChannelInfo(unit) then
+ event = "UNIT_SPELLCAST_CHANNEL_START"
+ elseif UnitCastingInfo(unit) then
+ event = "UNIT_SPELLCAST_START"
+ end
+ end
+ elseif castBar:IsShown() then
+ resetAttributes(castBar)
+ castBar:Hide()
+ end
+
+ if self.db.units[frame.UnitType].castbar.enable ~= true then return end
+ if self.db.units[frame.UnitType].health.enable ~= true and not (frame.isTarget and self.db.alwaysShowTargetHealth) then return end --Bug
+
+ if event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_CHANNEL_START" then
+ local name, _, _, texture, startTime, endTime, _, _, notInterruptible = UnitCastingInfo(unit)
+ event = "UNIT_SPELLCAST_START"
+ if not name then
+ name, _, _, texture, startTime, endTime, _, notInterruptible = UnitChannelInfo(unit)
+ event = "UNIT_SPELLCAST_CHANNEL_START"
+ end
+
+ if not name then
+ resetAttributes(castBar)
+ castBar:Hide()
+ return
+ end
+
+ endTime = endTime / 1000
+ startTime = startTime / 1000
+
+ castBar.max = endTime - startTime
+ castBar.startTime = startTime
+ castBar.delay = 0
+ castBar.casting = event == "UNIT_SPELLCAST_START"
+ castBar.channeling = event == "UNIT_SPELLCAST_CHANNEL_START"
+ castBar.notInterruptible = notInterruptible
+ castBar.holdTime = 0
+ castBar.interrupted = nil
+ castBar.spellName = name
+
+ if castBar.casting then
+ castBar.value = GetTime() - startTime
+ else
+ castBar.value = endTime - GetTime()
+ end
+
+ castBar:SetMinMaxValues(0, castBar.max)
+ castBar:SetValue(castBar.value)
+
+ castBar.Icon.texture:SetTexture(texture)
+ castBar.Spark:Show()
+ castBar.Name:SetText(name)
+ castBar.Time:SetText()
+
+ castBar:Show()
+ elseif event == "UNIT_SPELLCAST_STOP" or event == "UNIT_SPELLCAST_CHANNEL_STOP" then
+ if castBar:IsShown() then
+ resetAttributes(castBar)
+ end
+ elseif event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED" then
+ if castBar:IsShown() then
+ castBar.Spark:Hide()
+ castBar.Name:SetText(event == "UNIT_SPELLCAST_FAILED" and FAILED or INTERRUPTED)
+
+ castBar.holdTime = self.db.units[frame.UnitType].castbar.timeToHold --How long the castbar should stay visible after being interrupted, in seconds
+ castBar.interrupted = true
+
+ resetAttributes(castBar)
+ castBar:SetValue(castBar.max)
+ end
+ elseif event == "UNIT_SPELLCAST_DELAYED" or event == "UNIT_SPELLCAST_CHANNEL_UPDATE" then
+ if frame:IsShown() then
+ local name, startTime, endTime, _
+ if event == "UNIT_SPELLCAST_DELAYED" then
+ name, _, _, _, startTime, endTime = UnitCastingInfo(unit)
+ else
+ name, _, _, _, startTime, endTime = UnitChannelInfo(unit)
+ end
+
+ if not name then
+ resetAttributes(castBar)
+ castBar:Hide()
+ return
+ end
+
+ endTime = endTime / 1000
+ startTime = startTime / 1000
+
+ local delta
+ if castBar.casting then
+ delta = startTime - castBar.startTime
+ castBar.value = GetTime() - startTime
+ else
+ delta = castBar.startTime - startTime
+ castBar.value = endTime - GetTime()
+ end
+
+ if delta < 0 then
+ delta = 0
+ end
+
+ castBar.Name:SetText(name)
+ castBar.max = endTime - startTime
+ castBar.startTime = startTime
+ castBar.delay = castBar.delay + delta
+ castBar:SetMinMaxValues(0, castBar.max)
+ castBar:SetValue(castBar.value)
+ end
+ elseif event == "UNIT_SPELLCAST_INTERRUPTIBLE" or event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE" then
+ castBar.notInterruptible = event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE"
+ end
+
+ if not castBar.notInterruptible then
+ if castBar.interrupted then
+ castBar:SetStatusBarColor(self.db.colors.castInterruptedColor.r, self.db.colors.castInterruptedColor.g, self.db.colors.castInterruptedColor.b)
+ else
+ castBar:SetStatusBarColor(self.db.colors.castColor.r, self.db.colors.castColor.g, self.db.colors.castColor.b)
+ end
+ castBar.Icon.texture:SetDesaturated(false)
+ else
+ castBar:SetStatusBarColor(self.db.colors.castNoInterruptColor.r, self.db.colors.castNoInterruptColor.g, self.db.colors.castNoInterruptColor.b)
+
+ if self.db.colors.castbarDesaturate then
+ castBar.Icon.texture:SetDesaturated(true)
+ end
+ end
+
+ self:StyleFilterUpdate(frame, "FAKE_Casting")
+end
+
+function NP:Configure_CastBarScale(frame, scale, noPlayAnimation)
+ if frame.currentScale == scale then return end
+ local db = self.db.units[frame.UnitType].castbar
+ if not db.enable then return end
+
+ local castBar = frame.CastBar
+
+ if noPlayAnimation then
+ castBar:SetSize(db.width * scale, db.height * scale)
+ castBar.Icon:SetSize(db.iconSize * scale, db.iconSize * scale)
+ else
+ if castBar.scale:IsPlaying() or castBar.Icon.scale:IsPlaying() then
+ castBar.scale:Stop()
+ castBar.Icon.scale:Stop()
+ end
+
+ castBar.scale.width:SetChange(db.width * scale)
+ castBar.scale.height:SetChange(db.height * scale)
+ castBar.scale:Play()
+
+ castBar.Icon.scale.width:SetChange(db.iconSize * scale)
+ castBar.Icon.scale.height:SetChange(db.iconSize * scale)
+ castBar.Icon.scale:Play()
+ end
+end
+
+function NP:Configure_CastBar(frame, configuring)
+ local db = self.db.units[frame.UnitType].castbar
+ local castBar = frame.CastBar
+
+ castBar:SetPoint("TOP", frame.Health, "BOTTOM", db.xOffset, db.yOffset)
+
+ if db.showIcon then
+ castBar.Icon:ClearAllPoints()
+ castBar.Icon:SetPoint(db.iconPosition == "RIGHT" and "BOTTOMLEFT" or "BOTTOMRIGHT", castBar, db.iconPosition == "RIGHT" and "BOTTOMRIGHT" or "BOTTOMLEFT", db.iconOffsetX, db.iconOffsetY)
+ castBar.Icon:Show()
+ else
+ castBar.Icon:Hide()
+ end
+
+ castBar.Time:ClearAllPoints()
+ castBar.Name:ClearAllPoints()
+
+ castBar.Spark:SetPoint("CENTER", castBar:GetStatusBarTexture(), "RIGHT", 0, 0)
+ castBar.Spark:SetHeight(db.height * 2)
+
+ if db.textPosition == "BELOW" then
+ castBar.Time:SetPoint("TOPRIGHT", castBar, "BOTTOMRIGHT")
+ castBar.Name:SetPoint("TOPLEFT", castBar, "BOTTOMLEFT")
+ elseif db.textPosition == "ABOVE" then
+ castBar.Time:SetPoint("BOTTOMRIGHT", castBar, "TOPRIGHT")
+ castBar.Name:SetPoint("BOTTOMLEFT", castBar, "TOPLEFT")
+ else
+ castBar.Time:SetPoint("RIGHT", castBar, "RIGHT", -4, 0)
+ castBar.Name:SetPoint("LEFT", castBar, "LEFT", 4, 0)
+ end
+
+ if configuring then
+ self:Configure_CastBarScale(frame, frame.currentScale or 1, configuring)
+ end
+
+ castBar.Name:FontTemplate(LSM:Fetch("font", db.font), db.fontSize, db.fontOutline)
+ castBar.Time:FontTemplate(LSM:Fetch("font", db.font), db.fontSize, db.fontOutline)
+
+ if db.hideSpellName then
+ castBar.Name:Hide()
+ else
+ castBar.Name:Show()
+ end
+ if db.hideTime then
+ castBar.Time:Hide()
+ else
+ castBar.Time:Show()
+ end
+
+ castBar:SetStatusBarTexture(LSM:Fetch("statusbar", self.db.statusbar))
+
+ castBar.castTimeFormat = db.castTimeFormat
+ castBar.channelTimeFormat = db.channelTimeFormat
+end
+
+function NP:Construct_CastBar(parent)
+ local frame = CreateFrame("StatusBar", "$parentCastBar", parent)
+ NP:StyleFrame(frame)
+ frame:SetScript("OnUpdate", NP.Update_CastBarOnUpdate)
+
+ frame.Icon = CreateFrame("Frame", nil, frame)
+ frame.Icon.texture = frame.Icon:CreateTexture(nil, "BORDER")
+ frame.Icon.texture:SetAllPoints()
+ frame.Icon.texture:SetTexCoord(unpack(E.TexCoords))
+ NP:StyleFrame(frame.Icon)
+
+ frame.Time = frame:CreateFontString(nil, "OVERLAY")
+ frame.Time:SetJustifyH("RIGHT")
+ frame.Time:SetWordWrap(false)
+
+ frame.Name = frame:CreateFontString(nil, "OVERLAY")
+ frame.Name:SetJustifyH("LEFT")
+ frame.Name:SetWordWrap(false)
+
+ frame.Spark = frame:CreateTexture(nil, "OVERLAY")
+ frame.Spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
+ frame.Spark:SetBlendMode("ADD")
+ frame.Spark:SetSize(15, 15)
+
+ frame.holdTime = 0
+ frame.interrupted = nil
+
+ frame.scale = CreateAnimationGroup(frame)
+ frame.scale.width = frame.scale:CreateAnimation("Width")
+ frame.scale.width:SetDuration(0.2)
+ frame.scale.height = frame.scale:CreateAnimation("Height")
+ frame.scale.height:SetDuration(0.2)
+
+ frame.Icon.scale = CreateAnimationGroup(frame.Icon)
+ frame.Icon.scale.width = frame.Icon.scale:CreateAnimation("Width")
+ frame.Icon.scale.width:SetDuration(0.2)
+ frame.Icon.scale.height = frame.Icon.scale:CreateAnimation("Height")
+ frame.Icon.scale.height:SetDuration(0.2)
+
+ frame:Hide()
+
+ return frame
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/ComboPoints.lua b/ElvUI/Modules/Nameplates/Elements/ComboPoints.lua
new file mode 100644
index 0000000..048d009
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/ComboPoints.lua
@@ -0,0 +1,119 @@
+local E, L, V, P, G = unpack(select(2, ...))
+local NP = E:GetModule("NamePlates")
+local LSM = E.Libs.LSM
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetComboPoints = GetComboPoints
+local MAX_COMBO_POINTS = MAX_COMBO_POINTS
+
+function NP:Update_CPoints(frame)
+ if frame.UnitType == "FRIENDLY_PLAYER" or frame.UnitType == "FRIENDLY_NPC" then return end
+ if not self.db.units.TARGET.comboPoints.enable then return end
+
+ local numPoints
+ if frame.isTarget then
+ numPoints = GetComboPoints("player", "target")
+ end
+
+ if numPoints and numPoints > 0 then
+ frame.CPoints:Show()
+
+ for i = 1, MAX_COMBO_POINTS do
+ if i <= numPoints then
+ frame.CPoints[i]:Show()
+ else
+ frame.CPoints[i]:Hide()
+ end
+ end
+ else
+ frame.CPoints:Hide()
+ end
+end
+
+function NP:Configure_CPointsScale(frame, scale, noPlayAnimation)
+ if frame.UnitType == "FRIENDLY_PLAYER" or frame.UnitType == "FRIENDLY_NPC" then return end
+ local db = self.db.units.TARGET.comboPoints
+ if not db.enable then return end
+
+ if noPlayAnimation then
+ frame.CPoints:SetWidth(((db.width * 5) + (db.spacing * 4)) * scale)
+ frame.CPoints:SetHeight(db.height * scale)
+ else
+ if frame.CPoints.scale:IsPlaying() then
+ frame.CPoints.scale:Stop()
+ end
+
+ frame.CPoints.scale.width:SetChange(((db.width * 5) + (db.spacing * 4)) * scale)
+ frame.CPoints.scale.height:SetChange(db.height * scale)
+ frame.CPoints.scale:Play()
+ end
+end
+
+function NP:Configure_CPoints(frame, configuring)
+ if frame.UnitType == "FRIENDLY_PLAYER" or frame.UnitType == "FRIENDLY_NPC" then return end
+ local db = self.db.units.TARGET.comboPoints
+ if not db.enable then return end
+
+ local comboBar = frame.CPoints
+ local healthShown = self.db.units[frame.UnitType].health.enable or (frame.isTarget and self.db.alwaysShowTargetHealth)
+
+ comboBar:ClearAllPoints()
+ if healthShown then
+ comboBar:Point("CENTER", frame.Health, "BOTTOM", db.xOffset, db.yOffset)
+ else
+ comboBar:Point("CENTER", frame, "TOP", db.xOffset, db.yOffset)
+ end
+
+ for i = 1, MAX_COMBO_POINTS do
+ local comboPoint = comboBar[i]
+ comboPoint.backdrop:SetTexture(LSM:Fetch("statusbar", self.db.statusbar))
+ local color = self.db.colors.comboPoints[i]
+ comboPoint.backdrop:SetVertexColor(color.r, color.g, color.b)
+
+ comboPoint:SetWidth(db.width)
+
+ comboPoint:ClearAllPoints()
+ if i == 1 then
+ comboPoint:SetPoint("TOPLEFT")
+ comboPoint:SetPoint("BOTTOMLEFT")
+ else
+ comboPoint:SetPoint("TOPLEFT", comboBar[i - 1], "TOPRIGHT", db.spacing, 0)
+ comboPoint:SetPoint("BOTTOMLEFT", comboBar[i - 1], "BOTTOMRIGHT")
+ end
+ end
+
+ comboBar.spacing = db.spacing * (MAX_COMBO_POINTS - 1)
+
+ if configuring then
+ self:Configure_CPointsScale(frame, frame.currentScale or 1, configuring)
+ end
+end
+
+local function CPoints_OnSizeChanged(self, width)
+ width = width - self.spacing
+ for i = 1, MAX_COMBO_POINTS do
+ self[i]:SetWidth(width * 0.2)
+ end
+end
+
+function NP:Construct_CPoints(parent)
+ local comboBar = CreateFrame("Frame", "$parentComboPoints", parent)
+ comboBar:Hide()
+
+ comboBar.scale = CreateAnimationGroup(comboBar)
+ comboBar.scale.width = comboBar.scale:CreateAnimation("Width")
+ comboBar.scale.width:SetDuration(0.2)
+ comboBar.scale.height = comboBar.scale:CreateAnimation("Height")
+ comboBar.scale.height:SetDuration(0.2)
+
+ comboBar:SetScript("OnSizeChanged", CPoints_OnSizeChanged)
+
+ for i = 1, MAX_COMBO_POINTS do
+ comboBar[i] = CreateFrame("Frame", "$parentComboPoint"..i, comboBar)
+ self:StyleFrame(comboBar[i])
+ end
+
+ return comboBar
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/CutawayHealth.lua b/ElvUI/Modules/Nameplates/Elements/CutawayHealth.lua
new file mode 100644
index 0000000..b517899
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/CutawayHealth.lua
@@ -0,0 +1,61 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+
+--Lua functions
+--WoW API / Variables
+
+function NP:UpdateElement_CutawayHealthFadeOut(frame)
+ local cutawayHealth = frame.CutawayHealth
+ cutawayHealth.fading = true
+ E:UIFrameFadeOut(cutawayHealth, self.db.cutawayHealthFadeOutTime, cutawayHealth:GetAlpha(), 0)
+ cutawayHealth.isPlaying = nil
+end
+
+local function CutawayHealthClosure(frame)
+ NP:UpdateElement_CutawayHealthFadeOut(frame)
+end
+
+function NP:CutawayHealthValueChangeCallback(frame, health, maxHealth)
+ if self.db.cutawayHealth then
+ frame.CutawayHealth:SetMinMaxValues(0, maxHealth)
+ local oldValue = frame.Health:GetValue()
+ local change = oldValue - health
+ if change > 0 and not frame.CutawayHealth.isPlaying then
+ local cutawayHealth = frame.CutawayHealth
+ if cutawayHealth.fading then
+ E:UIFrameFadeRemoveFrame(cutawayHealth)
+ end
+ cutawayHealth.fading = false
+ cutawayHealth:SetValue(oldValue)
+ cutawayHealth:SetAlpha(1)
+
+ E:Delay(self.db.cutawayHealthLength, CutawayHealthClosure, frame)
+
+ cutawayHealth.isPlaying = true
+ cutawayHealth:Show()
+ end
+ else
+ if frame.CutawayHealth.isPlaying then
+ frame.CutawayHealth.isPlaying = nil
+ frame.CutawayHealth:SetScript("OnUpdate", nil)
+ end
+ frame.CutawayHealth:Hide()
+ end
+end
+
+function NP:CutawayHealthColorChangeCallback(frame, r, g, b)
+ frame.CutawayHealth:SetStatusBarColor(r * 1.5, g * 1.5, b * 1.5, 1)
+end
+
+function NP:ConstructElement_CutawayHealth(parent)
+ local healthBar = parent.Health
+
+ local cutawayHealth = CreateFrame("StatusBar", "$parentCutawayHealth", healthBar)
+ cutawayHealth:SetAllPoints()
+ cutawayHealth:SetStatusBarTexture(E.media.blankTex)
+ cutawayHealth:SetFrameLevel(healthBar:GetFrameLevel() - 1)
+
+ NP:RegisterHealthBarCallbacks(parent, NP.CutawayHealthValueChangeCallback, NP.CutawayHealthColorChangeCallback)
+
+ return cutawayHealth
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/Elite.lua b/ElvUI/Modules/Nameplates/Elements/Elite.lua
new file mode 100644
index 0000000..414dd24
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/Elite.lua
@@ -0,0 +1,53 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+
+--Lua functions
+--WoW API / Variables
+
+function NP:Update_Elite(frame)
+ local db = self.db.units[frame.UnitType].eliteIcon
+ if not db then return end
+
+ local icon = frame.Elite
+ if db.enable then
+ local elite, boss = frame.EliteIcon:IsShown(), frame.BossIcon:IsShown()
+
+ if boss then
+ icon:SetTexCoord(0, 0.15, 0.62, 0.94)
+ icon:Show()
+ elseif elite then
+ icon:SetTexCoord(0, 0.15, 0.35, 0.63)
+ icon:Show()
+ else
+ icon:Hide()
+ end
+ else
+ icon:Hide()
+ end
+end
+
+function NP:Configure_Elite(frame)
+ local db = self.db.units[frame.UnitType].eliteIcon
+ if not db then return end
+
+ local icon = frame.Elite
+
+ icon:Size(db.size)
+ icon:ClearAllPoints()
+
+ if frame.Health:IsShown() then
+ icon:SetParent(frame.Health)
+ icon:Point(db.position, frame.Health, db.position, db.xOffset, db.yOffset)
+ else
+ icon:SetParent(frame)
+ icon:Point(db.position, frame, db.position, db.xOffset, db.yOffset)
+ end
+end
+
+function NP:Construct_Elite(frame)
+ local icon = frame.Health:CreateTexture(nil, "OVERLAY")
+ icon:SetTexture(E.Media.Textures.Nameplates)
+ icon:Hide()
+
+ return icon
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/Glow.lua b/ElvUI/Modules/Nameplates/Elements/Glow.lua
new file mode 100644
index 0000000..c8d8a10
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/Glow.lua
@@ -0,0 +1,193 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+local LSM = E.Libs.LSM
+
+--Lua functions
+local ipairs = ipairs
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+--[[
+Target Glow Style Option Variables
+ style1 - Border
+ style2 - Background
+ style3 - Top Arrow Only
+ style4 - Side Arrows Only
+ style5 - Border + Top Arrow
+ style6 - Background + Top Arrow
+ style7 - Border + Side Arrows
+ style8 - Background + Side Arrows
+]]
+
+function NP:Update_Glow(frame)
+ local showIndicator
+
+ if frame.isTarget then
+ showIndicator = 1
+ elseif self.db.lowHealthThreshold > 0 then
+ local health = frame.oldHealthBar:GetValue()
+ local _, maxHealth = frame.oldHealthBar:GetMinMaxValues()
+ local perc = health / maxHealth
+
+ if health > 1 and perc <= self.db.lowHealthThreshold then
+ if perc <= self.db.lowHealthThreshold / 2 then
+ showIndicator = 2
+ else
+ showIndicator = 3
+ end
+ end
+ end
+
+ local glowStyle = self.db.units.TARGET.glowStyle
+ local healthIsShown = frame.Health:IsShown()
+
+ if not healthIsShown then
+ if glowStyle == "style1" then
+ glowStyle = "none"
+ elseif glowStyle == "style5" then
+ glowStyle = "style3"
+ elseif glowStyle == "style7" then
+ glowStyle = "style4"
+ end
+ end
+
+ if showIndicator and glowStyle ~= "none" then
+ local r, g, b
+
+ if showIndicator == 1 then
+ local color = self.db.colors.glowColor
+ r, g, b = color.r, color.g, color.b
+ elseif showIndicator == 2 then
+ r, g, b = 1, 0, 0
+ else
+ r, g, b = 1, 1, 0
+ end
+
+ -- Indicators
+ frame.TopIndicator:SetVertexColor(r, g, b)
+ frame.LeftIndicator:SetVertexColor(r, g, b)
+ frame.RightIndicator:SetVertexColor(r, g, b)
+
+ if glowStyle == "style3" or glowStyle == "style5" or glowStyle == "style6" then
+ frame.LeftIndicator:Hide()
+ frame.RightIndicator:Hide()
+
+ if healthIsShown then
+ frame.TopIndicator:Show()
+ end
+ elseif glowStyle == "style4" or glowStyle == "style7" or glowStyle == "style8" then
+ frame.TopIndicator:Hide()
+
+ if healthIsShown then
+ frame.LeftIndicator:Show()
+ frame.RightIndicator:Show()
+ end
+ end
+
+ -- Spark / Shadow
+ frame.Shadow:SetBackdropBorderColor(r, g, b)
+ frame.Spark:SetVertexColor(r, g, b)
+
+ if glowStyle == "style1" or glowStyle == "style5" or glowStyle == "style7" then
+ frame.Spark:Hide()
+ frame.Shadow:Show()
+ elseif glowStyle == "style2" or glowStyle == "style6" or glowStyle == "style8" then
+ frame.Shadow:Hide()
+ frame.Spark:Show()
+ end
+ else
+ frame.TopIndicator:Hide()
+ frame.LeftIndicator:Hide()
+ frame.RightIndicator:Hide()
+ frame.Shadow:Hide()
+ frame.Spark:Hide()
+ end
+end
+
+function NP:Configure_Glow(frame)
+ local glowStyle = self.db.units.TARGET.glowStyle
+ local healthIsShown = frame.Health:IsShown()
+
+ if not healthIsShown then
+ if glowStyle == "style1" then
+ glowStyle = "none"
+ elseif glowStyle == "style5" then
+ glowStyle = "style3"
+ elseif glowStyle == "style7" then
+ glowStyle = "style4"
+ end
+ end
+
+ if glowStyle ~= "none" then
+ local color = self.db.colors.glowColor
+ local r, g, b, a = color.r, color.g, color.b, color.a
+
+ -- Indicators
+ frame.LeftIndicator:SetVertexColor(r, g, b)
+ frame.RightIndicator:SetVertexColor(r, g, b)
+ frame.TopIndicator:SetVertexColor(r, g, b)
+
+ frame.TopIndicator:ClearAllPoints()
+ frame.LeftIndicator:ClearAllPoints()
+ frame.RightIndicator:ClearAllPoints()
+
+ if glowStyle == "style3" or glowStyle == "style5" or glowStyle == "style6" then
+ if healthIsShown then
+ frame.TopIndicator:SetPoint("BOTTOM", frame.Health, "TOP", 0, 6)
+ else
+ frame.TopIndicator:SetPoint("BOTTOM", frame.Name, "TOP", 0, 8)
+ end
+ elseif glowStyle == "style4" or glowStyle == "style7" or glowStyle == "style8" then
+ if healthIsShown then
+ frame.LeftIndicator:SetPoint("LEFT", frame.Health, "RIGHT", -3, 0)
+ frame.RightIndicator:SetPoint("RIGHT", frame.Health, "LEFT", 3, 0)
+ else
+ frame.LeftIndicator:SetPoint("LEFT", frame.Name, "RIGHT", 20, 0)
+ frame.RightIndicator:SetPoint("RIGHT", frame.Name, "LEFT", -20, 0)
+ end
+ end
+
+ -- Spark / Shadow
+ frame.Shadow:SetBackdropBorderColor(r, g, b)
+ frame.Shadow:SetAlpha(a)
+
+ frame.Spark:SetVertexColor(r, g, b, a)
+ frame.Spark:ClearAllPoints()
+
+ if glowStyle == "style1" or glowStyle == "style5" or glowStyle == "style7" then
+ frame.Shadow:SetOutside(frame.Health, E:Scale(E.PixelMode and 6 or 8), E:Scale(E.PixelMode and 6 or 8))
+ elseif glowStyle == "style2" or glowStyle == "style6" or glowStyle == "style8" then
+ if healthIsShown then
+ local size = E.Border + 14
+ frame.Spark:SetPoint("TOPLEFT", frame.Health, -(size * 2), size)
+ frame.Spark:SetPoint("BOTTOMRIGHT", frame.Health, (size * 2), -size)
+ else
+ local nameIsShown = frame.Name:IsShown()
+ frame.Spark:SetPoint("TOPLEFT", nameIsShown and frame.Name or frame.IconFrame, -20, 8)
+ frame.Spark:SetPoint("BOTTOMRIGHT", nameIsShown and frame.Name or frame.IconFrame, 20, -8)
+ end
+ end
+ end
+end
+
+local Textures = {"Spark", "TopIndicator", "LeftIndicator", "RightIndicator"}
+
+function NP:Construct_Glow(frame)
+ frame.Shadow = CreateFrame("Frame", "$parentGlow", frame)
+ frame.Shadow:SetFrameLevel(frame.Health:GetFrameLevel() - 1)
+ frame.Shadow:SetBackdrop({edgeFile = LSM:Fetch("border", "ElvUI GlowBorder"), edgeSize = E:Scale(6)})
+ frame.Shadow:Hide()
+
+ for _, object in ipairs(Textures) do
+ frame[object] = frame:CreateTexture(nil, "BACKGROUND")
+ frame[object]:Hide()
+ end
+
+ frame.Spark:SetTexture(E.Media.Textures.Spark)
+ frame.TopIndicator:SetTexture(E.Media.Textures.ArrowUp)
+ frame.TopIndicator:SetRotation(3.14)
+ frame.LeftIndicator:SetTexture(E.Media.Textures.ArrowUp)
+ frame.LeftIndicator:SetRotation(1.57)
+ frame.RightIndicator:SetTexture(E.Media.Textures.ArrowUp)
+ frame.RightIndicator:SetRotation(-1.57)
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/HealerIcon.lua b/ElvUI/Modules/Nameplates/Elements/HealerIcon.lua
new file mode 100644
index 0000000..81391d8
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/HealerIcon.lua
@@ -0,0 +1,31 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+
+--Lua functions
+--WoW API / Variables
+
+function NP:Update_HealerIcon(frame)
+ local icon = frame.HealerIcon
+ if frame.UnitType == "ENEMY_PLAYER" and self.Healers[frame.UnitName] then
+ icon:ClearAllPoints()
+ if frame.Health:IsShown() then
+ icon:SetPoint("RIGHT", frame.Health, "LEFT", -6, 0)
+ else
+ icon:SetPoint("BOTTOM", frame.Name, "TOP", 0, 3)
+ end
+
+ icon:Show()
+ else
+ icon:Hide()
+ end
+end
+
+function NP:Construct_HealerIcon(frame)
+ local texture = frame:CreateTexture(nil, "OVERLAY")
+ texture:SetPoint("RIGHT", frame.Health, "LEFT", -6, 0)
+ texture:SetSize(40, 40)
+ texture:SetTexture(E.Media.Textures.Healer)
+ texture:Hide()
+
+ return texture
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/HealthBar.lua b/ElvUI/Modules/Nameplates/Elements/HealthBar.lua
new file mode 100644
index 0000000..96e2fa7
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/HealthBar.lua
@@ -0,0 +1,213 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+local LSM = E.Libs.LSM
+
+--Lua functions
+--WoW API / Variables
+
+function NP:Update_HealthOnValueChanged()
+ local frame = self:GetParent().UnitFrame
+ if not frame.UnitType then return end -- Bugs
+
+ NP:Update_Health(frame)
+ NP:Update_HealthColor(frame)
+ NP:Update_Glow(frame)
+ NP:StyleFilterUpdate(frame, "UNIT_HEALTH")
+end
+
+function NP:Update_HealthColor(frame)
+ if not frame.Health:IsShown() then return end
+
+ local r, g, b
+ local scale = 1
+
+ local classColor = E.media.herocolor
+ local useClassColor = NP.db.units[frame.UnitType].health.useClassColor
+ if classColor and ((frame.UnitType == "FRIENDLY_PLAYER" and useClassColor) or (frame.UnitType == "ENEMY_PLAYER" and useClassColor)) then
+ r, g, b = classColor.r, classColor.g, classColor.b
+ else
+ local db = self.db.colors
+ local status = frame.ThreatStatus
+ if status then
+ if status == 3 then
+ if E.Role == "Tank" then
+ r, g, b = db.threat.goodColor.r, db.threat.goodColor.g, db.threat.goodColor.b
+ scale = NP.db.threat.goodScale
+ else
+ r, g, b = db.threat.badColor.r, db.threat.badColor.g, db.threat.badColor.b
+ scale = NP.db.threat.badScale
+ end
+ elseif status == 2 then
+ if E.Role == "Tank" then
+ r, g, b = db.threat.badTransition.r, db.threat.badTransition.g, db.threat.badTransition.b
+ else
+ r, g, b = db.threat.goodTransition.r, db.threat.goodTransition.g, db.threat.goodTransition.b
+ end
+ scale = 1
+ elseif status == 1 then
+ if E.Role == "Tank" then
+ r, g, b = db.threat.goodTransition.r, db.threat.goodTransition.g, db.threat.goodTransition.b
+ else
+ r, g, b = db.threat.badTransition.r, db.threat.badTransition.g, db.threat.badTransition.b
+ end
+ scale = 1
+ else
+ if E.Role == "Tank" then
+ r, g, b = db.threat.badColor.r, db.threat.badColor.g, db.threat.badColor.b
+ scale = self.db.threat.badScale
+ else
+ r, g, b = db.threat.goodColor.r, db.threat.goodColor.g, db.threat.goodColor.b
+ scale = self.db.threat.goodScale
+ end
+ end
+ end
+
+ if (not status) or (status and not NP.db.threat.useThreatColor) then
+ local reactionType = frame.UnitReaction
+ if reactionType == 4 then
+ r, g, b = db.reactions.neutral.r, db.reactions.neutral.g, db.reactions.neutral.b
+ elseif reactionType and reactionType > 4 then
+ if frame.UnitType == "FRIENDLY_PLAYER" then
+ r, g, b = db.reactions.friendlyPlayer.r, db.reactions.friendlyPlayer.g, db.reactions.friendlyPlayer.b
+ else
+ r, g, b = db.reactions.good.r, db.reactions.good.g, db.reactions.good.b
+ end
+ else
+ r, g, b = db.reactions.bad.r, db.reactions.bad.g, db.reactions.bad.b
+ end
+ end
+ end
+
+ if r ~= frame.Health.r or g ~= frame.Health.g or b ~= frame.Health.b then
+ if not frame.HealthColorChanged then
+ frame.Health:SetStatusBarColor(r, g, b)
+
+ if frame.HealthColorChangeCallbacks then
+ for _, cb in ipairs(frame.HealthColorChangeCallbacks) do
+ cb(self, frame, r, g, b)
+ end
+ end
+ end
+ frame.Health.r, frame.Health.g, frame.Health.b = r, g, b
+ end
+
+ if frame.ThreatScale ~= scale then
+ frame.ThreatScale = scale
+ if frame.isTarget and self.db.useTargetScale then
+ scale = scale * self.db.targetScale
+ end
+ self:SetFrameScale(frame, scale * (frame.ActionScale or 1))
+ end
+end
+
+function NP:Update_Health(frame)
+ local health = frame.oldHealthBar:GetValue()
+ local _, maxHealth = frame.oldHealthBar:GetMinMaxValues()
+ frame.Health:SetMinMaxValues(0, maxHealth)
+
+ if frame.HealthValueChangeCallbacks then
+ for _, cb in ipairs(frame.HealthValueChangeCallbacks) do
+ cb(self, frame, health, maxHealth)
+ end
+ end
+
+ frame.Health:SetValue(health)
+ frame.FlashTexture:Point("TOPRIGHT", frame.Health:GetStatusBarTexture(), "TOPRIGHT") --idk why this fixes this
+
+ if self.db.units[frame.UnitType].health.text.enable then
+ frame.Health.Text:SetText(E:GetFormattedText(self.db.units[frame.UnitType].health.text.format, health, maxHealth))
+ end
+end
+
+function NP:RegisterHealthBarCallbacks(frame, valueChangeCB, colorChangeCB)
+ if valueChangeCB then
+ frame.HealthValueChangeCallbacks = frame.HealthValueChangeCallbacks or {}
+ tinsert(frame.HealthValueChangeCallbacks, valueChangeCB)
+ end
+
+ if colorChangeCB then
+ frame.HealthColorChangeCallbacks = frame.HealthColorChangeCallbacks or {}
+ tinsert(frame.HealthColorChangeCallbacks, colorChangeCB)
+ end
+end
+
+function NP:Update_HealthBar(frame)
+ if self.db.units[frame.UnitType].health.enable or (frame.isTarget and self.db.alwaysShowTargetHealth) then
+ frame.Health:Show()
+ else
+ frame.Health:Hide()
+ end
+end
+
+function NP:Configure_HealthBarScale(frame, scale, noPlayAnimation)
+ if noPlayAnimation then
+ frame.Health:SetWidth(self.db.units[frame.UnitType].health.width * scale)
+ frame.Health:SetHeight(self.db.units[frame.UnitType].health.height * scale)
+ else
+ if frame.Health.scale:IsPlaying() then
+ frame.Health.scale:Stop()
+ end
+
+ frame.Health.scale.width:SetChange(self.db.units[frame.UnitType].health.width * scale)
+ frame.Health.scale.height:SetChange(self.db.units[frame.UnitType].health.height * scale)
+ frame.Health.scale:Play()
+ end
+end
+
+function NP:Configure_HealthBar(frame, configuring)
+ local db = self.db.units[frame.UnitType].health
+ local healthBar = frame.Health
+
+ healthBar:SetPoint("TOP", frame, "TOP", 0, 0)
+
+ if configuring then
+ healthBar:SetStatusBarTexture(LSM:Fetch("statusbar", self.db.statusbar), "BORDER")
+
+ self:Configure_HealthBarScale(frame, frame.currentScale or 1, configuring)
+
+ E:SetSmoothing(healthBar, self.db.smoothbars)
+
+ if db.text.enable then
+ healthBar.Text:ClearAllPoints()
+ healthBar.Text:Point(E.InversePoints[db.text.position], db.text.parent == "Nameplate" and frame or frame[db.text.parent], db.text.position, db.text.xOffset, db.text.yOffset)
+ healthBar.Text:FontTemplate(LSM:Fetch("font", db.text.font), db.text.fontSize, db.text.fontOutline)
+ healthBar.Text:Show()
+ else
+ healthBar.Text:Hide()
+ end
+ end
+end
+
+local function HealthBar_OnSizeChanged(self, width)
+ local health = self:GetValue()
+ local _, maxHealth = self:GetMinMaxValues()
+ self:GetStatusBarTexture():SetPoint("TOPRIGHT", -(width * ((maxHealth - health) / maxHealth)), 0)
+end
+
+function NP:Construct_HealthBar(parent)
+ local frame = CreateFrame("StatusBar", "$parentHealthBar", parent)
+ frame:SetStatusBarTexture(LSM:Fetch("statusbar", self.db.statusbar), "BORDER")
+ self:StyleFrame(frame)
+
+ frame:SetScript("OnSizeChanged", HealthBar_OnSizeChanged)
+
+ parent.FlashTexture = frame:CreateTexture(nil, "OVERLAY")
+ parent.FlashTexture:SetTexture(LSM:Fetch("background", "ElvUI Blank"))
+ parent.FlashTexture:Point("BOTTOMLEFT", frame:GetStatusBarTexture(), "BOTTOMLEFT")
+ parent.FlashTexture:Point("TOPRIGHT", frame:GetStatusBarTexture(), "TOPRIGHT")
+ parent.FlashTexture:Hide()
+
+ frame.Text = frame:CreateFontString(nil, "OVERLAY")
+ frame.Text:SetAllPoints(frame)
+ frame.Text:SetWordWrap(false)
+
+ frame.scale = CreateAnimationGroup(frame)
+ frame.scale.width = frame.scale:CreateAnimation("Width")
+ frame.scale.width:SetDuration(0.2)
+ frame.scale.height = frame.scale:CreateAnimation("Height")
+ frame.scale.height:SetDuration(0.2)
+
+ frame:Hide()
+
+ return frame
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/Highlight.lua b/ElvUI/Modules/Nameplates/Elements/Highlight.lua
new file mode 100644
index 0000000..5c6c52f
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/Highlight.lua
@@ -0,0 +1,34 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+local LSM = E.Libs.LSM
+
+--Lua functions
+--WoW API / Variables
+
+function NP:Update_Highlight(frame)
+ if not NP.db.highlight then return end
+
+ if frame.isMouseover and ((frame.IconOnlyChanged or frame.NameOnlyChanged) or (not self.db.units[frame.UnitType].health.enable and self.db.units[frame.UnitType].name.enable)) and not frame.isTarget then
+ frame.Name.NameOnlyGlow:Show()
+ frame.Health.Highlight:Show()
+ elseif frame.isMouseover and (not frame.NameOnlyChanged or self.db.units[frame.UnitType].health.enable) and not frame.isTarget then
+ frame.Health.Highlight:Show()
+ else
+ frame.Name.NameOnlyGlow:Hide()
+ frame.Health.Highlight:Hide()
+ end
+end
+
+function NP:Configure_Highlight(frame)
+ frame.Health.Highlight:ClearAllPoints()
+ frame.Health.Highlight:SetPoint("TOPLEFT", frame.Health, "TOPLEFT")
+ frame.Health.Highlight:SetPoint("BOTTOMRIGHT", frame.Health:GetStatusBarTexture(), "BOTTOMRIGHT")
+ frame.Health.Highlight:SetTexture(LSM:Fetch("statusbar", self.db.statusbar))
+end
+
+function NP:Construct_Highlight(frame)
+ local highlight = frame.Health:CreateTexture("$parentHighlight", "OVERLAY")
+ highlight:SetVertexColor(1, 1, 1, 0.3)
+ highlight:Hide()
+ return highlight
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/IconFrame.lua b/ElvUI/Modules/Nameplates/Elements/IconFrame.lua
new file mode 100644
index 0000000..0937abc
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/IconFrame.lua
@@ -0,0 +1,82 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+
+--Lua functions
+--WoW API / Variables
+
+function NP:Update_IconFrame(frame, triggered)
+ local db = self.db.units[frame.UnitType].iconFrame
+ if not db then return end
+
+ if (db and db.enable) or (frame.IconOnlyChanged or frame.IconChanged) then
+ local totem, unit, icon = self.Totems[frame.UnitName], self.UniqueUnits[frame.UnitName]
+ if totem then
+ icon = NP.TriggerConditions.totems[totem][3]
+ elseif unit then
+ icon = NP.TriggerConditions.uniqueUnits[unit][3]
+ end
+
+ if icon then
+ frame.IconFrame.texture:SetTexture(icon)
+ frame.IconFrame:Show()
+
+ self:StyleFrameColor(frame.IconFrame, frame.oldHealthBar:GetStatusBarColor())
+
+ if triggered then
+ frame.IconFrame:ClearAllPoints()
+ frame.IconFrame:SetPoint("TOP", frame)
+ end
+ else
+ frame.IconFrame:Hide()
+ end
+ else
+ frame.IconFrame:Hide()
+ end
+end
+
+function NP:Configure_IconOnlyGlow(frame)
+ local glowStyle = self.db.units.TARGET.glowStyle
+
+ frame.Shadow:Hide()
+ frame.Spark:Hide()
+
+ frame.TopIndicator:ClearAllPoints()
+ frame.LeftIndicator:ClearAllPoints()
+ frame.RightIndicator:ClearAllPoints()
+
+ if glowStyle == "style3" or glowStyle == "style5" or glowStyle == "style6" then
+ frame.TopIndicator:SetPoint("BOTTOM", frame.IconFrame, "TOP", -1, 6)
+ elseif glowStyle == "style4" or glowStyle == "style7" or glowStyle == "style8" then
+ frame.LeftIndicator:SetPoint("LEFT", frame.IconFrame, "RIGHT", -3, 0)
+ frame.RightIndicator:SetPoint("RIGHT", frame.IconFrame, "LEFT", 3, 0)
+ end
+end
+
+function NP:Configure_IconFrame(frame)
+ local db = self.db.units[frame.UnitType].iconFrame
+
+ if db then
+ if db.enable or frame.IconChanged then
+ frame.IconFrame:SetSize(db.size, db.size)
+ frame.IconFrame:ClearAllPoints()
+ frame.IconFrame:SetPoint(E.InversePoints[db.position], db.parent == "Nameplate" and frame or frame[db.parent], db.position, db.xOffset, db.yOffset)
+ else
+ frame.IconFrame:Hide()
+ end
+ end
+end
+
+function NP:Construct_IconFrame(frame)
+ local iconFrame = CreateFrame("Frame", nil, frame)
+ iconFrame:Hide()
+
+ iconFrame:SetSize(24, 24)
+ iconFrame:SetPoint("CENTER")
+ NP:StyleFrame(iconFrame, true)
+
+ iconFrame.texture = iconFrame:CreateTexture()
+ iconFrame.texture:SetAllPoints()
+ iconFrame.texture:SetTexCoord(unpack(E.TexCoords))
+
+ return iconFrame
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/Level.lua b/ElvUI/Modules/Nameplates/Elements/Level.lua
new file mode 100644
index 0000000..4f131b3
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/Level.lua
@@ -0,0 +1,39 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+local LSM = E.Libs.LSM
+
+--Lua functions
+--WoW API / Variables
+
+function NP:Update_Level(frame)
+ if not self.db.units[frame.UnitType].level.enable then return end
+
+ local levelText, r, g, b = self:UnitLevel(frame)
+
+ local level = frame.Level
+ level:ClearAllPoints()
+
+ if self.db.units[frame.UnitType].health.enable or (frame.isTarget and self.db.alwaysShowTargetHealth) then
+ level:SetJustifyH("RIGHT")
+ level:SetPoint("BOTTOMRIGHT", frame.Health, "TOPRIGHT", 0, E.Border*2)
+ else
+ level:SetPoint("LEFT", frame.Name, "RIGHT")
+ level:SetJustifyH("LEFT")
+ end
+
+ if self.db.units[frame.UnitType].health.enable or frame.isTarget then
+ level:SetText(levelText)
+ else
+ level:SetFormattedText(" [%s]", levelText)
+ end
+ level:SetTextColor(r, g, b)
+end
+
+function NP:Configure_Level(frame)
+ local db = self.db.units[frame.UnitType].level
+ frame.Level:FontTemplate(LSM:Fetch("font", db.font), db.fontSize, db.fontOutline)
+end
+
+function NP:Construct_Level(frame)
+ return frame:CreateFontString(nil, "OVERLAY")
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/Name.lua b/ElvUI/Modules/Nameplates/Elements/Name.lua
new file mode 100644
index 0000000..5384610
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/Name.lua
@@ -0,0 +1,124 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+local LSM = E.Libs.LSM
+
+--Lua functions
+local format = string.format
+local gmatch = gmatch
+local gsub = gsub
+local match = string.match
+local utf8lower = string.utf8lower
+local utf8sub = string.utf8sub
+--WoW API / Variables
+local UNKNOWN = UNKNOWN
+
+local function abbrev(name)
+ local letters, lastWord = "", match(name, ".+%s(.+)$")
+ if lastWord then
+ for word in gmatch(name, ".-%s") do
+ local firstLetter = utf8sub(gsub(word, "^[%s%p]*", ""), 1, 1)
+ if firstLetter ~= utf8lower(firstLetter) then
+ letters = format("%s%s. ", letters, firstLetter)
+ end
+ end
+ name = format("%s%s", letters, lastWord)
+ end
+ return name
+end
+
+function NP:Update_Name(frame, triggered)
+ if not triggered then
+ if not self.db.units[frame.UnitType].name.enable then return end
+ end
+
+ local name = frame.Name
+ local nameText = frame.UnitName or UNKNOWN
+ name:SetText(self.db.units[frame.UnitType].name.abbrev and abbrev(nameText) or nameText)
+
+ if not triggered then
+ name:ClearAllPoints()
+ if self.db.units[frame.UnitType].health.enable or (self.db.alwaysShowTargetHealth and frame.isTarget) then
+ name:SetJustifyH("LEFT")
+ name:SetPoint("BOTTOMLEFT", frame.Health, "TOPLEFT", 0, E.Border*2)
+ name:SetPoint("BOTTOMRIGHT", frame.Level, "BOTTOMLEFT")
+ else
+ name:SetJustifyH("CENTER")
+ name:SetPoint("TOP", frame)
+ end
+ end
+
+ local r, g, b = 1, 1, 1
+ local class = frame.UnitClass
+
+ local classColor, useClassColor
+ if class then
+ classColor = E.media.herocolor
+ useClassColor = self.db.units[frame.UnitType].name and self.db.units[frame.UnitType].name.useClassColor
+ end
+
+ if useClassColor and (frame.UnitType == "FRIENDLY_PLAYER" or frame.UnitType == "ENEMY_PLAYER") then
+ r, g, b = classColor.r, classColor.g, classColor.b
+ elseif triggered or (not self.db.units[frame.UnitType].health.enable and not frame.isTarget) then
+ local reactionType = frame.UnitReaction
+ if reactionType then
+ local db = self.db.colors
+ if reactionType == 4 then
+ r, g, b = db.reactions.neutral.r, db.reactions.neutral.g, db.reactions.neutral.b
+ elseif reactionType > 4 then
+ if frame.UnitType == "FRIENDLY_PLAYER" then
+ r, g, b = db.reactions.friendlyPlayer.r, db.reactions.friendlyPlayer.g, db.reactions.friendlyPlayer.b
+ else
+ r, g, b = db.reactions.good.r, db.reactions.good.g, db.reactions.good.b
+ end
+ else
+ r, g, b = db.reactions.bad.r, db.reactions.bad.g, db.reactions.bad.b
+ end
+ end
+ end
+
+ -- if for some reason the values failed just default to white
+ if not (r and g and b) then
+ r, g, b = 1, 1, 1
+ end
+
+ if triggered or (r ~= frame.Name.r or g ~= frame.Name.g or b ~= frame.Name.b) then
+ name:SetTextColor(r, g, b)
+ if not triggered then
+ frame.Name.r, frame.Name.g, frame.Name.b = r, g, b
+ end
+ end
+
+ if self.db.nameColoredGlow then
+ name.NameOnlyGlow:SetVertexColor(r - 0.1, g - 0.1, b - 0.1, 1)
+ else
+ name.NameOnlyGlow:SetVertexColor(self.db.colors.glowColor.r, self.db.colors.glowColor.g, self.db.colors.glowColor.b, self.db.colors.glowColor.a)
+ end
+end
+
+function NP:Configure_Name(frame)
+ local db = self.db.units[frame.UnitType].name
+ frame.Name:FontTemplate(LSM:Fetch("font", db.font), db.fontSize, db.fontOutline)
+end
+
+function NP:Configure_NameOnlyGlow(frame)
+ local name = frame.Name
+ name.NameOnlyGlow:ClearAllPoints()
+ name.NameOnlyGlow:SetPoint("TOPLEFT", frame.IconOnlyChanged and frame.IconFrame or name, -20, 8)
+ name.NameOnlyGlow:SetPoint("BOTTOMRIGHT", frame.IconOnlyChanged and frame.IconFrame or name, 20, -8)
+end
+
+function NP:Construct_Name(frame)
+ local name = frame:CreateFontString(nil, "OVERLAY")
+ name:SetJustifyV("BOTTOM")
+ name:SetWordWrap(false)
+
+ local g = frame:CreateTexture(nil, "BACKGROUND")
+ g:SetTexture(E.Media.Textures.Spark)
+ g:Hide()
+ g:SetPoint("TOPLEFT", name, -20, 8)
+ g:SetPoint("BOTTOMRIGHT", name, 20, -8)
+
+ name.NameOnlyGlow = g
+
+ return name
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Elements/RaidIcon.lua b/ElvUI/Modules/Nameplates/Elements/RaidIcon.lua
new file mode 100644
index 0000000..c3ea897
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Elements/RaidIcon.lua
@@ -0,0 +1,19 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+
+--Lua functions
+--WoW API / Variables
+
+function NP:Update_RaidIcon(frame)
+ local db = self.db.units[frame.UnitType].raidTargetIndicator
+ local icon = frame.RaidIcon
+
+ icon:SetSize(db.size, db.size)
+
+ icon:ClearAllPoints()
+ if frame.Health:IsShown() then
+ icon:SetPoint(E.InversePoints[db.position], frame.Health, db.position, db.xOffset, db.yOffset)
+ else
+ icon:SetPoint("BOTTOM", frame, "TOP", 0, 15)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Load_Nameplates.xml b/ElvUI/Modules/Nameplates/Load_Nameplates.xml
new file mode 100644
index 0000000..b9ed7f9
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Load_Nameplates.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/Nameplates.lua b/ElvUI/Modules/Nameplates/Nameplates.lua
new file mode 100644
index 0000000..9025637
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/Nameplates.lua
@@ -0,0 +1,1169 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local NP = E:GetModule("NamePlates")
+--local LSM = E.Libs.LSM
+local LAI = E.Libs.LAI
+
+--Lua functions
+local _G = _G
+local pcall = pcall
+local type = type
+local select, unpack, pairs, next, tonumber = select, unpack, pairs, next, tonumber
+local floor, random = math.floor, math.random
+local format, gsub, match, split = string.format, string.gsub, string.match, string.split
+local twipe = table.wipe
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetBattlefieldScore = GetBattlefieldScore
+local GetNumBattlefieldScores = GetNumBattlefieldScores
+local GetNumPartyMembers, GetNumRaidMembers = GetNumPartyMembers, GetNumRaidMembers
+local GetPlayerInfoByGUID = GetPlayerInfoByGUID
+local InCombatLockdown = InCombatLockdown
+local IsInInstance = IsInInstance
+local SetCVar = SetCVar
+local UnitExists = UnitExists
+local UnitGUID = UnitGUID
+local UnitHealthMax = UnitHealthMax
+local UnitIsPlayer = UnitIsPlayer
+local UnitName = UnitName
+local WorldFrame = WorldFrame
+local WorldGetChildren = WorldFrame.GetChildren
+local WorldGetNumChildren = WorldFrame.GetNumChildren
+
+local lastChildern, numChildren, hasTarget = 0, 0
+local OVERLAY = [=[Interface\TargetingFrame\UI-TargetingFrame-Flash]=]
+local FSPAT = "%s*"..(gsub(gsub(_G.FOREIGN_SERVER_LABEL, "^%s", ""), "[%*()]", "%%%1")).."$"
+
+local RaidIconCoordinate = {
+ [0] = {[0] = "STAR", [0.25] = "MOON"},
+ [0.25] = {[0] = "CIRCLE", [0.25] = "SQUARE"},
+ [0.5] = {[0] = "DIAMOND", [0.25] = "CROSS"},
+ [0.75] = {[0] = "TRIANGLE", [0.25] = "SKULL"}
+}
+
+NP.CreatedPlates = {}
+NP.VisiblePlates = {}
+NP.Healers = {}
+
+NP.GUIDByName = {}
+
+NP.ENEMY_PLAYER = {}
+NP.FRIENDLY_PLAYER = {}
+NP.ENEMY_NPC = {}
+NP.FRIENDLY_NPC = {}
+
+NP.ResizeQueue = {}
+
+NP.Totems = {}
+NP.UniqueUnits = {}
+
+function NP:CheckBGHealers()
+ local name, _, damageDone, healingDone
+ for i = 1, GetNumBattlefieldScores() do
+ name, _, _, _, _, _, _, _, _, _, damageDone, healingDone = GetBattlefieldScore(i)
+ if name then
+ name = match(name, "([^%-]+).*")
+ if name and healingDone > (damageDone * 2) then
+ self.Healers[name] = true
+ elseif name and self.Healers[name] then
+ self.Healers[name] = nil
+ end
+ end
+ end
+end
+
+function NP:SetFrameScale(frame, scale, noPlayAnimation)
+ if frame.currentScale ~= scale then
+ self:Configure_HealthBarScale(frame, scale, noPlayAnimation)
+ self:Configure_CastBarScale(frame, scale, noPlayAnimation)
+ self:Configure_CPointsScale(frame, scale, noPlayAnimation)
+ frame.currentScale = scale
+ end
+end
+
+function NP:GetPlateFrameLevel(frame)
+ local plateLevel
+ if frame.plateID then
+ plateLevel = 10 + frame.plateID*NP.levelStep
+ end
+ return plateLevel
+end
+
+function NP:SetPlateFrameLevel(frame, level, isTarget)
+ if frame and level then
+ if isTarget then
+ level = 890 --10 higher than the max calculated level of 880
+ elseif frame.FrameLevelChanged then
+ --calculate Style Filter FrameLevelChanged leveling
+ --level method: (10*(40*2)) max 800 + max 80 (40*2) = max 880
+ --highest possible should be level 880 and we add 1 to all so 881
+ local leveledCount = NP.CollectedFrameLevelCount or 1
+ level = (frame.FrameLevelChanged*(40*NP.levelStep)) + (leveledCount*NP.levelStep)
+ end
+
+ frame:SetFrameLevel(level+1)
+-- frame.Glow:SetFrameLevel(frame:GetFrameLevel()-1)
+ frame.Shadow:SetFrameLevel(frame:GetFrameLevel()-1)
+ frame.Buffs:SetFrameLevel(level+1)
+ frame.Debuffs:SetFrameLevel(level+1)
+ end
+end
+
+function NP:ResetNameplateFrameLevel(frame)
+ local isTarget = frame.isTarget --frame.isTarget is not the same here so keep this.
+ local plateLevel = NP:GetPlateFrameLevel(frame)
+ if plateLevel then
+ if frame.FrameLevelChanged then --keep how many plates we change, this is reset to 1 post-ResetNameplateFrameLevel
+ NP.CollectedFrameLevelCount = (NP.CollectedFrameLevelCount and NP.CollectedFrameLevelCount + 1) or 1
+ end
+ self:SetPlateFrameLevel(frame, plateLevel, isTarget)
+ end
+end
+
+function NP:StyleFrame(parent, noBackdrop, point)
+ point = point or parent
+ local noscalemult = E.mult * UIParent:GetScale()
+
+ if point.bordertop then return end
+
+ if not noBackdrop then
+ point.backdrop = parent:CreateTexture(nil, "BACKGROUND")
+ point.backdrop:SetAllPoints(point)
+ point.backdrop:SetTexture(unpack(E.media.backdropfadecolor))
+ end
+
+ if E.PixelMode then
+ point.bordertop = parent:CreateTexture()
+ point.bordertop:SetPoint("TOPLEFT", point, "TOPLEFT", -noscalemult, noscalemult)
+ point.bordertop:SetPoint("TOPRIGHT", point, "TOPRIGHT", noscalemult, noscalemult)
+ point.bordertop:SetHeight(noscalemult)
+ point.bordertop:SetTexture(unpack(E.media.bordercolor))
+
+ point.borderbottom = parent:CreateTexture()
+ point.borderbottom:SetPoint("BOTTOMLEFT", point, "BOTTOMLEFT", -noscalemult, -noscalemult)
+ point.borderbottom:SetPoint("BOTTOMRIGHT", point, "BOTTOMRIGHT", noscalemult, -noscalemult)
+ point.borderbottom:SetHeight(noscalemult)
+ point.borderbottom:SetTexture(unpack(E.media.bordercolor))
+
+ point.borderleft = parent:CreateTexture()
+ point.borderleft:SetPoint("TOPLEFT", point, "TOPLEFT", -noscalemult, noscalemult)
+ point.borderleft:SetPoint("BOTTOMLEFT", point, "BOTTOMLEFT", noscalemult, -noscalemult)
+ point.borderleft:SetWidth(noscalemult)
+ point.borderleft:SetTexture(unpack(E.media.bordercolor))
+
+ point.borderright = parent:CreateTexture()
+ point.borderright:SetPoint("TOPRIGHT", point, "TOPRIGHT", noscalemult, noscalemult)
+ point.borderright:SetPoint("BOTTOMRIGHT", point, "BOTTOMRIGHT", -noscalemult, -noscalemult)
+ point.borderright:SetWidth(noscalemult)
+ point.borderright:SetTexture(unpack(E.media.bordercolor))
+ else
+ point.bordertop = parent:CreateTexture(nil, "OVERLAY")
+ point.bordertop:SetPoint("TOPLEFT", point, "TOPLEFT", -noscalemult, noscalemult*2)
+ point.bordertop:SetPoint("TOPRIGHT", point, "TOPRIGHT", noscalemult, noscalemult*2)
+ point.bordertop:SetHeight(noscalemult)
+ point.bordertop:SetTexture(unpack(E.media.bordercolor))
+
+ point.bordertop.backdrop = parent:CreateTexture()
+ point.bordertop.backdrop:SetPoint("TOPLEFT", point.bordertop, "TOPLEFT", noscalemult, noscalemult)
+ point.bordertop.backdrop:SetPoint("TOPRIGHT", point.bordertop, "TOPRIGHT", -noscalemult, noscalemult)
+ point.bordertop.backdrop:SetHeight(noscalemult * 3)
+ point.bordertop.backdrop:SetTexture(0, 0, 0)
+
+ point.borderbottom = parent:CreateTexture(nil, "OVERLAY")
+ point.borderbottom:SetPoint("BOTTOMLEFT", point, "BOTTOMLEFT", -noscalemult, -noscalemult*2)
+ point.borderbottom:SetPoint("BOTTOMRIGHT", point, "BOTTOMRIGHT", noscalemult, -noscalemult*2)
+ point.borderbottom:SetHeight(noscalemult)
+ point.borderbottom:SetTexture(unpack(E.media.bordercolor))
+
+ point.borderbottom.backdrop = parent:CreateTexture()
+ point.borderbottom.backdrop:SetPoint("BOTTOMLEFT", point.borderbottom, "BOTTOMLEFT", noscalemult, -noscalemult)
+ point.borderbottom.backdrop:SetPoint("BOTTOMRIGHT", point.borderbottom, "BOTTOMRIGHT", -noscalemult, -noscalemult)
+ point.borderbottom.backdrop:SetHeight(noscalemult * 3)
+ point.borderbottom.backdrop:SetTexture(0, 0, 0)
+
+ point.borderleft = parent:CreateTexture(nil, "OVERLAY")
+ point.borderleft:SetPoint("TOPLEFT", point, "TOPLEFT", -noscalemult*2, noscalemult*2)
+ point.borderleft:SetPoint("BOTTOMLEFT", point, "BOTTOMLEFT", noscalemult*2, -noscalemult*2)
+ point.borderleft:SetWidth(noscalemult)
+ point.borderleft:SetTexture(unpack(E.media.bordercolor))
+
+ point.borderleft.backdrop = parent:CreateTexture()
+ point.borderleft.backdrop:SetPoint("TOPLEFT", point.borderleft, "TOPLEFT", -noscalemult, noscalemult)
+ point.borderleft.backdrop:SetPoint("BOTTOMLEFT", point.borderleft, "BOTTOMLEFT", -noscalemult, -noscalemult)
+ point.borderleft.backdrop:SetWidth(noscalemult * 3)
+ point.borderleft.backdrop:SetTexture(0, 0, 0)
+
+ point.borderright = parent:CreateTexture(nil, "OVERLAY")
+ point.borderright:SetPoint("TOPRIGHT", point, "TOPRIGHT", noscalemult*2, noscalemult*2)
+ point.borderright:SetPoint("BOTTOMRIGHT", point, "BOTTOMRIGHT", -noscalemult*2, -noscalemult*2)
+ point.borderright:SetWidth(noscalemult)
+ point.borderright:SetTexture(unpack(E.media.bordercolor))
+
+ point.borderright.backdrop = parent:CreateTexture()
+ point.borderright.backdrop:SetPoint("TOPRIGHT", point.borderright, "TOPRIGHT", noscalemult, noscalemult)
+ point.borderright.backdrop:SetPoint("BOTTOMRIGHT", point.borderright, "BOTTOMRIGHT", noscalemult, -noscalemult)
+ point.borderright.backdrop:SetWidth(noscalemult * 3)
+ point.borderright.backdrop:SetTexture(0, 0, 0)
+ end
+end
+
+function NP:StyleFrameColor(frame, r, g, b)
+ frame.bordertop:SetTexture(r, g, b)
+ frame.borderbottom:SetTexture(r, g, b)
+ frame.borderleft:SetTexture(r, g, b)
+ frame.borderright:SetTexture(r, g, b)
+end
+
+function NP:GetUnitByName(frame, unitType)
+ local unit = self[unitType][frame.UnitName]
+ if unit then
+ return unit
+ end
+end
+
+function NP:GetUnitClassByGUID(frame, guid)
+ if not guid then guid = self.GUIDByName[frame.UnitName] end
+ if guid then
+ local _, _, class = pcall(GetPlayerInfoByGUID, guid)
+ return class
+ end
+end
+
+function NP:UnitClass(frame, unitType)
+ return "DRUID"
+end
+
+function NP:UnitDetailedThreatSituation(frame)
+ if not frame.Threat:IsShown() then
+ if frame.UnitType == "ENEMY_NPC" then
+ local r, g = frame.oldName:GetTextColor()
+ return (r > 0.5 and g < 0.5) and 0 or nil
+ end
+ else
+ local r, g, b = frame.Threat:GetVertexColor()
+ if r > 0 then
+ if g > 0 then
+ if b > 0 then return 1 end
+ return 2
+ end
+ return 3
+ end
+ end
+end
+
+function NP:UnitLevel(frame)
+ local level, boss = frame.oldLevel:GetObjectType() == "FontString" and tonumber(frame.oldLevel:GetText()) or false, frame.BossIcon:IsShown()
+ if boss or not level then
+ return "??", 0.9, 0, 0
+ else
+ return level, frame.oldLevel:GetTextColor()
+ end
+end
+
+function NP:GetUnitInfo(frame)
+ local r, g, b = frame.oldHealthBar:GetStatusBarColor()
+ if r < 0.01 then
+ if b < 0.01 and g > 0.99 then
+ return 5, "FRIENDLY_NPC"
+ elseif b > 0.99 and g < 0.01 then
+ return 5, "FRIENDLY_PLAYER"
+ end
+ elseif r > 0.99 then
+ if b < 0.01 and g > 0.99 then
+ return 4, "ENEMY_NPC"
+ elseif b < 0.01 and g < 0.01 then
+ return 2, "ENEMY_NPC"
+ end
+ elseif r > 0.5 and r < 0.6 then
+ if g > 0.5 and g < 0.6 and b > 0.5 and b < 0.6 then
+ return 1, "ENEMY_NPC"
+ end
+ end
+ return 3, "ENEMY_PLAYER"
+end
+
+function NP:OnShow(isConfig, dontHideHighlight)
+ local frame = self.UnitFrame
+ NP:CheckRaidIcon(frame)
+
+ if self:IsShown() then
+ NP.VisiblePlates[frame] = 1
+ end
+
+ frame.UnitName = gsub(frame.oldName:GetText(), FSPAT, "")
+ local reaction, unitType = NP:GetUnitInfo(frame)
+ frame.UnitReaction = reaction
+
+ local unit = NP:GetUnitByName(frame, unitType)
+ if unit then
+ frame.unit = unit
+ frame.isGroupUnit = true
+
+ local guid = NP.GUIDByName[frame.UnitName] or UnitGUID(unit)
+ if guid then
+ frame.guid = guid
+ end
+ elseif unitType ~= "ENEMY_NPC" then
+ frame.guid = NP.GUIDByName[frame.UnitName]
+ end
+
+ frame.UnitClass = NP:UnitClass(frame, unitType)
+
+ if unitType ~= frame.UnitType or isConfig then
+ frame.UnitType = unitType
+
+ NP:Update_HealthBar(frame)
+
+ NP:Configure_CPoints(frame, true)
+
+ NP:Configure_Level(frame)
+ NP:Configure_Name(frame)
+
+ NP:Configure_Auras(frame, "Buffs")
+ NP:Configure_Auras(frame, "Debuffs")
+
+ if NP.db.units[unitType].health.enable or NP.db.alwaysShowTargetHealth then
+ NP:Configure_HealthBar(frame, true)
+ NP:Configure_CastBar(frame, true)
+ end
+
+ NP:Configure_Glow(frame)
+ NP:Configure_Elite(frame)
+ NP:Configure_Highlight(frame)
+ NP:Configure_IconFrame(frame)
+ end
+
+ frame.CutawayHealth:Hide()
+
+ NP:RegisterEvents(frame)
+ NP:UpdateElement_All(frame, nil, true)
+
+ NP:SetSize(self)
+
+ if not frame.isAlphaChanged then
+ if not dontHideHighlight then
+ NP:PlateFade(frame, NP.db.fadeIn and 1 or 0, 0, 1)
+ end
+ end
+
+ frame:Show()
+
+ NP:StyleFilterUpdate(frame, "NAME_PLATE_UNIT_ADDED")
+ NP:ForEachVisiblePlate("ResetNameplateFrameLevel") --keep this after `StyleFilterUpdate`
+end
+
+function NP:OnHide(isConfig, dontHideHighlight)
+ local frame = self.UnitFrame
+ NP.VisiblePlates[frame] = nil
+
+ frame.unit = nil
+ frame.isGroupUnit = nil
+
+ for i = 1, #frame.Buffs do
+ frame.Buffs[i]:SetScript("OnUpdate", nil)
+ frame.Buffs[i].timeLeft = nil
+ frame.Buffs[i]:Hide()
+ end
+
+ for i = 1, #frame.Debuffs do
+ frame.Debuffs[i]:SetScript("OnUpdate", nil)
+ frame.Debuffs[i].timeLeft = nil
+ frame.Debuffs[i]:Hide()
+ end
+
+ if isConfig then
+ frame.Buffs.anchoredIcons = 0
+ frame.Debuffs.anchoredIcons = 0
+ end
+
+ NP:StyleFilterClear(frame)
+
+ if frame.currentScale and frame.currentScale ~= 1 then
+ NP:SetFrameScale(frame, 1, true)
+ end
+
+ if frame.isEventsRegistered then
+ NP:UnregisterAllEvents(frame)
+ end
+
+ frame.TopIndicator:Hide()
+ frame.LeftIndicator:Hide()
+ frame.RightIndicator:Hide()
+ frame.Shadow:Hide()
+ frame.Spark:Hide()
+ frame.Health.r, frame.Health.g, frame.Health.b = nil, nil, nil
+ frame.Health:Hide()
+ frame.CastBar:Hide()
+ frame.CastBar.casting = nil
+ frame.CastBar.channeling = nil
+ frame.CastBar.notInterruptible = nil
+ frame.CastBar.spellName = nil
+ frame.Level:SetText()
+ frame.Name.r, frame.Name.g, frame.Name.b = nil, nil, nil
+ frame.Name:SetText()
+ frame.Name.NameOnlyGlow:Hide()
+ frame.Elite:Hide()
+ frame.CPoints:Hide()
+ frame.IconFrame:Hide()
+ frame:Hide()
+ frame.isTarget = nil
+ frame.isTargetChanged = false
+ frame.isMouseover = nil
+ frame.currentScale = nil
+ frame.UnitName = nil
+ frame.UnitClass = nil
+ frame.UnitReaction = nil
+ frame.TopLevelFrame = nil
+ frame.TopOffset = nil
+ frame.ThreatReaction = nil
+ frame.guid = nil
+ frame.alpha = nil
+ frame.isAlphaChanged = nil
+ frame.RaidIconType = nil
+ frame.ThreatScale = nil
+ frame.ThreatStatus = nil
+
+ if not dontHideHighlight then
+ frame.oldHighlight:Hide()
+ end
+
+ NP:StyleFilterClearVariables(self)
+end
+
+function NP:UpdateAllFrame(frame, isConfig, dontHideHighlight)
+ frame = frame:GetParent()
+
+ self.OnHide(frame, isConfig, dontHideHighlight)
+ self.OnShow(frame, isConfig, dontHideHighlight)
+end
+
+function NP:ConfigureAll()
+ if not E.private.nameplates.enable then return end
+
+ NP:StyleFilterConfigure()
+ NP:ForEachPlate("UpdateAllFrame", true, true)
+ NP:UpdateCVars()
+end
+
+function NP:ForEachPlate(functionToRun, ...)
+ for frame in pairs(self.CreatedPlates) do
+ if frame and frame.UnitFrame then
+ self[functionToRun](self, frame.UnitFrame, ...)
+ end
+ end
+
+ if functionToRun == "ResetNameplateFrameLevel" then
+ NP.CollectedFrameLevelCount = 1
+ end
+end
+
+function NP:ForEachVisiblePlate(functionToRun, ...)
+ for frame in pairs(self.VisiblePlates) do
+ self[functionToRun](self, frame, ...)
+ end
+end
+
+function NP:UpdateElement_All(frame, noTargetFrame, filterIgnore)
+ local healthShown = self.db.units[frame.UnitType].health.enable or (frame.isTarget and self.db.alwaysShowTargetHealth)
+
+ self:Update_HealthBar(frame)
+
+ if healthShown then
+ self:Update_Health(frame)
+ self:Update_HealthColor(frame)
+ self:Update_CastBar(frame, nil, frame.unit)
+ NP:UpdateElement_Auras(frame)
+ end
+
+ self:Update_RaidIcon(frame)
+ self:Update_HealerIcon(frame)
+
+ frame.Level:ClearAllPoints()
+ frame.Name:ClearAllPoints()
+ self:Update_Name(frame)
+ self:Update_Level(frame)
+
+ if not noTargetFrame then
+ self:Update_Elite(frame)
+ self:Update_Highlight(frame)
+ self:Update_Glow(frame)
+
+ self:SetTargetFrame(frame)
+ end
+
+ self:Update_IconFrame(frame)
+
+ if not filterIgnore then
+ self:StyleFilterUpdate(frame, "UpdateElement_All")
+ end
+end
+
+function NP:SetSize(frame)
+ if InCombatLockdown() then
+ self.ResizeQueue[frame] = true
+ else
+ local unitFrame = frame.UnitFrame
+ local unitType = unitFrame.UnitType
+ unitType = (unitType == "FRIENDLY_PLAYER" or unitType == "FRIENDLY_NPC") and "friendly" or "enemy"
+
+ if self.db.clickThrough[unitType] then
+ frame:SetSize(0.001, 0.001)
+ else
+ if unitType == "friendly" then
+ frame:SetSize(self.db.plateSize.friendlyWidth, self.db.plateSize.friendlyHeight)
+ else
+ frame:SetSize(self.db.plateSize.enemyWidth, self.db.plateSize.enemyHeight)
+ end
+ end
+
+ self.ResizeQueue[frame] = nil
+ end
+end
+
+local plateID = 0
+function NP:OnCreated(frame)
+ plateID = plateID + 1
+ local Health, CastBar = frame:GetChildren()
+ local Threat, Border, CastBarBorder, CastBarShield, CastBarIcon, Highlight, Name, Level, BossIcon, RaidIcon, EliteIcon = frame:GetRegions()
+
+ local unitFrame = CreateFrame("Frame", format("ElvUI_NamePlate%d", plateID), frame)
+ frame.UnitFrame = unitFrame
+ unitFrame:Hide()
+ unitFrame:SetAllPoints()
+ unitFrame:SetScript("OnEvent", self.OnEvent)
+ unitFrame.plateID = plateID
+
+ unitFrame.Health = self:Construct_HealthBar(unitFrame)
+ unitFrame.Health.Highlight = self:Construct_Highlight(unitFrame)
+ unitFrame.CutawayHealth = self:ConstructElement_CutawayHealth(unitFrame)
+ unitFrame.Level = self:Construct_Level(unitFrame)
+ unitFrame.Name = self:Construct_Name(unitFrame)
+ unitFrame.CastBar = self:Construct_CastBar(unitFrame)
+ unitFrame.Elite = self:Construct_Elite(unitFrame)
+ unitFrame.Buffs = self:ConstructElement_Auras(unitFrame, "Buffs")
+ unitFrame.Debuffs = self:ConstructElement_Auras(unitFrame, "Debuffs")
+ unitFrame.HealerIcon = self:Construct_HealerIcon(unitFrame)
+ unitFrame.CPoints = self:Construct_CPoints(unitFrame)
+ unitFrame.IconFrame = self:Construct_IconFrame(unitFrame)
+ self:Construct_Glow(unitFrame)
+
+ self:QueueObject(Health)
+ self:QueueObject(CastBar)
+ self:QueueObject(Level)
+ self:QueueObject(Name)
+ self:QueueObject(Threat)
+ self:QueueObject(Border)
+ self:QueueObject(CastBarBorder)
+ self:QueueObject(CastBarShield)
+ self:QueueObject(Highlight)
+ BossIcon:SetAlpha(0)
+ EliteIcon:SetAlpha(0)
+
+ unitFrame.oldHealthBar = Health
+ unitFrame.oldCastBar = CastBar
+ unitFrame.oldCastBar.Shield = CastBarShield
+ unitFrame.oldCastBar.Icon = CastBarIcon
+ unitFrame.oldName = Name
+ unitFrame.oldHighlight = Highlight
+ unitFrame.oldLevel = Level
+
+ unitFrame.Threat = Threat
+ RaidIcon:SetParent(unitFrame)
+ unitFrame.RaidIcon = RaidIcon
+
+ unitFrame.BossIcon = BossIcon
+ unitFrame.EliteIcon = EliteIcon
+
+ self.OnShow(frame, true)
+ self:SetSize(frame)
+
+ frame:HookScript("OnShow", self.OnShow)
+ frame:HookScript("OnHide", self.OnHide)
+ Health:HookScript("OnValueChanged", self.Update_HealthOnValueChanged)
+
+ self.CreatedPlates[frame] = true
+ self.VisiblePlates[unitFrame] = 1
+end
+
+function NP:OnEvent(event, unit, ...)
+ if not unit and not self.unit then return end
+ if self.unit ~= unit then return end
+
+ NP:Update_CastBar(self, event, unit, ...)
+end
+
+function NP:RegisterEvents(frame)
+ if not frame.unit then return end
+
+ if self.db.units[frame.UnitType].health.enable or (frame.isTarget and self.db.alwaysShowTargetHealth) then
+ if self.db.units[frame.UnitType].castbar.enable then
+ frame:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
+ frame:RegisterEvent("UNIT_SPELLCAST_DELAYED")
+ frame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
+ frame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
+ frame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
+ frame:RegisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE")
+ frame:RegisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE")
+ frame:RegisterEvent("UNIT_SPELLCAST_START")
+ frame:RegisterEvent("UNIT_SPELLCAST_STOP")
+ frame:RegisterEvent("UNIT_SPELLCAST_FAILED")
+ frame.isEventsRegistered = true
+ end
+
+ NP.OnEvent(frame, nil, frame.unit)
+ end
+end
+
+function NP:UnregisterAllEvents(frame)
+ frame:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED")
+ frame:UnregisterEvent("UNIT_SPELLCAST_DELAYED")
+ frame:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START")
+ frame:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
+ frame:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
+ frame:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE")
+ frame:UnregisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE")
+ frame:UnregisterEvent("UNIT_SPELLCAST_START")
+ frame:UnregisterEvent("UNIT_SPELLCAST_STOP")
+ frame:UnregisterEvent("UNIT_SPELLCAST_FAILED")
+ frame.isEventsRegistered = nil
+end
+
+function NP:QueueObject(object)
+ local objectType = object:GetObjectType()
+ if objectType == "Texture" then
+ object:SetTexture("")
+ object:SetTexCoord(0, 0, 0, 0)
+ elseif objectType == "FontString" then
+ object:SetWidth(0.001)
+ elseif objectType == "StatusBar" then
+ object:SetStatusBarTexture("")
+ end
+ object:Hide()
+end
+
+function NP:PlateFade(nameplate, timeToFade, startAlpha, endAlpha)
+ -- we need our own function because we want a smooth transition and dont want it to force update every pass.
+ -- its controlled by fadeTimer which is reset when UIFrameFadeOut or UIFrameFadeIn code runs.
+
+ if not nameplate.FadeObject then
+ nameplate.FadeObject = {}
+ end
+
+ nameplate.FadeObject.timeToFade = (nameplate.isTarget and 0) or timeToFade
+ nameplate.FadeObject.startAlpha = startAlpha
+ nameplate.FadeObject.endAlpha = endAlpha
+ nameplate.FadeObject.diffAlpha = endAlpha - startAlpha
+
+ if nameplate.FadeObject.fadeTimer then
+ nameplate.FadeObject.fadeTimer = 0
+ else
+ E:UIFrameFade(nameplate, nameplate.FadeObject)
+ end
+end
+
+function NP:SetTargetFrame(frame)
+ if hasTarget and frame.alpha == 1 then
+ if not frame.isTarget then
+ frame.isTarget = true
+
+ self:SetPlateFrameLevel(frame, self:GetPlateFrameLevel(frame), true)
+
+ if self.db.useTargetScale then
+ self:SetFrameScale(frame, (frame.ThreatScale or 1) * self.db.targetScale)
+ end
+
+ if not frame.isGroupUnit then
+ frame.unit = "target"
+ frame.guid = UnitGUID("target")
+
+ self:RegisterEvents(frame)
+ end
+
+ self:UpdateElement_Auras(frame)
+
+ if not self.db.units[frame.UnitType].health.enable and self.db.alwaysShowTargetHealth then
+ frame.Health.r, frame.Health.g, frame.Health.b = nil, nil, nil
+
+ self:Configure_HealthBar(frame)
+ self:Configure_CastBar(frame)
+
+ self:Configure_Elite(frame)
+ self:Configure_CPoints(frame)
+
+ self:RegisterEvents(frame)
+
+ self:UpdateElement_All(frame, true)
+
+ self:Configure_Glow(frame)
+ end
+
+ NP:PlateFade(frame, NP.db.fadeIn and 1 or 0, frame:GetAlpha(), 1)
+
+ self:Update_Highlight(frame)
+ self:Update_Glow(frame)
+ self:Update_CPoints(frame)
+ self:StyleFilterUpdate(frame, "PLAYER_TARGET_CHANGED")
+ self:ForEachVisiblePlate("ResetNameplateFrameLevel") --keep this after `StyleFilterUpdate`
+ end
+ elseif frame.isTarget then
+ frame.isTarget = nil
+
+ self:SetPlateFrameLevel(frame, self:GetPlateFrameLevel(frame))
+
+ if self.db.useTargetScale then
+ self:SetFrameScale(frame, (frame.ThreatScale or 1))
+ end
+
+ if not frame.isGroupUnit then
+ frame.unit = nil
+
+ if frame.isEventsRegistered then
+ self:UnregisterAllEvents(frame)
+ self:Update_CastBar(frame)
+ end
+ end
+
+ if not self.db.units[frame.UnitType].health.enable then
+ self:UpdateAllFrame(frame, nil, true)
+ else
+ self:Update_Glow(frame)
+ end
+
+ self:Update_CPoints(frame)
+
+ if not frame.AlphaChanged then
+ if hasTarget then
+ NP:PlateFade(frame, NP.db.fadeIn and 1 or 0, frame:GetAlpha(), self.db.nonTargetTransparency)
+ else
+ NP:PlateFade(frame, NP.db.fadeIn and 1 or 0, frame:GetAlpha(), 1)
+ end
+ end
+
+ self:StyleFilterUpdate(frame, "PLAYER_TARGET_CHANGED")
+ self:ForEachVisiblePlate("ResetNameplateFrameLevel") --keep this after `StyleFilterUpdate`
+ else
+ if hasTarget and not frame.isAlphaChanged then
+ frame.isAlphaChanged = true
+
+ if not frame.AlphaChanged then
+ NP:PlateFade(frame, NP.db.fadeIn and 1 or 0, frame:GetAlpha(), self.db.nonTargetTransparency)
+ end
+
+ self:StyleFilterUpdate(frame, "PLAYER_TARGET_CHANGED")
+ elseif not hasTarget and frame.isAlphaChanged then
+ frame.isAlphaChanged = nil
+
+ if not frame.AlphaChanged then
+ NP:PlateFade(frame, NP.db.fadeIn and 1 or 0, frame:GetAlpha(), 1)
+ end
+
+ self:StyleFilterUpdate(frame, "PLAYER_TARGET_CHANGED")
+ end
+ end
+end
+
+function NP:SetMouseoverFrame(frame)
+ if frame.oldHighlight:IsShown() then
+ if not frame.isMouseover then
+ frame.isMouseover = true
+
+ self:Update_Highlight(frame)
+
+ if not frame.isGroupUnit then
+ frame.unit = "mouseover"
+ frame.guid = UnitGUID("mouseover")
+
+ self:Update_CastBar(frame, nil, frame.unit)
+ end
+
+ self:UpdateElement_Auras(frame)
+ end
+ elseif frame.isMouseover then
+ frame.isMouseover = nil
+
+ self:Update_Highlight(frame)
+
+ if not frame.isGroupUnit then
+ frame.unit = nil
+
+ self:Update_CastBar(frame)
+ end
+ end
+end
+
+local function findNewPlate(...)
+ for i = lastChildern + 1, numChildren do
+ local frame = select(i, ...)
+ local region = frame:GetRegions()
+ if region and region:GetObjectType() == "Texture" and region:GetTexture() == OVERLAY and not NP.CreatedPlates[frame] then
+ NP:OnCreated(frame)
+ end
+ end
+end
+
+function NP:OnUpdate()
+ numChildren = WorldGetNumChildren(WorldFrame)
+ if lastChildern ~= numChildren then
+ findNewPlate(WorldGetChildren(WorldFrame))
+ lastChildern = numChildren
+ end
+
+ for frame in pairs(NP.VisiblePlates) do
+ if hasTarget then
+ frame.alpha = frame:GetParent():GetAlpha()
+ frame:GetParent():SetAlpha(1)
+ else
+ frame.alpha = 1
+ end
+
+ NP:SetMouseoverFrame(frame)
+ NP:SetTargetFrame(frame)
+
+ if frame.UnitReaction ~= NP:GetUnitInfo(frame) then
+ NP:UpdateAllFrame(frame, nil, true)
+ end
+
+ local status = NP:UnitDetailedThreatSituation(frame)
+ if frame.ThreatStatus ~= status then
+ frame.ThreatStatus = status
+
+ NP:Update_HealthColor(frame)
+ end
+ end
+end
+
+function NP:CheckRaidIcon(frame)
+ if frame.RaidIcon:IsShown() then
+ local ux, uy = frame.RaidIcon:GetTexCoord()
+ frame.RaidIconType = RaidIconCoordinate[ux][uy]
+ else
+ frame.RaidIconType = nil
+ end
+end
+
+function NP:SearchNameplateByGUID(guid)
+ for frame in pairs(self.VisiblePlates) do
+ if frame and frame:IsShown() and frame.guid == guid then
+ return frame
+ end
+ end
+end
+
+function NP:SearchNameplateByName(sourceName)
+ if not sourceName then return end
+ local SearchFor = split("-", sourceName)
+ for frame in pairs(self.VisiblePlates) do
+ if frame and frame:IsShown() and frame.UnitName == SearchFor then
+ return frame
+ end
+ end
+end
+
+function NP:SearchNameplateByIconName(raidIcon)
+ for frame in pairs(self.VisiblePlates) do
+ self:CheckRaidIcon(frame)
+ if frame and frame:IsShown() and frame.RaidIcon:IsShown() and (frame.RaidIconType == raidIcon) then
+ return frame
+ end
+ end
+end
+
+function NP:SearchForFrame(guid, raidIcon, name)
+ local frame
+ if guid then frame = self:SearchNameplateByGUID(guid) end
+ if (not frame) and name then frame = self:SearchNameplateByName(name) end
+ if (not frame) and raidIcon then frame = self:SearchNameplateByIconName(raidIcon) end
+
+ return frame
+end
+
+function NP:UpdateCVars()
+ SetCVar("ShowClassColorInNameplate", "1")
+ SetCVar("showVKeyCastbar", "0")
+ SetCVar("nameplateAllowOverlap", self.db.motionType == "STACKED" and "0" or "1")
+end
+
+local function CopySettings(from, to)
+ for setting, value in pairs(from) do
+ if type(value) == "table" and to[setting] ~= nil then
+ CopySettings(from[setting], to[setting])
+ else
+ if to[setting] ~= nil then
+ to[setting] = from[setting]
+ end
+ end
+ end
+end
+
+function NP:ResetSettings(unit)
+ CopySettings(P.nameplates.units[unit], self.db.units[unit])
+end
+
+function NP:CopySettings(from, to)
+ if from == to then return end
+
+ CopySettings(self.db.units[from], self.db.units[to])
+end
+
+function NP:PLAYER_ENTERING_WORLD()
+ twipe(self.Healers)
+ local inInstance, instanceType = IsInInstance()
+ if inInstance and (instanceType == "pvp") and self.db.units.ENEMY_PLAYER.markHealers then
+ self:RegisterEvent("UPDATE_BATTLEFIELD_SCORE", "CheckBGHealers")
+ self.CheckHealerTimer = self:ScheduleRepeatingTimer("CheckBGHealers", 3)
+ else
+ self:UnregisterEvent("UPDATE_BATTLEFIELD_SCORE")
+ if self.CheckHealerTimer then
+ self:CancelTimer(self.CheckHealerTimer)
+ self.CheckHealerTimer = nil;
+ end
+ end
+end
+
+function NP:PLAYER_TARGET_CHANGED()
+ hasTarget = UnitExists("target") == 1
+end
+
+function NP:UPDATE_MOUSEOVER_UNIT()
+ if UnitIsPlayer("mouseover")then
+ local name = UnitName("mouseover")
+ for frame in pairs(NP.VisiblePlates) do
+ if frame.UnitName == name then
+ local guid = UnitGUID("mouseover")
+ if NP.GUIDByName[name] ~= guid then
+ NP.GUIDByName[name] = guid
+ NP.OnShow(frame:GetParent(), nil, true)
+ end
+ end
+ end
+ end
+end
+
+function NP:UNIT_COMBO_POINTS(_, unit)
+ if unit == "player" or unit == "vehicle" then
+ self:ForEachVisiblePlate("Update_CPoints")
+ end
+end
+
+function NP:PLAYER_REGEN_DISABLED()
+ if self.db.showFriendlyCombat == "TOGGLE_ON" then
+ SetCVar("nameplateShowFriends", 1)
+ elseif self.db.showFriendlyCombat == "TOGGLE_OFF" then
+ SetCVar("nameplateShowFriends", 0)
+ end
+
+ if self.db.showEnemyCombat == "TOGGLE_ON" then
+ SetCVar("nameplateShowEnemies", 1)
+ elseif self.db.showEnemyCombat == "TOGGLE_OFF" then
+ SetCVar("nameplateShowEnemies", 0)
+ end
+
+ NP:ForEachVisiblePlate("StyleFilterUpdate", "PLAYER_REGEN_DISABLED")
+end
+
+function NP:PLAYER_REGEN_ENABLED()
+ if next(self.ResizeQueue) then
+ for frame in pairs(self.ResizeQueue) do
+ self:SetSize(frame)
+ end
+ end
+
+ if self.db.showFriendlyCombat == "TOGGLE_ON" then
+ SetCVar("nameplateShowFriends", 0)
+ elseif self.db.showFriendlyCombat == "TOGGLE_OFF" then
+ SetCVar("nameplateShowFriends", 1)
+ end
+
+ if self.db.showEnemyCombat == "TOGGLE_ON" then
+ SetCVar("nameplateShowEnemies", 0)
+ elseif self.db.showEnemyCombat == "TOGGLE_OFF" then
+ SetCVar("nameplateShowEnemies", 1)
+ end
+
+ NP:ForEachVisiblePlate("StyleFilterUpdate", "PLAYER_REGEN_ENABLED")
+end
+
+function NP:SPELL_UPDATE_COOLDOWN(...)
+ NP:ForEachVisiblePlate("StyleFilterUpdate", "SPELL_UPDATE_COOLDOWN")
+end
+
+function NP:RAID_TARGET_UPDATE()
+ for frame in pairs(self.VisiblePlates) do
+ NP:CheckRaidIcon(frame)
+ NP:StyleFilterUpdate(frame, "RAID_TARGET_UPDATE")
+ end
+end
+
+function NP:CacheArenaUnits()
+ twipe(self.ENEMY_PLAYER)
+ twipe(self.ENEMY_NPC)
+
+ for i = 1, 5 do
+ if UnitExists("arena"..i) then
+ local unit = format("arena%d", i)
+ self.ENEMY_PLAYER[UnitName(unit)] = unit
+ end
+ if UnitExists("arenapet"..i) then
+ local unit = format("arenapet%d", i)
+ self.ENEMY_NPC[UnitName(unit)] = unit
+ end
+ end
+end
+
+function NP:CacheGroupUnits()
+ twipe(self.FRIENDLY_PLAYER)
+
+ if GetNumRaidMembers() > 0 then
+ for i = 1, 40 do
+ if UnitExists("raid"..i) then
+ local unit = format("raid%d", i)
+ self.FRIENDLY_PLAYER[UnitName(unit)] = unit
+ end
+ end
+ elseif GetNumPartyMembers() > 0 then
+ for i = 1, 5 do
+ if UnitExists("party"..i) then
+ local unit = format("party%d", i)
+ self.FRIENDLY_PLAYER[UnitName(unit)] = unit
+ end
+ end
+ end
+end
+
+function NP:CacheGroupPetUnits()
+ twipe(self.FRIENDLY_NPC)
+ twipe(self.ENEMY_NPC)
+
+ for i = 1, 5 do
+ if UnitExists("arenapet"..i) then
+ local unit = format("arenapet%d", i)
+ self.ENEMY_NPC[UnitName(unit)] = unit
+ end
+ end
+ if GetNumRaidMembers() > 0 then
+ for i = 1, 40 do
+ if UnitExists("raidpet"..i) then
+ local unit = format("raidpet%d", i)
+ self.FRIENDLY_NPC[UnitName(unit)] = unit
+ end
+ end
+ elseif GetNumPartyMembers() > 0 then
+ for i = 1, 5 do
+ if UnitExists("partypet"..i) then
+ local unit = format("partypet%d", i)
+ self.FRIENDLY_NPC[UnitName(unit)] = unit
+ end
+ end
+ end
+end
+
+function NP:TogleTestFrame(unitType)
+ local unitFrame = ElvNP_Test.UnitFrame
+ if not ElvNP_Test:IsShown() or unitFrame.UnitType ~= unitType then
+ if unitType == "ENEMY_NPC" then
+ unitFrame.oldHealthBar:SetStatusBarColor(1, 0, 0)
+ elseif unitType == "FRIENDLY_NPC" then
+ unitFrame.oldHealthBar:SetStatusBarColor(0, 1, 0)
+ elseif unitType == "FRIENDLY_PLAYER" then
+ unitFrame.oldHealthBar:SetStatusBarColor(0, 0, 1)
+ else
+ local color = E.media.herocolor
+ unitFrame.oldHealthBar:SetStatusBarColor(color.r, color.g, color.b)
+ end
+
+ local maxHealth = UnitHealthMax("player")
+ unitFrame.oldHealthBar:SetMinMaxValues(0, maxHealth)
+ unitFrame.oldHealthBar:SetValue(random(1, maxHealth))
+
+ unitFrame.oldName:SetText(L[unitType])
+ unitFrame.oldLevel:SetText(E.mylevel)
+ unitFrame.Buffs.forceShow = true
+ unitFrame.Debuffs.forceShow = true
+ unitFrame.RaidIcon:SetTexture([[Interface\TargetingFrame\UI-RaidTargetingIcons]])
+ SetRaidTargetIconTexture(unitFrame.RaidIcon, random(1, 8))
+ unitFrame.RaidIcon:Show()
+
+ if not ElvNP_Test:IsShown() then
+ ElvNP_Test:Show()
+ end
+
+ self:UpdateAllFrame(unitFrame, true, true)
+ else
+ ElvNP_Test:Hide()
+ end
+end
+
+function NP:Initialize()
+ self.db = E.db.nameplates
+
+ if E.private.nameplates.enable ~= true then return end
+ self.Initialized = true
+
+ --Add metatable to all our StyleFilters so they can grab default values if missing
+ self:StyleFilterInitialize()
+
+ --Populate `NP.StyleFilterEvents` with events Style Filters will be using and sort the filters based on priority.
+ self:StyleFilterConfigure()
+
+ self.levelStep = 2
+
+ self:UpdateCVars()
+
+ local ElvNP_Test = CreateFrame("Button", "ElvNP_Test")
+ ElvNP_Test:Point("BOTTOM", UIParent, "BOTTOM", 0, 250)
+ ElvNP_Test:SetMovable(true)
+ ElvNP_Test:RegisterForDrag("LeftButton", "RightButton")
+ ElvNP_Test:SetScript("OnDragStart", function() ElvNP_Test:StartMoving() end)
+ ElvNP_Test:SetScript("OnDragStop", function() ElvNP_Test:StopMovingOrSizing() end)
+
+ CreateFrame("StatusBar", nil, ElvNP_Test)
+ CreateFrame("StatusBar", nil, ElvNP_Test)
+
+ for i = 1, 11 do
+ if i == 7 or i == 8 then
+ ElvNP_Test:CreateFontString(nil, "OVERLAY", "GameFontNormal"):SetText("Empty")
+ else
+ ElvNP_Test:CreateTexture():Hide()
+ end
+ end
+
+ self:StyleFrame(ElvNP_Test, true)
+ self:OnCreated(ElvNP_Test)
+ ElvNP_Test:Hide()
+
+ self.Frame = CreateFrame("Frame"):SetScript("OnUpdate", self.OnUpdate)
+
+ self:RegisterEvent("PLAYER_ENTERING_WORLD")
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ self:RegisterEvent("PLAYER_REGEN_DISABLED")
+ self:RegisterEvent("PLAYER_LOGOUT", self.StyleFilterClearDefaults)
+ self:RegisterEvent("PLAYER_TARGET_CHANGED")
+ self:RegisterEvent("SPELL_UPDATE_COOLDOWN")
+ self:RegisterEvent("RAID_TARGET_UPDATE")
+
+ self:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
+ -- Arena & Arena Pets
+ self:CacheArenaUnits()
+ self:RegisterEvent("ARENA_OPPONENT_UPDATE", "CacheArenaUnits")
+ -- Group
+ self:CacheGroupUnits()
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED", "CacheGroupUnits")
+ self:RegisterEvent("RAID_ROSTER_UPDATE", "CacheGroupUnits")
+ -- Group Pets
+ self:CacheGroupPetUnits()
+ self:RegisterEvent("UNIT_NAME_UPDATE", "CacheGroupPetUnits")
+
+ LAI.UnregisterAllCallbacks(self)
+ LAI.RegisterCallback(self, "LibAuraInfo_AURA_APPLIED")
+ LAI.RegisterCallback(self, "LibAuraInfo_AURA_REMOVED")
+ LAI.RegisterCallback(self, "LibAuraInfo_AURA_REFRESH")
+ LAI.RegisterCallback(self, "LibAuraInfo_AURA_APPLIED_DOSE")
+ LAI.RegisterCallback(self, "LibAuraInfo_AURA_CLEAR")
+ LAI.RegisterCallback(self, "LibAuraInfo_UNIT_AURA")
+ self:RegisterEvent("UNIT_COMBO_POINTS")
+end
+
+local function InitializeCallback()
+ NP:Initialize()
+end
+
+E:RegisterModule(NP:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Nameplates/StyleFilter.lua b/ElvUI/Modules/Nameplates/StyleFilter.lua
new file mode 100644
index 0000000..ddd0f67
--- /dev/null
+++ b/ElvUI/Modules/Nameplates/StyleFilter.lua
@@ -0,0 +1,883 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local mod = E:GetModule("NamePlates")
+local LSM = E.Libs.LSM
+
+--Lua functions
+local ipairs, next, pairs, rawget, rawset, select, setmetatable, tonumber, type, unpack, tostring = ipairs, next, pairs, rawget, rawset, select, setmetatable, tonumber, type, unpack, tostring
+local tinsert, sort, twipe = table.insert, table.sort, table.wipe
+local match = string.match
+--WoW API / Variables
+local GetInstanceInfo = GetInstanceInfo
+local GetSpellCooldown = GetSpellCooldown
+local GetSpellInfo = GetSpellInfo
+local GetTime = GetTime
+local UnitAffectingCombat = UnitAffectingCombat
+local UnitHealth = UnitHealth
+local UnitHealthMax = UnitHealthMax
+local UnitPower = UnitPower
+local UnitPowerMax = UnitPowerMax
+
+mod.TriggerConditions = {
+ raidTargets = {
+ STAR = "star",
+ CIRCLE = "circle",
+ DIAMOND = "diamond",
+ TRIANGLE = "triangle",
+ MOON = "moon",
+ SQUARE = "square",
+ CROSS = "cross",
+ SKULL = "skull",
+ },
+ frameTypes = {
+ ["FRIENDLY_PLAYER"] = "friendlyPlayer",
+ ["FRIENDLY_NPC"] = "friendlyNPC",
+ ["ENEMY_PLAYER"] = "enemyPlayer",
+ ["ENEMY_NPC"] = "enemyNPC",
+ },
+ roles = {
+ ["TANK"] = "tank",
+ ["HEALER"] = "healer",
+ ["DAMAGER"] = "damager"
+ },
+ difficulties = {
+ -- dungeons
+ [1] = "normal",
+ [2] = "heroic",
+ -- raids
+ [14] = "normal",
+ [15] = "heroic",
+ },
+ totems = {},
+ uniqueUnits = {}
+}
+
+local totemTypes = {
+ air = { -- Air Totems
+ [8177] = "a1", -- Grounding Totem
+ [10595] = "a2", -- Nature Resistance Totem I
+ [10600] = "a2", -- Nature Resistance Totem II
+ [10601] = "a2", -- Nature Resistance Totem III
+ [25574] = "a2", -- Nature Resistance Totem IV
+ [58746] = "a2", -- Nature Resistance Totem V
+ [58749] = "a2", -- Nature Resistance Totem VI
+ [6495] = "a3", -- Sentry Totem
+ [8512] = "a4", -- Windfury Totem
+ [3738] = "a5", -- Wrath of Air Totem
+ },
+ earth = { -- Earth Totems
+ [2062] = "e1", -- Earth Elemental Totem
+ [2484] = "e2", -- Earthbind Totem
+ [5730] = "e3", -- Stoneclaw Totem I
+ [6390] = "e3", -- Stoneclaw Totem II
+ [6391] = "e3", -- Stoneclaw Totem III
+ [6392] = "e3", -- Stoneclaw Totem IV
+ [10427] = "e3", -- Stoneclaw Totem V
+ [10428] = "e3", -- Stoneclaw Totem VI
+ [25525] = "e3", -- Stoneclaw Totem VII
+ [58580] = "e3", -- Stoneclaw Totem VIII
+ [58581] = "e3", -- Stoneclaw Totem IX
+ [58582] = "e3", -- Stoneclaw Totem X
+ [8071] = "e4", -- Stoneskin Totem I -- Faction Champs
+ [8154] = "e4", -- Stoneskin Totem II
+ [8155] = "e4", -- Stoneskin Totem III
+ [10406] = "e4", -- Stoneskin Totem IV
+ [10407] = "e4", -- Stoneskin Totem V
+ [10408] = "e4", -- Stoneskin Totem VI
+ [25508] = "e4", -- Stoneskin Totem VII
+ [25509] = "e4", -- Stoneskin Totem VIII
+ [58751] = "e4", -- Stoneskin Totem IX
+ [58753] = "e4", -- Stoneskin Totem X
+ [8075] = "e5", -- Strength of Earth Totem I -- Faction Champs
+ [8160] = "e5", -- Strength of Earth Totem II
+ [8161] = "e5", -- Strength of Earth Totem III
+ [10442] = "e5", -- Strength of Earth Totem IV
+ [25361] = "e5", -- Strength of Earth Totem V
+ [25528] = "e5", -- Strength of Earth Totem VI
+ [57622] = "e5", -- Strength of Earth Totem VII
+ [58643] = "e5", -- Strength of Earth Totem VIII
+ [8143] = "e6", -- Tremor Totem
+ },
+ fire = { -- Fire Totems
+ [2894] = "f1", -- Fire Elemental Totem
+ [8227] = "f2", -- Flametongue Totem I -- Faction Champs
+ [8249] = "f2", -- Flametongue Totem II
+ [10526] = "f2", -- Flametongue Totem III
+ [16387] = "f2", -- Flametongue Totem IV
+ [25557] = "f2", -- Flametongue Totem V
+ [58649] = "f2", -- Flametongue Totem VI
+ [58652] = "f2", -- Flametongue Totem VII
+ [58656] = "f2", -- Flametongue Totem VIII
+ [8181] = "f3", -- Frost Resistance Totem I
+ [10478] = "f3", -- Frost Resistance Totem II
+ [10479] = "f3", -- Frost Resistance Totem III
+ [25560] = "f3", -- Frost Resistance Totem IV
+ [58741] = "f3", -- Frost Resistance Totem V
+ [58745] = "f3", -- Frost Resistance Totem VI
+ [8190] = "f4", -- Magma Totem I
+ [10585] = "f4", -- Magma Totem II
+ [10586] = "f4", -- Magma Totem III
+ [10587] = "f4", -- Magma Totem IV
+ [25552] = "f4", -- Magma Totem V
+ [58731] = "f4", -- Magma Totem VI
+ [58734] = "f4", -- Magma Totem VII
+ [3599] = "f5", -- Searing Totem I -- Faction Champs
+ [6363] = "f5", -- Searing Totem II
+ [6364] = "f5", -- Searing Totem III
+ [6365] = "f5", -- Searing Totem IV
+ [10437] = "f5", -- Searing Totem V
+ [10438] = "f5", -- Searing Totem VI
+ [25533] = "f5", -- Searing Totem VII
+ [58699] = "f5", -- Searing Totem VIII
+ [58703] = "f5", -- Searing Totem IX
+ [58704] = "f5", -- Searing Totem X
+ [30706] = "f6", -- Totem of Wrath I
+ [57720] = "f6", -- Totem of Wrath II
+ [57721] = "f6", -- Totem of Wrath III
+ [57722] = "f6", -- Totem of Wrath IV
+ },
+ water = { -- Water Totems
+ [8170] = "w1", -- Cleansing Totem
+ [8184] = "w2", -- Fire Resistance Totem I
+ [10537] = "w2", -- Fire Resistance Totem II
+ [10538] = "w2", -- Fire Resistance Totem III
+ [25563] = "w2", -- Fire Resistance Totem IV
+ [58737] = "w2", -- Fire Resistance Totem V
+ [58739] = "w2", -- Fire Resistance Totem VI
+ [5394] = "w3", -- Healing Stream Totem I -- Faction Champs
+ [6375] = "w3", -- Healing Stream Totem II
+ [6377] = "w3", -- Healing Stream Totem III
+ [10462] = "w3", -- Healing Stream Totem IV
+ [10463] = "w3", -- Healing Stream Totem V
+ [25567] = "w3", -- Healing Stream Totem VI
+ [58755] = "w3", -- Healing Stream Totem VII
+ [58756] = "w3", -- Healing Stream Totem VIII
+ [58757] = "w3", -- Healing Stream Totem IX
+ [5675] = "w4", -- Mana Spring Totem I
+ [10495] = "w4", -- Mana Spring Totem II
+ [10496] = "w4", -- Mana Spring Totem III
+ [10497] = "w4", -- Mana Spring Totem IV
+ [25570] = "w4", -- Mana Spring Totem V
+ [58771] = "w4", -- Mana Spring Totem VI
+ [58773] = "w4", -- Mana Spring Totem VII
+ [58774] = "w4", -- Mana Spring Totem VIII
+ [16190] = "w5" -- Mana Tide Totem
+ },
+ other = {
+ [724] = "o1" -- Lightwell
+ }
+}
+
+local totemRanks = {
+ "",
+ " II",
+ " III",
+ " IV",
+ " V",
+ " VI",
+ " VII",
+ " VIII",
+ " IX",
+ " X"
+}
+
+local uniqueUnitTypes = {
+ pvp = {
+ [34433] = "u1", -- Shadow Fiend
+ },
+ pve = {
+ [72052] = "u2", -- Kinetic Bomb
+ }
+}
+
+G.nameplates.uniqueUnitTypes = uniqueUnitTypes
+
+for unitType, units in pairs(uniqueUnitTypes) do
+ for spellID, unit in pairs(units) do
+ local name, _, texture = GetSpellInfo(spellID)
+ mod.TriggerConditions.uniqueUnits[unit] = {name, unitType, texture}
+ mod.UniqueUnits[name] = unit
+ end
+end
+
+for totemSchool, totems in pairs(totemTypes) do
+ for spellID, totemID in pairs(totems) do
+ local totemName, rank, texture = GetSpellInfo(spellID)
+
+ if not mod.TriggerConditions.totems[totemID] then
+ mod.TriggerConditions.totems[totemID] = {totemName, totemSchool, texture}
+ end
+
+ rank = totemRanks[tonumber(match(rank, ("%d+")))]
+
+ if rank then
+ totemName = totemName..rank
+ else
+ totemName = totemName
+ end
+
+ mod.Totems[totemName] = totemID
+ end
+end
+
+G.nameplates.totemTypes = totemTypes
+
+function mod:StyleFilterAuraCheck(names, icons, mustHaveAll, missing, minTimeLeft, maxTimeLeft)
+ local total, count = 0, 0
+ for name, value in pairs(names) do
+ if value == true then --only if they are turned on
+ total = total + 1 --keep track of the names
+ end
+ for _, icon in ipairs(icons) do
+ if icon:IsShown() and (value == true) and ((icon.name and icon.name == name) or (icon.spellID and icon.spellID == tonumber(name)))
+ and (not minTimeLeft or (minTimeLeft == 0 or (icon.expirationTime and (icon.expirationTime - GetTime()) > minTimeLeft))) and (not maxTimeLeft or (maxTimeLeft == 0 or (icon.expirationTime and (icon.expirationTime - GetTime()) < maxTimeLeft))) then
+ count = count + 1 --keep track of how many matches we have
+ end
+ end
+ end
+
+ if total == 0 then
+ return nil --If no auras are checked just pass nil, we dont need to run the filter here.
+ else
+ return ((mustHaveAll and not missing) and total == count) -- [x] Check for all [ ] Missing: total needs to match count
+ or ((not mustHaveAll and not missing) and count > 0) -- [ ] Check for all [ ] Missing: count needs to be greater than zero
+ or ((not mustHaveAll and missing) and count == 0) -- [ ] Check for all [x] Missing: count needs to be zero
+ or ((mustHaveAll and missing) and total ~= count) -- [x] Check for all [x] Missing: count must not match total
+ end
+end
+
+function mod:StyleFilterCooldownCheck(names, mustHaveAll)
+ local total, count = 0, 0
+ local _, gcd = GetSpellCooldown(61304)
+
+ for name, value in pairs(names) do
+ if value == "ONCD" or value == "OFFCD" then --only if they are turned on
+ total = total + 1 --keep track of the names
+
+ local _, duration = GetSpellCooldown(name)
+ if (duration > gcd and value == "ONCD")
+ or (duration <= gcd and value == "OFFCD") then
+ count = count + 1
+ --print(((duration > gcd and value == "ONCD") and name.."passes because it is on cd.") or ((duration <= gcd and value == "OFFCD") and name.." passes because it is off cd."))
+ end
+ end
+ end
+
+ if total == 0 then
+ return nil
+ else
+ return (mustHaveAll and total == count) or (not mustHaveAll and count > 0)
+ end
+end
+
+function mod:StyleFilterSetChanges(frame, actions, HealthColorChanged, BorderChanged, FlashingHealth, TextureChanged, ScaleChanged, FrameLevelChanged, AlphaChanged, NameColorChanged, NameOnlyChanged, VisibilityChanged, IconChanged, IconOnlyChanged)
+ if VisibilityChanged then
+ frame.StyleChanged = true
+ frame.VisibilityChanged = true
+ frame:Hide()
+ return --We hide it. Lets not do other things (no point)
+ end
+ if FrameLevelChanged then
+ frame.StyleChanged = true
+ frame.FrameLevelChanged = actions.frameLevel -- we pass this to `ResetNameplateFrameLevel`
+ end
+ if HealthColorChanged then
+ frame.StyleChanged = true
+ frame.HealthColorChanged = true
+ frame.Health:SetStatusBarColor(actions.color.healthColor.r, actions.color.healthColor.g, actions.color.healthColor.b, actions.color.healthColor.a)
+ frame.CutawayHealth:SetStatusBarColor(actions.color.healthColor.r * 1.5, actions.color.healthColor.g * 1.5, actions.color.healthColor.b * 1.5, actions.color.healthColor.a)
+ end
+ if BorderChanged then --Lets lock this to the values we want (needed for when the media border color changes)
+ frame.StyleChanged = true
+ frame.BorderChanged = true
+ frame.Health.bordertop:SetTexture(actions.color.borderColor.r, actions.color.borderColor.g, actions.color.borderColor.b, actions.color.borderColor.a)
+ frame.Health.borderbottom:SetTexture(actions.color.borderColor.r, actions.color.borderColor.g, actions.color.borderColor.b, actions.color.borderColor.a)
+ frame.Health.borderleft:SetTexture(actions.color.borderColor.r, actions.color.borderColor.g, actions.color.borderColor.b, actions.color.borderColor.a)
+ frame.Health.borderright:SetTexture(actions.color.borderColor.r, actions.color.borderColor.g, actions.color.borderColor.b, actions.color.borderColor.a)
+ end
+ if FlashingHealth then
+ frame.StyleChanged = true
+ frame.FlashingHealth = true
+ if not TextureChanged then
+ frame.FlashTexture:SetTexture(LSM:Fetch("statusbar", mod.db.statusbar))
+ end
+ frame.FlashTexture:SetVertexColor(actions.flash.color.r, actions.flash.color.g, actions.flash.color.b)
+ frame.FlashTexture:SetAlpha(actions.flash.color.a)
+ frame.FlashTexture:Show()
+ E:Flash(frame.FlashTexture, actions.flash.speed * 0.1, true)
+ end
+ if TextureChanged then
+ frame.StyleChanged = true
+ frame.TextureChanged = true
+ local tex = LSM:Fetch("statusbar", actions.texture.texture)
+ frame.Health.Highlight:SetTexture(tex)
+ frame.Health:SetStatusBarTexture(tex)
+ if FlashingHealth then
+ frame.FlashTexture:SetTexture(tex)
+ end
+ end
+ if ScaleChanged then
+ frame.StyleChanged = true
+ frame.ScaleChanged = true
+ local scale = (frame.ThreatScale or 1)
+ frame.ActionScale = actions.scale
+ if frame.isTarget and mod.db.useTargetScale then
+ scale = scale * mod.db.targetScale
+ end
+ mod:SetFrameScale(frame, scale * actions.scale)
+ end
+ if AlphaChanged then
+ frame.StyleChanged = true
+ frame.AlphaChanged = true
+ mod:PlateFade(frame, mod.db.fadeIn and 1 or 0, frame:GetAlpha(), actions.alpha / 100)
+ end
+ if NameColorChanged then
+ frame.StyleChanged = true
+ frame.NameColorChanged = true
+ local nameText = frame.oldName:GetText()
+ if nameText and nameText ~= "" then
+ frame.Name:SetTextColor(actions.color.nameColor.r, actions.color.nameColor.g, actions.color.nameColor.b, actions.color.nameColor.a)
+ if mod.db.nameColoredGlow then
+ frame.Name.NameOnlyGlow:SetVertexColor(actions.color.nameColor.r - 0.1, actions.color.nameColor.g - 0.1, actions.color.nameColor.b - 0.1, 1)
+ end
+ end
+ end
+ if NameOnlyChanged then
+ frame.StyleChanged = true
+ frame.NameOnlyChanged = true
+ --hide the bars
+ if frame.CastBar:IsShown() then frame.CastBar:Hide() end
+ if frame.Health:IsShown() then frame.Health:Hide() end
+ --hide the target indicator
+ mod:Configure_Glow(frame)
+ mod:Update_Glow(frame)
+ --position the name and update its color
+ frame.Name:ClearAllPoints()
+ frame.Name:SetJustifyH("CENTER")
+ frame.Name:SetPoint("TOP", frame)
+ frame.Level:ClearAllPoints()
+ frame.Level:SetPoint("LEFT", frame.Name, "RIGHT")
+ frame.Level:SetJustifyH("LEFT")
+ if not NameColorChanged then
+ mod:Update_Name(frame, true)
+ end
+ end
+ if IconChanged then
+ frame.StyleChanged = true
+ frame.IconChanged = true
+ mod:Configure_IconFrame(frame)
+ mod:Update_IconFrame(frame)
+ end
+ if IconOnlyChanged then
+ frame.StyleChanged = true
+ frame.IconOnlyChanged = true
+ mod:Update_IconFrame(frame, true)
+ if frame.Health:IsShown() then frame.Health:Hide() end
+ frame.Level:Hide()
+ frame.Name:Hide()
+ mod:Configure_Glow(frame)
+ mod:Update_Glow(frame)
+ mod:Update_RaidIcon(frame)
+ mod:Configure_IconOnlyGlow(frame)
+ mod:Configure_NameOnlyGlow(frame)
+ end
+end
+
+function mod:StyleFilterClearChanges(frame, HealthColorChanged, BorderChanged, FlashingHealth, TextureChanged, ScaleChanged, FrameLevelChanged, AlphaChanged, NameColorChanged, NameOnlyChanged, VisibilityChanged, IconChanged, IconOnlyChanged)
+ frame.StyleChanged = nil
+ if VisibilityChanged then
+ frame.VisibilityChanged = nil
+ mod:PlateFade(frame, mod.db.fadeIn and 1 or 0, 0, 1) -- fade those back in so it looks clean
+ frame:Show()
+ end
+ if FrameLevelChanged then
+ frame.FrameLevelChanged = nil
+ end
+ if HealthColorChanged then
+ frame.HealthColorChanged = nil
+ frame.Health:SetStatusBarColor(frame.Health.r, frame.Health.g, frame.Health.b)
+ frame.CutawayHealth:SetStatusBarColor(frame.Health.r * 1.5, frame.Health.g * 1.5, frame.Health.b * 1.5, 1)
+ end
+ if BorderChanged then
+ frame.BorderChanged = nil
+ local r, g, b = unpack(E.media.bordercolor)
+ frame.Health.bordertop:SetTexture(r, g, b)
+ frame.Health.borderbottom:SetTexture(r, g, b)
+ frame.Health.borderleft:SetTexture(r, g, b)
+ frame.Health.borderright:SetTexture(r, g, b)
+ end
+ if FlashingHealth then
+ frame.FlashingHealth = nil
+ E:StopFlash(frame.FlashTexture)
+ frame.FlashTexture:Hide()
+ end
+ if TextureChanged then
+ frame.TextureChanged = nil
+ local tex = LSM:Fetch("statusbar", mod.db.statusbar)
+ frame.Health.Highlight:SetTexture(tex)
+ frame.Health:SetStatusBarTexture(tex)
+ end
+ if ScaleChanged then
+ frame.ScaleChanged = nil
+ frame.ActionScale = nil
+ local scale = frame.ThreatScale or 1
+ if frame.isTarget and mod.db.useTargetScale then
+ scale = scale * mod.db.targetScale
+ end
+ mod:SetFrameScale(frame, scale)
+ end
+ if AlphaChanged then
+ frame.AlphaChanged = nil
+ mod:PlateFade(frame, mod.db.fadeIn and 1 or 0, (frame.FadeObject and frame.FadeObject.endAlpha) or 0.5, 1)
+ end
+ if NameColorChanged then
+ frame.NameColorChanged = nil
+ frame.Name:SetTextColor(frame.Name.r, frame.Name.g, frame.Name.b)
+ end
+ if NameOnlyChanged then
+ frame.NameOnlyChanged = nil
+ frame.TopLevelFrame = nil --We can safely clear this here because it is set upon `UpdateElement_Auras` if needed
+ if mod.db.units[frame.UnitType].health.enable or (frame.isTarget and mod.db.alwaysShowTargetHealth) then
+ frame.Health:Show()
+ mod:Configure_Glow(frame)
+ mod:Update_Glow(frame)
+ end
+ if mod.db.units[frame.UnitType].name.enable then
+ frame.Level:Show()
+ frame.Name:ClearAllPoints()
+ frame.Level:ClearAllPoints()
+ mod:Update_Level(frame)
+ mod:Update_Name(frame)
+ else
+ frame.Name:SetText()
+ end
+ end
+ if IconChanged then
+ frame.IconChanged = nil
+ frame.IconFrame:Hide()
+ end
+ if IconOnlyChanged then
+ frame.IconOnlyChanged = nil
+ mod:Update_IconFrame(frame)
+ if mod.db.units[frame.UnitType].iconFrame and mod.db.units[frame.UnitType].iconFrame.enable then
+ mod:Configure_IconFrame(frame)
+ end
+ if mod.db.units[frame.UnitType].health.enable or (frame.isTarget and mod.db.alwaysShowTargetHealth) then
+ frame.Health:Show()
+ mod:Configure_Glow(frame)
+ mod:Update_Glow(frame)
+ end
+ if mod.db.units[frame.UnitType].name.enable then
+ frame.Name:Show()
+ frame.Level:Show()
+ frame.Name:ClearAllPoints()
+ frame.Level:ClearAllPoints()
+ mod:Update_Level(frame)
+ mod:Update_Name(frame)
+ else
+ frame.Name:SetText()
+ end
+ mod:Update_RaidIcon(frame)
+ mod:Configure_IconOnlyGlow(frame)
+ mod:Configure_NameOnlyGlow(frame)
+ end
+end
+
+function mod:StyleFilterConditionCheck(frame, filter, trigger)
+ local passed -- skip StyleFilterPass when triggers are empty
+
+ -- Name
+ if trigger.names and next(trigger.names) then
+ for _, value in pairs(trigger.names) do
+ if value then -- only run if at least one is selected
+ local name = trigger.names[frame.UnitName]
+ if (not trigger.negativeMatch and name) or (trigger.negativeMatch and not name) then passed = true else return end
+ break -- we can execute this once on the first enabled option then kill the loop
+ end
+ end
+ end
+
+ -- Health
+ if trigger.healthThreshold then
+ local health = (trigger.healthUsePlayer and UnitHealth("player")) or frame.oldHealthBar:GetValue() or 0
+ local maxHealth = (trigger.healthUsePlayer and UnitHealthMax("player")) or select(2, frame.oldHealthBar:GetMinMaxValues()) or 0
+ local percHealth = (maxHealth and (maxHealth > 0) and health/maxHealth) or 0
+ local underHealthThreshold = trigger.underHealthThreshold and (trigger.underHealthThreshold ~= 0) and (trigger.underHealthThreshold > percHealth)
+ local overHealthThreshold = trigger.overHealthThreshold and (trigger.overHealthThreshold ~= 0) and (trigger.overHealthThreshold < percHealth)
+ if underHealthThreshold or overHealthThreshold then passed = true else return end
+ end
+
+ -- Power
+ if trigger.powerThreshold then
+ local power, maxPower = UnitPower("player"), UnitPowerMax("player")
+ local percPower = (maxPower and (maxPower > 0) and power/maxPower) or 0
+ local underPowerThreshold = trigger.underPowerThreshold and (trigger.underPowerThreshold ~= 0) and (trigger.underPowerThreshold > percPower)
+ local overPowerThreshold = trigger.overPowerThreshold and (trigger.overPowerThreshold ~= 0) and (trigger.overPowerThreshold < percPower)
+ if underPowerThreshold or overPowerThreshold then passed = true else return end
+ end
+
+ -- Require Target
+ if trigger.requireTarget then
+ if UnitExists("target") then passed = true else return end
+ end
+
+ -- Player Combat
+ if trigger.inCombat or trigger.outOfCombat then
+ local inCombat = UnitAffectingCombat("player")
+ if (trigger.inCombat and inCombat) or (trigger.outOfCombat and not inCombat) then passed = true else return end
+ end
+
+ -- Player Target
+ if trigger.isTarget or trigger.notTarget then
+ if (trigger.isTarget and frame.isTarget) or (trigger.notTarget and not frame.isTarget) then passed = true else return end
+ end
+
+ -- Group Role
+ if trigger.role.tank or trigger.role.healer or trigger.role.damager then
+ if trigger.role[mod.TriggerConditions.roles[E:GetPlayerRole()]] then passed = true else return end
+ end
+
+ -- Instance Type
+ if trigger.instanceType.none or trigger.instanceType.party or trigger.instanceType.raid or trigger.instanceType.arena or trigger.instanceType.pvp then
+ local _, instanceType, difficultyID = GetInstanceInfo()
+ if trigger.instanceType[instanceType] then
+ passed = true
+
+ -- Instance Difficulty
+ if instanceType == "raid" or instanceType == "party" then
+ local D = trigger.instanceDifficulty[(instanceType == "party" and "dungeon") or instanceType]
+ for _, value in pairs(D) do
+ if value and not D[mod.TriggerConditions.difficulties[difficultyID]] then return end
+ end
+ end
+ else return end
+ elseif trigger.instanceType.sanctuary then
+ if UnitIsPVPSanctuary("player") then passed = true else return end
+ end
+
+ -- Level
+ if trigger.level then
+ local myLevel = E.mylevel
+ local level = mod:UnitLevel(frame)
+ level = level == "??" and -1 or tonumber(level)
+ local curLevel = (trigger.curlevel and trigger.curlevel ~= 0 and (trigger.curlevel == level))
+ local minLevel = (trigger.minlevel and trigger.minlevel ~= 0 and (trigger.minlevel <= level))
+ local maxLevel = (trigger.maxlevel and trigger.maxlevel ~= 0 and (trigger.maxlevel >= level))
+ local matchMyLevel = trigger.mylevel and (level == myLevel)
+ if curLevel or minLevel or maxLevel or matchMyLevel then passed = true else return end
+ end
+
+ -- Unit Type
+ if trigger.nameplateType and trigger.nameplateType.enable then
+ if trigger.nameplateType[mod.TriggerConditions.frameTypes[frame.UnitType]] then passed = true else return end
+ end
+
+ -- Reaction Type
+ if trigger.reactionType and trigger.reactionType.enable then
+ local reaction = frame.UnitReaction
+ if ((reaction == 1 or reaction == 2 or reaction == 3) and trigger.reactionType.hostile) or (reaction == 4 and trigger.reactionType.neutral) or (reaction == 5 and trigger.reactionType.friendly) then passed = true else return end
+ end
+
+ -- Raid Target
+ if trigger.raidTarget.star or trigger.raidTarget.circle or trigger.raidTarget.diamond or trigger.raidTarget.triangle or trigger.raidTarget.moon or trigger.raidTarget.square or trigger.raidTarget.cross or trigger.raidTarget.skull then
+ if trigger.raidTarget[mod.TriggerConditions.raidTargets[frame.RaidIconType]] then passed = true else return end
+ end
+
+ -- Casting
+ if trigger.casting then
+ local b, c = frame.CastBar, trigger.casting
+
+ -- Spell
+ if b.spellName then
+ if c.spells and next(c.spells) then
+ for _, value in pairs(c.spells) do
+ if value then -- only run if at least one is selected
+ local _, _, _, _, _, _, spellID = GetSpellInfo(b.spellName)
+ local castingSpell = (spellID and c.spells[tostring(spellID)]) or c.spells[b.spellName]
+ if (c.notSpell and not castingSpell) or (castingSpell and not c.notSpell) then passed = true else return end
+ break -- we can execute this once on the first enabled option then kill the loop
+ end
+ end
+ end
+ end
+
+ -- Status
+ if c.isCasting or c.isChanneling or c.notCasting or c.notChanneling then
+ if (c.isCasting and b.casting) or (c.isChanneling and b.channeling)
+ or (c.notCasting and not b.casting) or (c.notChanneling and not b.channeling) then passed = true else return end
+ end
+
+ -- Interruptible
+ if c.interruptible or c.notInterruptible then
+ if (b.casting or b.channeling) and ((c.interruptible and not b.notInterruptible)
+ or (c.notInterruptible and b.notInterruptible)) then passed = true else return end
+ end
+ end
+
+ -- Cooldown
+ if trigger.cooldowns and trigger.cooldowns.names and next(trigger.cooldowns.names) then
+ local cooldown = mod:StyleFilterCooldownCheck(trigger.cooldowns.names, trigger.cooldowns.mustHaveAll)
+ if cooldown ~= nil then -- ignore if none are set to ONCD or OFFCD
+ if cooldown then passed = true else return end
+ end
+ end
+
+ -- Buffs
+ if frame.Buffs and trigger.buffs and trigger.buffs.names and next(trigger.buffs.names) then
+ local buff = mod:StyleFilterAuraCheck(trigger.buffs.names, frame.Buffs, trigger.buffs.mustHaveAll, trigger.buffs.missing, trigger.buffs.minTimeLeft, trigger.buffs.maxTimeLeft)
+ if buff ~= nil then -- ignore if none are selected
+ if buff then passed = true else return end
+ end
+ end
+
+ -- Debuffs
+ if frame.Debuffs and trigger.debuffs and trigger.debuffs.names and next(trigger.debuffs.names) then
+ local debuff = mod:StyleFilterAuraCheck(trigger.debuffs.names, frame.Debuffs, trigger.debuffs.mustHaveAll, trigger.debuffs.missing, trigger.debuffs.minTimeLeft, trigger.debuffs.maxTimeLeft)
+ if debuff ~= nil then -- ignore if none are selected
+ if debuff then passed = true else return end
+ end
+ end
+
+ -- Totems
+ if frame.UnitName and trigger.totems.enable then
+ local totem = mod.Totems[frame.UnitName]
+ if totem then if trigger.totems[totem] then passed = true else return end end
+ end
+
+ -- Unique Units
+ if frame.UnitName and trigger.uniqueUnits.enable then
+ local unit = mod.UniqueUnits[frame.UnitName]
+ if unit then if trigger.uniqueUnits[unit] then passed = true else return end end
+ end
+
+ -- Plugin Callback
+ if mod.StyleFilterCustomChecks then
+ for _, customCheck in pairs(mod.StyleFilterCustomChecks) do
+ local custom = customCheck(frame, filter, trigger)
+ if custom ~= nil then -- ignore if nil return
+ if custom then passed = true else return end
+ end
+ end
+ end
+
+ -- Pass it along
+ if passed then
+ mod:StyleFilterPass(frame, filter.actions)
+ end
+end
+
+function mod:StyleFilterPass(frame, actions)
+ local healthBarEnabled = (frame.UnitType and mod.db.units[frame.UnitType].health.enable) or (frame.isTarget and mod.db.alwaysShowTargetHealth)
+ local healthBarShown = healthBarEnabled and frame.Health:IsShown()
+
+ mod:StyleFilterSetChanges(frame, actions,
+ (healthBarShown and actions.color and actions.color.health), --HealthColorChanged
+ (healthBarShown and actions.color and actions.color.border and frame.Health.backdrop), --BorderChanged
+ (healthBarShown and actions.flash and actions.flash.enable and frame.FlashTexture), --FlashingHealth
+ (healthBarShown and actions.texture and actions.texture.enable), --TextureChanged
+ (healthBarShown and actions.scale and actions.scale ~= 1), --ScaleChanged
+ (actions.frameLevel and actions.frameLevel ~= 0), --FrameLevelChanged
+ (actions.alpha and actions.alpha ~= -1), --AlphaChanged
+ (actions.color and actions.color.name), --NameColorChanged
+ (actions.nameOnly), --NameOnlyChanged
+ (actions.hide), --VisibilityChanged
+ (actions.icon), --IconChanged
+ (actions.iconOnly) --IconOnlyChanged
+ )
+end
+
+function mod:StyleFilterClear(frame)
+ if frame and frame.StyleChanged then
+ mod:StyleFilterClearChanges(frame, frame.HealthColorChanged, frame.BorderChanged, frame.FlashingHealth, frame.TextureChanged, frame.ScaleChanged, frame.FrameLevelChanged, frame.AlphaChanged, frame.NameColorChanged, frame.NameOnlyChanged, frame.VisibilityChanged, frame.IconChanged, frame.IconOnlyChanged)
+ end
+end
+
+function mod:StyleFilterSort(place)
+ if self[2] and place[2] then
+ return self[2] > place[2] --Sort by priority: 1=first, 2=second, 3=third, etc
+ end
+end
+
+function mod:StyleFilterClearVariables(nameplate)
+ nameplate.ActionScale = nil
+ nameplate.ThreatScale = nil
+end
+
+mod.StyleFilterTriggerList = {}
+mod.StyleFilterTriggerEvents = {}
+function mod:StyleFilterConfigure()
+ twipe(mod.StyleFilterTriggerList)
+ twipe(mod.StyleFilterTriggerEvents)
+
+ for filterName, filter in pairs(E.global.nameplates.filters) do
+ local t = filter.triggers
+ if t and E.db.nameplates and E.db.nameplates.filters then
+ if E.db.nameplates.filters[filterName] and E.db.nameplates.filters[filterName].triggers and E.db.nameplates.filters[filterName].triggers.enable then
+ tinsert(mod.StyleFilterTriggerList, {filterName, t.priority or 1})
+
+ mod.StyleFilterTriggerEvents.UpdateElement_All = 1
+ mod.StyleFilterTriggerEvents.NAME_PLATE_UNIT_ADDED = 1
+
+ if t.casting then
+ if next(t.casting.spells) then
+ for _, value in pairs(t.casting.spells) do
+ if value then
+ mod.StyleFilterTriggerEvents.FAKE_Casting = 0
+ break
+ end end end
+
+ if (t.casting.interruptible or t.casting.notInterruptible)
+ or (t.casting.isCasting or t.casting.isChanneling or t.casting.notCasting or t.casting.notChanneling) then
+ mod.StyleFilterTriggerEvents.FAKE_Casting = 0
+ end
+ end
+
+ if t.raidTarget and (t.raidTarget.star or t.raidTarget.circle or t.raidTarget.diamond or t.raidTarget.triangle or t.raidTarget.moon or t.raidTarget.square or t.raidTarget.cross or t.raidTarget.skull) then
+ mod.StyleFilterTriggerEvents.RAID_TARGET_UPDATE = 1
+ end
+
+ -- real events
+ mod.StyleFilterTriggerEvents.PLAYER_TARGET_CHANGED = true
+
+ if t.healthThreshold then
+ mod.StyleFilterTriggerEvents.UNIT_HEALTH = 1
+ mod.StyleFilterTriggerEvents.UNIT_MAXHEALTH = 1
+ end
+
+ if t.powerThreshold then
+ mod.StyleFilterTriggerEvents.UNIT_MANA = 1
+ mod.StyleFilterTriggerEvents.UNIT_ENERGY = 1
+ mod.StyleFilterTriggerEvents.UNIT_FOCUS = 1
+ mod.StyleFilterTriggerEvents.UNIT_RAGE = 1
+ mod.StyleFilterTriggerEvents.UNIT_RUNIC_POWER = 1
+ mod.StyleFilterTriggerEvents.UNIT_DISPLAYPOWER = 1
+ end
+
+ if t.names and next(t.names) then
+ for _, value in pairs(t.names) do
+ if value then
+ mod.StyleFilterTriggerEvents.UNIT_NAME_UPDATE = 1
+ break
+ end end end
+
+ if t.inCombat or t.outOfCombat then
+ mod.StyleFilterTriggerEvents.PLAYER_REGEN_DISABLED = true
+ mod.StyleFilterTriggerEvents.PLAYER_REGEN_ENABLED = true
+ end
+
+ if t.cooldowns and t.cooldowns.names and next(t.cooldowns.names) then
+ for _, value in pairs(t.cooldowns.names) do
+ if value == "ONCD" or value == "OFFCD" then
+ mod.StyleFilterTriggerEvents.SPELL_UPDATE_COOLDOWN = 1
+ break
+ end end end
+
+ if t.buffs and t.buffs.names and next(t.buffs.names) then
+ for _, value in pairs(t.buffs.names) do
+ if value then
+ mod.StyleFilterTriggerEvents.UNIT_AURA = true
+ break
+ end end end
+
+ if t.debuffs and t.debuffs.names and next(t.debuffs.names) then
+ for _, value in pairs(t.debuffs.names) do
+ if value then
+ mod.StyleFilterTriggerEvents.UNIT_AURA = true
+ break
+ end end end
+ end
+ end
+ end
+
+ if next(mod.StyleFilterTriggerList) then
+ sort(mod.StyleFilterTriggerList, mod.StyleFilterSort) -- sort by priority
+ else
+ mod:ForEachPlate("StyleFilterClear")
+ end
+end
+
+function mod:StyleFilterUpdate(frame, event)
+ local hasEvent = mod.StyleFilterTriggerEvents[event]
+ if not hasEvent then
+ return
+ elseif hasEvent == true then -- skip on 1 or 0
+ if not frame.StyleFilterWaitTime then
+ frame.StyleFilterWaitTime = GetTime()
+ elseif GetTime() > (frame.StyleFilterWaitTime + 0.1) then
+ frame.StyleFilterWaitTime = nil
+ else
+ return -- block calls faster than 0.1 second
+ end
+ end
+
+ mod:StyleFilterClear(frame)
+
+ for filterNum in ipairs(mod.StyleFilterTriggerList) do
+ local filter = E.global.nameplates.filters[mod.StyleFilterTriggerList[filterNum][1]]
+ if filter then
+ mod:StyleFilterConditionCheck(frame, filter, filter.triggers)
+ end
+ end
+end
+
+function mod:StyleFilterAddCustomCheck(name, func)
+ if not mod.StyleFilterCustomChecks then
+ mod.StyleFilterCustomChecks = {}
+ end
+
+ mod.StyleFilterCustomChecks[name] = func
+end
+
+function mod:StyleFilterRemoveCustomCheck(name)
+ if not mod.StyleFilterCustomChecks then
+ return
+ end
+
+ mod.StyleFilterCustomChecks[name] = nil
+end
+
+-- Shamelessy taken from AceDB-3.0 and stripped down by Simpy
+local function copyDefaults(dest, src)
+ for k, v in pairs(src) do
+ if type(v) == "table" then
+ if not rawget(dest, k) then rawset(dest, k, {}) end
+ if type(dest[k]) == "table" then copyDefaults(dest[k], v) end
+ elseif rawget(dest, k) == nil then
+ rawset(dest, k, v)
+ end
+ end
+end
+
+local function removeDefaults(db, defaults)
+ setmetatable(db, nil)
+
+ for k, v in pairs(defaults) do
+ if type(v) == "table" and type(db[k]) == "table" then
+ removeDefaults(db[k], v)
+ if next(db[k]) == nil then db[k] = nil end
+ elseif db[k] == defaults[k] then
+ db[k] = nil
+ end
+ end
+end
+
+function mod:StyleFilterClearDefaults()
+ for filterName, filterTable in pairs(E.global.nameplates.filters) do
+ if G.nameplates.filters[filterName] then
+ local defaultTable = E:CopyTable({}, E.StyleFilterDefaults)
+ E:CopyTable(defaultTable, G.nameplates.filters[filterName])
+ removeDefaults(filterTable, defaultTable)
+ else
+ removeDefaults(filterTable, E.StyleFilterDefaults)
+ end
+ end
+end
+
+function mod:StyleFilterCopyDefaults(tbl)
+ copyDefaults(tbl, E.StyleFilterDefaults)
+end
+
+function mod:StyleFilterInitialize()
+ for _, filterTable in pairs(E.global.nameplates.filters) do
+ mod:StyleFilterCopyDefaults(filterTable)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Addons/Ace3.lua b/ElvUI/Modules/Skins/Addons/Ace3.lua
new file mode 100644
index 0000000..9ad19f0
--- /dev/null
+++ b/ElvUI/Modules/Skins/Addons/Ace3.lua
@@ -0,0 +1,491 @@
+local E, _, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local select = select
+--WoW API / Variables
+local hooksecurefunc = hooksecurefunc
+
+-- functions that were overwritten, we need these to
+-- finish the function call when our code executes!
+local oldRegisterAsWidget, oldRegisterAsContainer
+
+-- these do *not* need to match the current lib minor version
+-- these numbers are used to not attempt skinning way older
+-- versions of AceGUI and AceConfigDialog.
+local minorGUI, minorConfigDialog = 1, 76
+
+function S:Ace3_SkinDropdownPullout()
+ if self and self.obj then
+ local pullout = self.obj.pullout
+ local dropdown = self.obj.dropdown
+
+ if pullout and pullout.frame then
+ if pullout.frame.template and pullout.slider.template then return end
+
+ if not pullout.frame.template then
+ pullout.frame:SetTemplate("Default", true)
+ end
+
+ if not pullout.slider.template then
+ pullout.slider:SetTemplate("Default")
+ pullout.slider:Point("TOPRIGHT", pullout.frame, "TOPRIGHT", -10, -10)
+ pullout.slider:Point("BOTTOMRIGHT", pullout.frame, "BOTTOMRIGHT", -10, 10)
+ if pullout.slider:GetThumbTexture() then
+ pullout.slider:SetThumbTexture(E.Media.Textures.Melli)
+ pullout.slider:GetThumbTexture():SetVertexColor(1, 0.82, 0, 0.8)
+ pullout.slider:GetThumbTexture():Size(10, 14)
+ end
+ end
+ elseif dropdown then
+ dropdown:SetTemplate("Default", true)
+
+ if dropdown.slider then
+ dropdown.slider:SetTemplate("Default")
+ dropdown.slider:Point("TOPRIGHT", dropdown, "TOPRIGHT", -10, -10)
+ dropdown.slider:Point("BOTTOMRIGHT", dropdown, "BOTTOMRIGHT", -10, 10)
+
+ if dropdown.slider:GetThumbTexture() then
+ dropdown.slider:SetThumbTexture(E.Media.Textures.Melli)
+ dropdown.slider:GetThumbTexture():SetVertexColor(1, 0.82, 0, 0.8)
+ dropdown.slider:GetThumbTexture():Size(10, 14)
+ end
+ end
+
+ if TYPE == "LSM30_Sound" then
+ local frame = self.obj.frame
+ local width = frame:GetWidth()
+ dropdown:Point("TOPLEFT", frame, "BOTTOMLEFT")
+ dropdown:Point("TOPRIGHT", frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 30, 0)
+ end
+ end
+ end
+end
+
+function S:Ace3_CheckBoxIsEnableSwitch(widget)
+ local text = widget.text and widget.text:GetText()
+ if text then
+ local enabled, disabled = text == S.Ace3_L.GREEN_ENABLE, text == S.Ace3_L.RED_ENABLE
+ local isSwitch = (text == S.Ace3_L.Enable) or enabled or disabled
+
+ return isSwitch
+ end
+end
+
+function S:Ace3_RegisterAsWidget(widget)
+ if not E.private.skins.ace3.enable then
+ return oldRegisterAsWidget(self, widget)
+ end
+
+ local TYPE = widget.type
+ if TYPE == "MultiLineEditBox" then
+ local frame = widget.frame
+ local scrollBG = widget.scrollBG or select(2, frame:GetChildren()) or frame:GetChildren()
+ local scrollBar = widget.scrollBar or _G[widget.scrollframe:GetName().."ScrollBar"]
+
+ if not scrollBG.template then
+ scrollBG:SetTemplate()
+ end
+
+ S:HandleButton(widget.button)
+ S:HandleScrollBar(scrollBar)
+ scrollBG:Point("TOPRIGHT", scrollBar, "TOPLEFT", -3, 19)
+ widget.scrollFrame:Point("BOTTOMRIGHT", scrollBG, "BOTTOMRIGHT", -4, 8)
+ elseif TYPE == "CheckBox" then
+ local check = widget.check
+ local checkbg = widget.checkbg
+ local highlight = widget.highlight
+
+ checkbg:CreateBackdrop()
+ checkbg.backdrop:SetInside(widget.checkbg, 4, 4)
+ checkbg.backdrop:SetFrameLevel(widget.checkbg.backdrop:GetFrameLevel() + 1)
+ checkbg:SetTexture()
+ checkbg.SetTexture = E.noop
+
+ check:SetParent(checkbg.backdrop)
+
+ highlight:SetTexture()
+ highlight.SetTexture = E.noop
+
+ hooksecurefunc(widget, "SetDisabled", function(w, value)
+ local isSwitch = S:Ace3_CheckBoxIsEnableSwitch(w)
+
+ if value then
+ if isSwitch then
+ w:SetLabel(S.Ace3_L.RED_ENABLE)
+ end
+ end
+ end)
+
+ hooksecurefunc(widget, "SetValue", function(w, value)
+ local isSwitch = S:Ace3_CheckBoxIsEnableSwitch(w)
+
+ if isSwitch then
+ w:SetLabel(value and S.Ace3_L.GREEN_ENABLE or S.Ace3_L.RED_ENABLE)
+ end
+ end)
+
+ if E.private.skins.checkBoxSkin then
+ checkbg.backdrop:SetInside(widget.checkbg, 5, 5)
+ check:SetTexture(E.Media.Textures.Melli)
+ check.SetTexture = E.noop
+ check:SetInside(widget.checkbg.backdrop)
+
+ hooksecurefunc(check, "SetDesaturated", function(chk, value)
+ if value == true then
+ chk:SetDesaturated(false)
+ end
+ end)
+
+ hooksecurefunc(widget, "SetDisabled", function(w, value)
+ local isSwitch = S:Ace3_CheckBoxIsEnableSwitch(w)
+
+ if value then
+ if isSwitch then
+ check:SetVertexColor(1.0, 0.2, 0.2, 1.0)
+ else
+ check:SetVertexColor(0.6, 0.6, 0.6, 0.8)
+ end
+ end
+ end)
+
+ hooksecurefunc(widget, "SetValue", function(w, value)
+ local isSwitch = S:Ace3_CheckBoxIsEnableSwitch(w)
+
+ if value then
+ if isSwitch then
+ check:SetVertexColor(0.2, 1.0, 0.2, 1.0)
+ else
+ check:SetVertexColor(1, 0.82, 0, 0.8)
+ end
+ else
+ if w.tristate and value == nil then
+ check:SetVertexColor(0.6, 0.6, 0.6, 0.8)
+ end
+ end
+ end)
+ else
+ check:SetOutside(widget.checkbg.backdrop, 3, 3)
+ end
+ elseif TYPE == "Dropdown" then
+ local frame = widget.dropdown
+ local button = widget.button
+ local button_cover = widget.button_cover
+ local text = widget.text
+ frame:StripTextures()
+
+ S:HandleNextPrevButton(button, nil, {1, 0.8, 0})
+
+ if not frame.backdrop then
+ frame:CreateBackdrop()
+ end
+
+ frame.backdrop:Point("TOPLEFT", 15, -2)
+ frame.backdrop:Point("BOTTOMRIGHT", -21, 0)
+
+ widget.label:ClearAllPoints()
+ widget.label:Point("BOTTOMLEFT", frame.backdrop, "TOPLEFT", 2, 0)
+
+ button:ClearAllPoints()
+ button:Point("TOPLEFT", frame.backdrop, "TOPRIGHT", -22, -2)
+ button:Point("BOTTOMRIGHT", frame.backdrop, "BOTTOMRIGHT", -2, 2)
+ button:SetParent(frame.backdrop)
+
+ text:ClearAllPoints()
+ text:SetJustifyH("RIGHT")
+ text:Point("RIGHT", button, "LEFT", -3, 0)
+ text:Point("LEFT", frame.backdrop, "LEFT", 2, 0)
+ text:SetParent(frame.backdrop)
+
+ button:HookScript("OnClick", S.Ace3_SkinDropdownPullout)
+ if button_cover then
+ button_cover:HookScript("OnClick", S.Ace3_SkinDropdownPullout)
+ end
+ elseif TYPE == "LSM30_Font" or TYPE == "LSM30_Sound" or TYPE == "LSM30_Border" or TYPE == "LSM30_Background" or TYPE == "LSM30_Statusbar" then
+ local frame = widget.frame
+ local button = frame.dropButton
+ local text = frame.text
+
+ frame:StripTextures()
+
+ S:HandleNextPrevButton(button, nil, {1, 0.8, 0})
+
+ if not frame.backdrop then
+ frame:CreateBackdrop()
+ end
+
+ frame.label:ClearAllPoints()
+ frame.label:Point("BOTTOMLEFT", frame.backdrop, "TOPLEFT", 2, 0)
+
+ text:ClearAllPoints()
+ text:Point("RIGHT", button, "LEFT", -2, 0)
+ text:Point("LEFT", frame.backdrop, "LEFT", 2, 0)
+
+ button:ClearAllPoints()
+ button:Point("TOPLEFT", frame.backdrop, "TOPRIGHT", -22, -2)
+ button:Point("BOTTOMRIGHT", frame.backdrop, "BOTTOMRIGHT", -2, 2)
+
+ frame.backdrop:Point("TOPLEFT", 0, -21)
+ frame.backdrop:Point("BOTTOMRIGHT", -4, -1)
+
+ if TYPE == "LSM30_Sound" then
+ widget.soundbutton:SetParent(frame.backdrop)
+ widget.soundbutton:ClearAllPoints()
+ widget.soundbutton:Point("LEFT", frame.backdrop, "LEFT", 2, 0)
+ elseif TYPE == "LSM30_Statusbar" then
+ widget.bar:SetParent(frame.backdrop)
+ widget.bar:ClearAllPoints()
+ widget.bar:Point("TOPLEFT", frame.backdrop, "TOPLEFT", 2, -2)
+ widget.bar:Point("BOTTOMRIGHT", button, "BOTTOMLEFT", -1, 0)
+ end
+
+ button:SetParent(frame.backdrop)
+ text:SetParent(frame.backdrop)
+
+ button:HookScript("OnClick", S.Ace3_SkinDropdownPullout)
+ elseif TYPE == "EditBox" then
+ local frame = widget.editbox
+ local button = widget.button
+ S:HandleEditBox(frame)
+ S:HandleButton(button)
+
+ hooksecurefunc(frame, "SetTextInsets", function(fr, l, r, t, b)
+ if l == 0 then
+ fr:SetTextInsets(3, r, t, b)
+ end
+ end)
+
+ button:Point("RIGHT", frame.backdrop, "RIGHT", -2, 0)
+
+ hooksecurefunc(frame, "SetPoint", function(fr, a, b, c, d, e)
+ if d == 7 then
+ fr:Point(a, b, c, 0, e)
+ end
+ end)
+
+ frame.backdrop:Point("TOPLEFT", 0, -2)
+ frame.backdrop:Point("BOTTOMRIGHT", -1, 0)
+ frame.backdrop:SetParent(widget.frame)
+ frame:SetParent(frame.backdrop)
+ elseif TYPE == "Button" or TYPE == "Button-ElvUI" then
+ local frame = widget.frame
+ S:HandleButton(frame, true, nil, true)
+ frame.backdrop:SetInside()
+
+ widget.text:SetParent(frame.backdrop)
+ elseif TYPE == "Slider" or TYPE == "Slider-ElvUI" then
+ local frame = widget.slider
+ local editbox = widget.editbox
+ local lowtext = widget.lowtext
+ local hightext = widget.hightext
+
+ S:HandleSliderFrame(frame)
+
+ editbox:SetTemplate()
+ editbox:Height(15)
+ editbox:Point("TOP", frame, "BOTTOM", 0, -1)
+
+ lowtext:Point("TOPLEFT", frame, "BOTTOMLEFT", 2, -2)
+ hightext:Point("TOPRIGHT", frame, "BOTTOMRIGHT", -2, -2)
+
+ hooksecurefunc(widget, "SetDisabled", function(w, disabled)
+ local thumbTex = w.slider:GetThumbTexture()
+ if disabled then
+ thumbTex:SetVertexColor(0.6, 0.6, 0.6, 0.8)
+ else
+ thumbTex:SetVertexColor(1, 0.82, 0, 0.8)
+ end
+ end)
+ elseif TYPE == "Keybinding" then
+ local button = widget.button
+ local msgframe = widget.msgframe
+ local msg = widget.msgframe.msg
+ S:HandleButton(button)
+ msgframe:StripTextures()
+ msgframe:CreateBackdrop("Default", true)
+ msgframe.backdrop:SetInside()
+ msgframe:SetToplevel(true)
+
+ msg:ClearAllPoints()
+ msg:Point("LEFT", 10, 0)
+ msg:Point("RIGHT", -10, 0)
+ msg:SetJustifyV("MIDDLE")
+ msg:Width(msg:GetWidth() + 10)
+ elseif (TYPE == "ColorPicker" or TYPE == "ColorPicker-ElvUI") then
+ local frame = widget.frame
+ local colorSwatch = widget.colorSwatch
+
+ if not frame.backdrop then
+ frame:CreateBackdrop()
+ end
+
+ frame.backdrop:Size(24, 16)
+ frame.backdrop:ClearAllPoints()
+ frame.backdrop:Point("LEFT", frame, "LEFT", 4, 0)
+ frame.backdrop:SetBackdropColor(0, 0, 0, 0)
+ frame.backdrop.SetBackdropColor = E.noop
+
+ colorSwatch:SetTexture(E.media.blankTex)
+ colorSwatch:ClearAllPoints()
+ colorSwatch:SetParent(frame.backdrop)
+ colorSwatch:SetInside(frame.backdrop)
+
+ if colorSwatch.background then
+ colorSwatch.background:SetTexture(0, 0, 0, 0)
+ end
+
+ if colorSwatch.checkers then
+ colorSwatch.checkers:ClearAllPoints()
+ colorSwatch.checkers:SetDrawLayer("ARTWORK")
+ colorSwatch.checkers:SetParent(frame.backdrop)
+ colorSwatch.checkers:SetInside(frame.backdrop)
+ end
+ elseif TYPE == "Icon" then
+ widget.frame:StripTextures()
+ end
+
+ return oldRegisterAsWidget(self, widget)
+end
+
+function S:Ace3_RegisterAsContainer(widget)
+ if not E.private.skins.ace3.enable then
+ return oldRegisterAsContainer(self, widget)
+ end
+ local TYPE = widget.type
+ if TYPE == "ScrollFrame" then
+ S:HandleScrollBar(widget.scrollbar)
+ widget.scrollbar:Point("TOPLEFT", widget.scrollframe, "TOPRIGHT", 8, -16)
+ widget.scrollbar:Point("BOTTOMLEFT", widget.scrollframe, "BOTTOMRIGHT", 8, 16)
+ elseif TYPE == "InlineGroup" or TYPE == "TreeGroup" or TYPE == "TabGroup" or TYPE == "Frame" or TYPE == "DropdownGroup" or TYPE == "Window" then
+ local frame = widget.content:GetParent()
+ if TYPE == "Frame" then
+ frame:StripTextures()
+ for i = 1, frame:GetNumChildren() do
+ local child = select(i, frame:GetChildren())
+ if child:IsObjectType("Button") and child:GetText() then
+ S:HandleButton(child)
+ else
+ child:StripTextures()
+ end
+ end
+ elseif TYPE == "Window" then
+ frame:StripTextures()
+ S:HandleCloseButton(frame.obj.closebutton)
+ end
+
+ if TYPE == "InlineGroup" then
+ frame:SetTemplate("Transparent")
+ frame.ignoreBackdropColors = true
+ frame:SetBackdropColor(0, 0, 0, 0.25)
+ else
+ frame:SetTemplate("Transparent")
+ end
+
+ if widget.treeframe then
+ widget.treeframe:SetTemplate("Transparent")
+ frame:Point("TOPLEFT", widget.treeframe, "TOPRIGHT", 1, 0)
+
+ local oldRefreshTree = widget.RefreshTree
+ widget.RefreshTree = function(wdg, scrollToSelection)
+ oldRefreshTree(wdg, scrollToSelection)
+ if not wdg.tree then return end
+ local status = wdg.status or wdg.localstatus
+ local groupstatus = status.groups
+ local lines = wdg.lines
+ local buttons = wdg.buttons
+ local offset = status.scrollvalue
+
+ for i = offset + 1, #lines do
+ local button = buttons[i - offset]
+ if button then
+ button.highlight:SetTexture(E.Media.Textures.Highlight)
+ button.highlight:SetVertexColor(1, 0.82, 0, 0.35)
+ button.highlight:Point("TOPLEFT", 0, 0)
+ button.highlight:Point("BOTTOMRIGHT", 0, 1)
+
+ button.toggle:SetHighlightTexture("")
+
+ if groupstatus[lines[i].uniquevalue] then
+ button.toggle:SetNormalTexture(E.Media.Textures.Minus)
+ button.toggle:SetPushedTexture(E.Media.Textures.Minus)
+ else
+ button.toggle:SetNormalTexture(E.Media.Textures.Plus)
+ button.toggle:SetPushedTexture(E.Media.Textures.Plus)
+ end
+ end
+ end
+ end
+ end
+
+ if TYPE == "TabGroup" then
+ local oldCreateTab = widget.CreateTab
+ widget.CreateTab = function(wdg, id)
+ local tab = oldCreateTab(wdg, id)
+ tab:StripTextures()
+ tab:CreateBackdrop("Transparent")
+ tab.backdrop:Point("TOPLEFT", 10, -3)
+ tab.backdrop:Point("BOTTOMRIGHT", -10, 0)
+
+ tab:SetHitRectInsets(10, 10, 3, 0)
+
+ return tab
+ end
+ end
+
+ if widget.scrollbar then
+ S:HandleScrollBar(widget.scrollbar)
+ widget.scrollbar:Point("TOPRIGHT", -4, -23)
+ widget.scrollbar:Point("BOTTOMRIGHT", -4, 23)
+ end
+ elseif TYPE == "SimpleGroup" then
+ local frame = widget.content:GetParent()
+ frame:SetTemplate("Transparent", nil, true)
+ frame.ignoreBackdropColors = true
+ frame:SetBackdropColor(0, 0, 0, 0.25)
+ end
+
+ return oldRegisterAsContainer(self, widget)
+end
+
+function S:Ace3_StyleTooltip()
+ if not self then return end
+ self:SetTemplate("Transparent", nil, true)
+end
+
+function S:Ace3_SkinTooltip(lib, minor) -- lib: AceConfigDialog or AceGUI
+ -- we only check `minor` here when checking an instance of AceConfigDialog
+ -- we can safely ignore it when checking AceGUI because we minor check that
+ -- inside of its own function.
+ if not lib or (minor and minor < minorConfigDialog) then return end
+
+ if lib.tooltip and not S:IsHooked(lib.tooltip, "OnShow") then
+ S:SecureHookScript(lib.tooltip, "OnShow", S.Ace3_StyleTooltip)
+ end
+
+ if lib.popup and not lib.popup.template then -- StaticPopup
+ lib.popup:SetTemplate("Transparent")
+ lib.popup:GetChildren():StripTextures()
+ S:HandleButton(lib.popup.accept, true)
+ S:HandleButton(lib.popup.cancel, true)
+ end
+end
+
+function S:HookAce3(lib, minor) -- lib: AceGUI
+ if not lib or (not minor or minor < minorGUI) then return end
+
+ if not S.Ace3_L then
+ S.Ace3_L = E.Libs.ACL:GetLocale("ElvUI", E.global.general.locale or "enUS")
+ end
+
+ if lib.RegisterAsWidget ~= S.Ace3_RegisterAsWidget then
+ oldRegisterAsWidget = lib.RegisterAsWidget
+ lib.RegisterAsWidget = S.Ace3_RegisterAsWidget
+ end
+
+ if lib.RegisterAsContainer ~= S.Ace3_RegisterAsContainer then
+ oldRegisterAsContainer = lib.RegisterAsContainer
+ lib.RegisterAsContainer = S.Ace3_RegisterAsContainer
+ end
+
+ S:Ace3_SkinTooltip(lib)
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Addons/Load_Addons.xml b/ElvUI/Modules/Skins/Addons/Load_Addons.xml
new file mode 100644
index 0000000..67686d3
--- /dev/null
+++ b/ElvUI/Modules/Skins/Addons/Load_Addons.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Achievement.lua b/ElvUI/Modules/Skins/Blizzard/Achievement.lua
new file mode 100644
index 0000000..af051d5
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Achievement.lua
@@ -0,0 +1,540 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local ipairs = ipairs
+local unpack = unpack
+--WoW API / Variables
+local hooksecurefunc = hooksecurefunc
+local GetAchievementNumCriteria = GetAchievementNumCriteria
+local GetAchievementCriteriaInfo = GetAchievementCriteriaInfo
+local CRITERIA_TYPE_ACHIEVEMENT = CRITERIA_TYPE_ACHIEVEMENT
+
+local function skinAchievement(achievement, biggerIcon)
+ if achievement.isSkinned then return end
+
+ _G[achievement:GetName().."Background"]:Kill()
+ achievement:StripTextures()
+ achievement:SetTemplate("Default", true)
+ achievement.icon:SetTemplate()
+ achievement.icon:SetSize(biggerIcon and 54 or 36, biggerIcon and 54 or 36)
+ achievement.icon:ClearAllPoints()
+ achievement.icon:Point("TOPLEFT", 8, -8)
+ achievement.icon.bling:Kill()
+ achievement.icon.frame:Kill()
+ achievement.icon.texture:SetTexCoord(unpack(E.TexCoords))
+ achievement.icon.texture:SetInside()
+
+ if achievement.highlight then
+ achievement.highlight:StripTextures()
+ achievement:HookScript("OnEnter", S.SetModifiedBackdrop)
+ achievement:HookScript("OnLeave", S.SetOriginalBackdrop)
+ end
+
+ if achievement.label then
+ achievement.label:SetTextColor(1, 1, 1)
+ end
+
+ if achievement.description then
+ achievement.description:SetTextColor(.6, .6, .6)
+ achievement.description.SetTextColor = E.noop
+ end
+
+ if achievement.hiddenDescription then
+ achievement.hiddenDescription:SetTextColor(1, 1, 1)
+ end
+
+ if achievement.tracked then
+ S:HandleCheckBox(achievement.tracked, true)
+ achievement.tracked:Size(14, 14)
+ achievement.tracked:ClearAllPoints()
+ achievement.tracked:Point("TOPLEFT", achievement.icon, "BOTTOMLEFT", 0, -2)
+ end
+
+ hooksecurefunc(achievement, "Saturate", function(self)
+ self:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end)
+ hooksecurefunc(achievement, "Desaturate", function(self)
+ self:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end)
+
+ achievement.isSkinned = true
+end
+
+S:AddCallback("Skin_AchievementUI_HybridScrollButton", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.achievement then return end
+
+ hooksecurefunc("HybridScrollFrame_CreateButtons", function(frame, template)
+ if template == "AchievementCategoryTemplate" then
+ for _, button in ipairs(frame.buttons) do
+ if not button.isSkinned then
+ button:StripTextures(true)
+ button:StyleButton()
+ button.isSkinned = true
+ end
+ end
+ elseif template == "AchievementTemplate" then
+ for _, achievement in ipairs(frame.buttons) do
+ skinAchievement(achievement, true)
+ end
+ elseif template == "ComparisonTemplate" then
+ for _, achievement in ipairs(frame.buttons) do
+ skinAchievement(achievement.player)
+ skinAchievement(achievement.friend)
+ end
+ elseif template == "StatTemplate" then
+ for _, stats in ipairs(frame.buttons) do
+ if not stats.isSkinned then
+ -- stats:StripTextures(true)
+ stats:StyleButton()
+ stats.isSkinned = true
+ end
+ end
+ end
+ end)
+end)
+
+S:AddCallbackForAddon("Blizzard_AchievementUI", "Skin_Blizzard_AchievementUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.achievement then return end
+
+ local frames = {
+ "AchievementFrame",
+ -- "AchievementFrameCategories",
+ "AchievementFrameSummary",
+ "AchievementFrameSummaryCategoriesHeader",
+ "AchievementFrameSummaryAchievementsHeader",
+ "AchievementFrameStatsBG",
+ "AchievementFrameAchievements",
+ "AchievementFrameComparison",
+ "AchievementFrameComparisonHeader",
+ "AchievementFrameComparisonSummaryPlayer",
+ "AchievementFrameComparisonSummaryFriend"
+ }
+
+ for _, frame in ipairs(frames) do
+ _G[frame]:StripTextures(true)
+ end
+
+ local nonameFrames = {
+ "AchievementFrameStats",
+ "AchievementFrameSummary",
+ "AchievementFrameAchievements",
+ "AchievementFrameComparison"
+ }
+
+ for _, frame in ipairs(nonameFrames) do
+ frame = _G[frame]
+ for i = 1, frame:GetNumChildren() do
+ local child = select(i, frame:GetChildren())
+ if child and not child:GetName() then
+ child:SetBackdrop(nil)
+ end
+ end
+ end
+
+ local function updatePanelInfo(self)
+ if self == AchievementFrameComparison then
+ if AchievementFrame.isComparison then
+ AchievementFrame:Width(863)
+ else
+ AchievementFrame:Width(737)
+ end
+ end
+
+ S:SetUIPanelWindowInfo(AchievementFrame, "xoffset", 11, nil, true)
+ S:SetUIPanelWindowInfo(AchievementFrame, "yoffset", -12, nil, true)
+ S:SetUIPanelWindowInfo(AchievementFrame, "width", nil, -11)
+ end
+
+ AchievementFrame:HookScript("OnShow", updatePanelInfo)
+ AchievementFrameComparison:HookScript("OnShow", updatePanelInfo)
+ AchievementFrameComparison:HookScript("OnHide", updatePanelInfo)
+
+ S:HandleCloseButton(AchievementFrameCloseButton, AchievementFrame.backdrop)
+
+ S:HandleDropDownBox(AchievementFrameFilterDropDown)
+
+ S:HandleScrollBar(AchievementFrameCategoriesContainerScrollBar)
+ S:HandleScrollBar(AchievementFrameAchievementsContainerScrollBar)
+ S:HandleScrollBar(AchievementFrameStatsContainerScrollBar)
+ S:HandleScrollBar(AchievementFrameComparisonContainerScrollBar)
+ S:HandleScrollBar(AchievementFrameComparisonStatsContainerScrollBar)
+
+ AchievementFrameHeaderTitle:SetParent(AchievementFrame)
+ AchievementFrameHeaderTitle:ClearAllPoints()
+ AchievementFrameHeaderTitle:Point("TOPLEFT", AchievementFrame, "TOPLEFT", -29, -9)
+
+ AchievementFrameHeaderPoints:SetParent(AchievementFrame)
+ AchievementFrameHeaderPoints:ClearAllPoints()
+ AchievementFrameHeaderPoints:Point("LEFT", AchievementFrameHeaderTitle, "RIGHT", 2, 0)
+
+ AchievementFrameHeaderShield:SetParent(AchievementFrame)
+
+ AchievementFrameHeader:Hide()
+ AchievementFrameHeader.Show = E.noop
+
+ AchievementFrame:Size(737, 485)
+ AchievementFrame:SetTemplate("Transparent")
+
+ AchievementFrameFilterDropDown:Point("TOPRIGHT", AchievementFrame, "TOPRIGHT", -21, -5)
+
+ AchievementFrameCategories:SetTemplate("Default")
+ AchievementFrameCategories:Point("TOPLEFT", 8, -35)
+ AchievementFrameCategories:Point("BOTTOMLEFT", 21, 8)
+
+ AchievementFrameCategoriesContainerScrollBar:Point("TOPLEFT", AchievementFrameCategoriesContainer, "TOPRIGHT", 3, -14)
+ AchievementFrameCategoriesContainerScrollBar:Point("BOTTOMLEFT", AchievementFrameCategoriesContainer, "BOTTOMRIGHT", 3, 14)
+
+ AchievementFrameSummaryAchievements:Point("TOPLEFT", 5, -10)
+ AchievementFrameSummaryAchievements:Point("TOPRIGHT", -5, -30)
+
+ AchievementFrameAchievements:SetTemplate("Transparent")
+
+ AchievementFrameAchievementsContainer:Point("TOPLEFT", 2, -2)
+ AchievementFrameAchievementsContainer:Point("BOTTOMRIGHT", -2, 4)
+
+ AchievementFrameAchievementsContainerScrollBar:Point("TOPLEFT", AchievementFrameAchievementsContainer, "TOPRIGHT", 5, -17)
+ AchievementFrameAchievementsContainerScrollBar:Point("BOTTOMLEFT", AchievementFrameAchievementsContainer, "BOTTOMRIGHT", 5, 15)
+
+ AchievementFrameStats:SetTemplate("Transparent")
+
+ AchievementFrameStatsContainerScrollBar:Point("TOPLEFT", AchievementFrameStatsContainer, "TOPRIGHT", 3, -16)
+ AchievementFrameStatsContainerScrollBar:Point("BOTTOMLEFT", AchievementFrameStatsContainer, "BOTTOMRIGHT", 3, 14)
+
+ AchievementFrameComparison:SetTemplate("Transparent")
+
+ AchievementFrameComparisonHeader:Point("BOTTOMRIGHT", AchievementFrameComparison, "TOPRIGHT", 50, -1)
+
+ AchievementFrameComparison:Point("TOPLEFT", AchievementFrameCategories, "TOPRIGHT", 3, 0)
+
+ AchievementFrameComparisonSummary:Height(30)
+ AchievementFrameComparisonSummary:Point("TOPLEFT", 4, -2)
+
+ AchievementFrameComparisonContainer:Point("TOPLEFT", AchievementFrameComparisonSummary, "BOTTOMLEFT", 0, -3)
+
+ AchievementFrameComparisonContainerScrollBar:Point("TOPLEFT", AchievementFrameComparisonSummary, "TOPRIGHT", 9, -17)
+ AchievementFrameComparisonContainerScrollBar:Point("BOTTOMLEFT", AchievementFrameComparisonContainer, "BOTTOMRIGHT", 9, 14)
+
+ AchievementFrameComparisonStatsContainer:Point("TOPLEFT", 5, -3)
+
+ AchievementFrameComparisonStatsContainerScrollBar:Point("TOPLEFT", AchievementFrameComparisonStatsContainer, "TOPRIGHT", 3, -16)
+ AchievementFrameComparisonStatsContainerScrollBar:Point("BOTTOMLEFT", AchievementFrameComparisonStatsContainer, "BOTTOMRIGHT", 3, 14)
+
+ AchievementFrameAchievementsContainerScrollBar.Show = function(self)
+ AchievementFrameAchievements:SetWidth(500)
+ for _, button in ipairs(AchievementFrameAchievements.buttons) do
+ button:SetWidth(496)
+ end
+ getmetatable(self).__index.Show(self)
+ end
+
+ AchievementFrameAchievementsContainerScrollBar.Hide = function(self)
+ AchievementFrameAchievements:SetWidth(521)
+ for _, button in ipairs(AchievementFrameAchievements.buttons) do
+ button:SetWidth(517)
+ end
+ getmetatable(self).__index.Hide(self)
+ end
+
+ AchievementFrameStatsContainerScrollBar.Show = function(self)
+ AchievementFrameStats:SetWidth(500)
+ for _, button in ipairs(AchievementFrameStats.buttons) do
+ button:SetWidth(494)
+ end
+ getmetatable(self).__index.Show(self)
+ end
+
+ AchievementFrameStatsContainerScrollBar.Hide = function(self)
+ AchievementFrameStats:SetWidth(521)
+ for _, button in ipairs(AchievementFrameStats.buttons) do
+ button:SetWidth(515)
+ end
+ getmetatable(self).__index.Hide(self)
+ end
+
+--[[
+ AchievementFrameComparisonContainerScrollBar.Show = function(self)
+ AchievementFrameComparison:SetWidth(626)
+ AchievementFrameComparisonSummaryPlayer:SetWidth(498)
+ for _, button in ipairs(AchievementFrameComparisonContainer.buttons) do
+ button:SetWidth(616)
+ button.player:SetWidth(498)
+ end
+ getmetatable(self).__index.Show(self)
+ end
+]]
+
+ AchievementFrameComparisonContainerScrollBar.Hide = function(self)
+ AchievementFrameComparison:SetWidth(647)
+ AchievementFrameComparisonSummaryPlayer:SetWidth(519)
+ for _, button in ipairs(AchievementFrameComparisonContainer.buttons) do
+ button:SetWidth(637)
+ button.player:SetWidth(519)
+ end
+ getmetatable(self).__index.Hide(self)
+ end
+
+--[[
+ AchievementFrameComparisonStatsContainerScrollBar.Show = function(self)
+ AchievementFrameComparison:SetWidth(626)
+ for _, button in ipairs(AchievementFrameComparisonStatsContainer.buttons) do
+ button:SetWidth(616)
+ end
+ getmetatable(self).__index.Show(self)
+ end
+]]
+
+ AchievementFrameComparisonStatsContainerScrollBar.Hide = function(self)
+ AchievementFrameComparison:SetWidth(647)
+ for _, button in ipairs(AchievementFrameComparisonStatsContainer.buttons) do
+ button:SetWidth(637)
+ end
+ getmetatable(self).__index.Hide(self)
+ end
+
+ local function categoriesContainerScripts()
+ AchievementFrameCategoriesContainerScrollBar.Show = function(self)
+ ACHIEVEMENTUI_CATEGORIESWIDTH = 176
+
+ AchievementFrameCategories:SetWidth(176)
+ AchievementFrameCategoriesContainer:GetScrollChild():SetWidth(176)
+
+ AchievementFrameAchievements:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 24, 0)
+ AchievementFrameStats:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 24, 0)
+ AchievementFrameComparison:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 24, 0)
+
+ for _, button in ipairs(AchievementFrameCategoriesContainer.buttons) do
+ AchievementFrameCategories_DisplayButton(button, button.element)
+ end
+ getmetatable(self).__index.Show(self)
+ end
+
+ AchievementFrameCategoriesContainerScrollBar.Hide = function(self)
+ ACHIEVEMENTUI_CATEGORIESWIDTH = 197
+
+ AchievementFrameCategories:SetWidth(197)
+ AchievementFrameCategoriesContainer:GetScrollChild():SetWidth(197)
+
+ AchievementFrameAchievements:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 3, 0)
+ AchievementFrameStats:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 3, 0)
+ AchievementFrameComparison:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 3, 0)
+
+ for _, button in ipairs(AchievementFrameCategoriesContainer.buttons) do
+ AchievementFrameCategories_DisplayButton(button, button.element)
+ end
+ getmetatable(self).__index.Hide(self)
+ end
+ end
+
+ if AchievementFrameCategoriesContainer.update then
+ categoriesContainerScripts()
+ else
+ AchievementFrameCategories:HookScript("OnEvent", categoriesContainerScripts)
+ end
+
+ for i = 1, 2 do
+ local tab = _G["AchievementFrameTab"..i]
+ S:HandleTab(tab)
+ tab.text:SetPoint("CENTER", 0, 2)
+ tab.text.SetPoint = E.noop
+ end
+
+ AchievementFrameTab1:Point("BOTTOMLEFT", AchievementFrame, "BOTTOMLEFT", 0, -30)
+ AchievementFrameTab2:Point("LEFT", AchievementFrameTab1, "RIGHT", -15, 0)
+
+ local sbcR, sbcG, sbcB = 4/255, 179/255, 30/255
+
+ local function skinStatusBar(bar)
+ bar:StripTextures()
+ bar:SetStatusBarTexture(E.media.normTex)
+ bar:SetStatusBarColor(sbcR, sbcG, sbcB)
+ bar:CreateBackdrop("Default")
+ E:RegisterStatusBar(bar)
+
+ local barName = bar:GetName()
+ local title = _G[barName.."Title"]
+ local label = _G[barName.."Label"]
+ local text = _G[barName.."Text"]
+
+ if title then
+ title:Point("LEFT", 4, 0)
+ end
+
+ if label then
+ label:Point("LEFT", 4, 0)
+ end
+
+ if text then
+ text:Point("RIGHT", -4, 0)
+ end
+ end
+
+ skinStatusBar(AchievementFrameSummaryCategoriesStatusBar)
+ skinStatusBar(AchievementFrameComparisonSummaryPlayerStatusBar)
+ skinStatusBar(AchievementFrameComparisonSummaryFriendStatusBar)
+ AchievementFrameComparisonSummaryFriendStatusBar.text:ClearAllPoints()
+ AchievementFrameComparisonSummaryFriendStatusBar.text:Point("CENTER")
+
+ for i = 1, 8 do
+ local frame = _G["AchievementFrameSummaryCategoriesCategory"..i]
+ local button = _G["AchievementFrameSummaryCategoriesCategory"..i.."Button"]
+ local highlight = _G["AchievementFrameSummaryCategoriesCategory"..i.."ButtonHighlight"]
+ local middle = _G["AchievementFrameSummaryCategoriesCategory"..i.."ButtonHighlightMiddle"]
+
+ skinStatusBar(frame)
+ button:StripTextures()
+ highlight:StripTextures()
+
+ middle:SetTexture(1, 1, 1, 0.3)
+ middle:SetAllPoints(frame)
+ end
+
+ for i = 1, 20 do
+ _G["AchievementFrameStatsContainerButton"..i]:StyleButton()
+ _G["AchievementFrameStatsContainerButton"..i.."BG"]:SetTexture(1, 1, 1, 0.2)
+ _G["AchievementFrameStatsContainerButton"..i.."HeaderLeft"]:Kill()
+ _G["AchievementFrameStatsContainerButton"..i.."HeaderRight"]:Kill()
+ _G["AchievementFrameStatsContainerButton"..i.."HeaderMiddle"]:Kill()
+
+ local frame = _G["AchievementFrameComparisonStatsContainerButton"..i]
+ frame:StripTextures()
+ frame:StyleButton()
+ _G["AchievementFrameComparisonStatsContainerButton"..i.."BG"]:SetTexture(1, 1, 1, 0.2)
+ _G["AchievementFrameComparisonStatsContainerButton"..i.."HeaderLeft"]:Kill()
+ _G["AchievementFrameComparisonStatsContainerButton"..i.."HeaderRight"]:Kill()
+ _G["AchievementFrameComparisonStatsContainerButton"..i.."HeaderMiddle"]:Kill()
+ end
+
+ hooksecurefunc("AchievementFrameSummary_UpdateAchievements", function()
+ local frame, prevFrame
+
+ for i = 1, ACHIEVEMENTUI_MAX_SUMMARY_ACHIEVEMENTS do
+ frame = _G["AchievementFrameSummaryAchievement"..i]
+
+ skinAchievement(frame)
+
+ if i ~= 1 then
+ prevFrame = _G["AchievementFrameSummaryAchievement"..(i-1)]
+ frame:ClearAllPoints()
+ frame:Point("TOPLEFT", prevFrame, "BOTTOMLEFT", 0, -1)
+ frame:Point("TOPRIGHT", prevFrame, "BOTTOMRIGHT", 0, 1)
+ end
+
+ frame:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end)
+
+ hooksecurefunc("AchievementButton_GetProgressBar", function(index)
+ local frame = _G["AchievementFrameProgressBar"..index]
+
+ if frame and not frame.skinned then
+ frame:StripTextures()
+ frame:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(frame)
+ frame:SetStatusBarColor(sbcR, sbcG, sbcB)
+ frame:GetStatusBarTexture():SetInside()
+ frame:Height(frame:GetHeight() + (E.Border + E.Spacing))
+ frame:SetTemplate("Default")
+
+ frame.text:ClearAllPoints()
+ frame.text:Point("CENTER", frame, "CENTER", 0, -1)
+ frame.text:SetJustifyH("CENTER")
+
+ if index > 1 then
+ frame:ClearAllPoints()
+ frame:Point("TOP", _G["AchievementFrameProgressBar"..index-1], "BOTTOM", 0, -5)
+ frame.SetPoint = E.noop
+ frame.ClearAllPoints = E.noop
+ end
+
+ frame.skinned = true
+ end
+ end)
+
+ hooksecurefunc("AchievementObjectives_DisplayCriteria", function(objectivesFrame, id)
+ local numCriteria = GetAchievementNumCriteria(id)
+ local textStrings, metas = 0, 0
+
+ for i = 1, numCriteria do
+ local _, criteriaType, completed, _, _, _, _, assetID = GetAchievementCriteriaInfo(id, i)
+
+ if criteriaType == CRITERIA_TYPE_ACHIEVEMENT and assetID then
+ metas = metas + 1
+ local metaCriteria = AchievementButton_GetMeta(metas)
+
+ metaCriteria:Height(21)
+ metaCriteria:StyleButton()
+ metaCriteria.border:Kill()
+ metaCriteria.icon:SetTexCoord(unpack(E.TexCoords))
+ metaCriteria.icon:Point("TOPLEFT", 2, -2)
+ metaCriteria.label:Point("LEFT", 26, 0)
+
+ if objectivesFrame.completed and completed then
+ metaCriteria.label:SetShadowOffset(0, 0)
+ metaCriteria.label:SetTextColor(1, 1, 1, 1)
+ elseif completed then
+ metaCriteria.label:SetShadowOffset(1, -1)
+ metaCriteria.label:SetTextColor(0, 1, 0, 1)
+ else
+ metaCriteria.label:SetShadowOffset(1, -1)
+ metaCriteria.label:SetTextColor(.6, .6, .6, 1)
+ end
+ elseif criteriaType ~= 1 then
+ textStrings = textStrings + 1
+ local criteria = AchievementButton_GetCriteria(textStrings)
+
+ if objectivesFrame.completed and completed then
+ criteria.name:SetTextColor(1, 1, 1, 1)
+ criteria.name:SetShadowOffset(0, 0)
+ elseif completed then
+ criteria.name:SetTextColor(0, 1, 0, 1)
+ criteria.name:SetShadowOffset(1, -1)
+ else
+ criteria.name:SetTextColor(.6, .6, .6, 1)
+ criteria.name:SetShadowOffset(1, -1)
+ end
+ end
+ end
+ end)
+
+ hooksecurefunc("AchievementObjectives_DisplayProgressiveAchievement", function(objectivesFrame, id)
+ local mini
+
+ for i = 1, 12 do
+ mini = _G["AchievementFrameMiniAchievement"..i]
+
+ if mini and not mini.isSkinned then
+ local icon = _G["AchievementFrameMiniAchievement"..i.."Icon"]
+ local points = _G["AchievementFrameMiniAchievement"..i.."Points"]
+ local border = _G["AchievementFrameMiniAchievement"..i.."Border"]
+ local shield = _G["AchievementFrameMiniAchievement"..i.."Shield"]
+
+ mini:SetTemplate()
+ mini:SetBackdropColor(0, 0, 0, 0)
+ mini:Size(32)
+
+ local prevFrame = _G["AchievementFrameMiniAchievement"..i - 1]
+ if i == 1 then
+ mini:Point("TOPLEFT", 6, -4)
+ elseif i == 7 then
+ mini:Point("TOPLEFT", AchievementFrameMiniAchievement1, "BOTTOMLEFT", 0, -20)
+ else
+ mini:Point("TOPLEFT", prevFrame, "TOPRIGHT", 10, 0)
+ end
+ mini.SetPoint = E.noop
+
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetInside()
+
+ points:Point("BOTTOMRIGHT", -8, -15)
+ points:SetTextColor(1, 0.80, 0.10)
+
+ border:Kill()
+ shield:Kill()
+
+ mini.isSkinned = true
+ end
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Alerts.lua b/ElvUI/Modules/Skins/Blizzard/Alerts.lua
new file mode 100644
index 0000000..b5208de
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Alerts.lua
@@ -0,0 +1,73 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+local tonumber = tonumber
+local match = string.match
+--WoW API / Variables
+
+S:AddCallback("Skin_Alerts", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.alertframes then return end
+
+ S:RawHook("AchievementAlertFrame_GetAlertFrame", function()
+ local frame = S.hooks.AchievementAlertFrame_GetAlertFrame()
+
+ if frame and not frame.isSkinned then
+ local name = frame:GetName()
+
+ frame:DisableDrawLayer("OVERLAY")
+
+ frame:CreateBackdrop("Transparent")
+ frame.backdrop:Point("TOPLEFT", frame, 0, -6)
+ frame.backdrop:Point("BOTTOMRIGHT", frame, 0, 6)
+
+ S:SetBackdropHitRect(frame)
+
+ _G[name.."Background"]:SetTexture(nil)
+ _G[name.."Unlocked"]:SetTextColor(1, 1, 1)
+
+ local icon = _G[name.."Icon"]
+ icon:DisableDrawLayer("BACKGROUND")
+ icon:DisableDrawLayer("OVERLAY")
+
+ icon.texture:ClearAllPoints()
+ icon.texture:Point("LEFT", frame, 13, 0)
+ icon.texture:SetTexCoord(unpack(E.TexCoords))
+
+ icon:CreateBackdrop("Default")
+ icon.backdrop:SetOutside(icon.texture)
+
+ frame.isSkinned = true
+
+ if tonumber(match(name, ".+(%d+)")) == MAX_ACHIEVEMENT_ALERTS then
+ S:Unhook("AchievementAlertFrame_GetAlertFrame")
+ end
+ end
+
+ return frame
+ end, true)
+
+ local frame = DungeonCompletionAlertFrame1
+ frame:DisableDrawLayer("BORDER")
+ frame:DisableDrawLayer("OVERLAY")
+
+ frame:CreateBackdrop("Transparent")
+ frame.backdrop:Point("TOPLEFT", frame, 0, -6)
+ frame.backdrop:Point("BOTTOMRIGHT", frame, 0, 6)
+
+ S:SetBackdropHitRect(frame)
+
+ frame.dungeonTexture:ClearAllPoints()
+ frame.dungeonTexture:Point("LEFT", frame, 13, 0)
+ frame.dungeonTexture:Size(42)
+ frame.dungeonTexture:SetTexCoord(unpack(E.TexCoords))
+
+ frame.dungeonTexture.backdrop = CreateFrame("Frame", "$parentDungeonTextureBackground", frame)
+ frame.dungeonTexture.backdrop:SetTemplate("Default")
+ frame.dungeonTexture.backdrop:SetOutside(frame.dungeonTexture)
+ frame.dungeonTexture.backdrop:SetFrameLevel(0)
+
+ frame.glowFrame:DisableDrawLayer("OVERLAY")
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Arena.lua b/ElvUI/Modules/Skins/Blizzard/Arena.lua
new file mode 100644
index 0000000..04f3175
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Arena.lua
@@ -0,0 +1,40 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallback("Skin_Arena", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.arena then return end
+
+ ArenaFrame:StripTextures()
+
+ ArenaFrame:CreateBackdrop("Transparent")
+ ArenaFrame.backdrop:Point("TOPLEFT", 11, -12)
+ ArenaFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(ArenaFrame, "width")
+ S:SetBackdropHitRect(ArenaFrame)
+
+ S:HandleCloseButton(ArenaFrameCloseButton, ArenaFrame.backdrop)
+
+ S:HandleButton(ArenaFrameGroupJoinButton)
+ S:HandleButton(ArenaFrameJoinButton)
+ S:HandleButton(ArenaFrameCancelButton)
+
+ for i = 1, MAX_ARENA_BATTLES do
+ S:HandleButtonHighlight(_G["ArenaZone"..i])
+ end
+
+ ArenaFrameZoneDescription:SetTextColor(1, 1, 1)
+
+ ArenaFrameNameHeader:Point("TOPLEFT", 28, -55)
+
+ ArenaZone1:Point("TOPLEFT", 24, -79)
+
+ ArenaFrameGroupJoinButton:Width(127)
+
+ ArenaFrameCancelButton:Point("CENTER", ArenaFrame, "TOPLEFT", 302, -417)
+ ArenaFrameJoinButton:Point("RIGHT", ArenaFrameCancelButton, "LEFT", -3, 0)
+ ArenaFrameGroupJoinButton:Point("RIGHT", ArenaFrameJoinButton, "LEFT", -3, 0)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/ArenaRegistrar.lua b/ElvUI/Modules/Skins/Blizzard/ArenaRegistrar.lua
new file mode 100644
index 0000000..f0120be
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/ArenaRegistrar.lua
@@ -0,0 +1,87 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local select = select
+--WoW API / Variables
+
+S:AddCallback("Skin_ArenaRegistrar", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.arenaregistrar then return end
+
+ ArenaRegistrarFrame:StripTextures(true)
+ ArenaRegistrarFrame:CreateBackdrop("Transparent")
+ ArenaRegistrarFrame.backdrop:Point("TOPLEFT", 11, -12)
+ ArenaRegistrarFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(ArenaRegistrarFrame, "width")
+ S:SetBackdropHitRect(ArenaRegistrarFrame)
+
+ S:HandleCloseButton(ArenaRegistrarFrameCloseButton, ArenaRegistrarFrame.backdrop)
+
+ ArenaRegistrarGreetingFrame:StripTextures()
+ ArenaRegistrarGreetingFrame:GetRegions():SetTextColor(1, 1, 1)
+
+ RegistrationText:SetTextColor(1, 1, 1)
+ ArenaRegistrarPurchaseText:SetTextColor(1, 1, 1)
+
+ for i = 1, 6 do
+ local button = _G["ArenaRegistrarButton"..i]
+ S:HandleButtonHighlight(button)
+ select(3, button:GetRegions()):SetTextColor(1, 1, 1)
+ end
+
+ S:HandleButton(ArenaRegistrarFrameGoodbyeButton)
+ S:HandleButton(ArenaRegistrarFrameCancelButton)
+ S:HandleButton(ArenaRegistrarFramePurchaseButton)
+
+ select(6, ArenaRegistrarFrameEditBox:GetRegions()):Kill()
+ select(7, ArenaRegistrarFrameEditBox:GetRegions()):Kill()
+ S:HandleEditBox(ArenaRegistrarFrameEditBox)
+
+ ArenaRegistrarFrameEditBox:Height(18)
+
+ ArenaRegistrarFrameGoodbyeButton:Width(80)
+ ArenaRegistrarFrameGoodbyeButton:Point("BOTTOMRIGHT", -40, 84)
+ ArenaRegistrarFrameCancelButton:Point("BOTTOMRIGHT", -40, 84)
+ ArenaRegistrarFramePurchaseButton:Point("BOTTOMLEFT", 19, 84)
+
+ -- PVP Banner
+ PVPBannerFrame:StripTextures()
+ PVPBannerFrame:CreateBackdrop("Transparent")
+ PVPBannerFrame.backdrop:Point("TOPLEFT", 11, -12)
+ PVPBannerFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(PVPBannerFrame, "width")
+ S:SetBackdropHitRect(PVPBannerFrame)
+
+ S:HandleCloseButton(PVPBannerFrameCloseButton, PVPBannerFrame.backdrop)
+
+ PVPBannerFramePortrait:Kill()
+
+ PVPBannerFrameCustomizationFrame:StripTextures()
+
+ for i = 1, 2 do
+ _G["PVPBannerFrameCustomization"..i]:StripTextures()
+ S:HandleNextPrevButton(_G["PVPBannerFrameCustomization"..i.."LeftButton"])
+ S:HandleNextPrevButton(_G["PVPBannerFrameCustomization"..i.."RightButton"])
+ end
+
+ S:HandleButton(PVPColorPickerButton1)
+ S:HandleButton(PVPColorPickerButton2)
+ S:HandleButton(PVPColorPickerButton3)
+
+ S:HandleButton(PVPBannerFrameAcceptButton)
+ S:HandleButton(PVPBannerFrameCancelButton)
+ local PVPBannerFrameCancelButton2 = select(4, PVPBannerFrame:GetChildren())
+ S:HandleButton(PVPBannerFrameCancelButton2)
+
+ PVPBannerFrameCustomization1:Point("TOPLEFT", PVPBannerFrameCustomizationBorder, "TOPLEFT", 48, -50)
+
+ PVPColorPickerButton1:Point("TOP", PVPBannerFrameCustomization2, "BOTTOM", 1, -7)
+ PVPColorPickerButton2:Point("TOP", PVPBannerFrameCustomization2, "BOTTOM", 1, -33)
+ PVPColorPickerButton3:Point("TOP", PVPBannerFrameCustomization2, "BOTTOM", 1, -59)
+
+ PVPBannerFrameCancelButton2:Point("CENTER", PVPBannerFrame, "TOPLEFT", 304, -417)
+ PVPBannerFrameAcceptButton:Point("CENTER", PVPBannerFrame, "TOPLEFT", 221, -417)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/AuctionHouse.lua b/ElvUI/Modules/Skins/Blizzard/AuctionHouse.lua
new file mode 100644
index 0000000..6c6d5e8
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/AuctionHouse.lua
@@ -0,0 +1,381 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local ipairs, unpack = ipairs, unpack
+--WoW API / Variables
+local GetAuctionSellItemInfo = GetAuctionSellItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local PlaySound = PlaySound
+local hooksecurefunc = hooksecurefunc
+
+S:AddCallbackForAddon("Blizzard_AuctionUI", "Skin_Blizzard_AuctionUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.auctionhouse then return end
+
+ AuctionFrame:StripTextures(true)
+ AuctionFrame:CreateBackdrop("Transparent")
+ AuctionFrame.backdrop:Point("TOPLEFT", 12, 0)
+ AuctionFrame.backdrop:Point("BOTTOMRIGHT", 0, 0)
+
+ S:HookScript(AuctionFrame, "OnShow", function(self)
+ S:SetUIPanelWindowInfo(self, "xoffset", -1, nil, true)
+ S:SetUIPanelWindowInfo(self, "yoffset", -12, nil, true)
+ S:SetUIPanelWindowInfo(self, "width", nil, 1)
+ S:SetBackdropHitRect(self)
+ S:Unhook(self, "OnShow")
+ end)
+
+ local buttons = {
+ BrowseSearchButton,
+ BrowseResetButton,
+ BrowseBidButton,
+ BrowseBuyoutButton,
+ BrowseCloseButton,
+ BidBidButton,
+ BidBuyoutButton,
+ BidCloseButton,
+ AuctionsCreateAuctionButton,
+ AuctionsCancelAuctionButton,
+ AuctionsStackSizeMaxButton,
+ AuctionsNumStacksMaxButton,
+ AuctionsCloseButton
+ }
+ local checkBoxes = {
+ IsUsableCheckButton,
+ ShowOnPlayerCheckButton
+ }
+ local editBoxes = {
+ BrowseName,
+ BrowseMinLevel,
+ BrowseMaxLevel,
+ BrowseBidPriceGold,
+ BrowseBidPriceSilver,
+ BrowseBidPriceCopper,
+ BidBidPriceGold,
+ BidBidPriceSilver,
+ BidBidPriceCopper,
+ AuctionsStackSizeEntry,
+ AuctionsNumStacksEntry,
+ StartPriceGold,
+ StartPriceSilver,
+ StartPriceCopper,
+ BuyoutPriceGold,
+ BuyoutPriceSilver,
+ BuyoutPriceCopper
+ }
+ local sortTabs = {
+ BrowseQualitySort,
+ BrowseLevelSort,
+ BrowseDurationSort,
+ BrowseHighBidderSort,
+ BrowseCurrentBidSort,
+ BidQualitySort,
+ BidLevelSort,
+ BidDurationSort,
+ BidBuyoutSort,
+ BidStatusSort,
+ BidBidSort,
+ AuctionsQualitySort,
+ AuctionsDurationSort,
+ AuctionsHighBidderSort,
+ AuctionsBidSort
+ }
+
+ for _, button in ipairs(buttons) do
+ S:HandleButton(button, true)
+ end
+ for _, checkBox in ipairs(checkBoxes) do
+ S:HandleCheckBox(checkBox)
+ end
+ for _, editBox in ipairs(editBoxes) do
+ S:HandleEditBox(editBox)
+ editBox:SetTextInsets(1, 1, -1, 1)
+ end
+ for _, tab in ipairs(sortTabs) do
+ tab:StripTextures()
+ tab:SetNormalTexture([[Interface\Buttons\UI-SortArrow]])
+ tab:StyleButton()
+ end
+
+ for i = 1, AuctionFrame.numTabs do
+ local tab = _G["AuctionFrameTab"..i]
+
+ S:HandleTab(tab)
+
+ if i == 1 then
+ tab:ClearAllPoints()
+ tab:Point("BOTTOMLEFT", AuctionFrame, "BOTTOMLEFT", 12, -30)
+ tab.SetPoint = E.noop
+ end
+ end
+
+ AuctionFrameTab2:Point("TOPLEFT", AuctionFrameTab1, "TOPRIGHT", -15, 0)
+ AuctionFrameTab3:Point("TOPLEFT", AuctionFrameTab2, "TOPRIGHT", -15, 0)
+
+ for i = 1, NUM_FILTERS_TO_DISPLAY do
+ local tab = _G["AuctionFilterButton"..i]
+
+ tab:StripTextures()
+
+ tab:SetHighlightTexture(E.Media.Textures.Highlight)
+ tab:GetHighlightTexture():SetInside()
+ tab:GetHighlightTexture():SetAlpha(0.35)
+ end
+
+ S:HandleCloseButton(AuctionFrameCloseButton, AuctionFrame.backdrop)
+
+ AuctionFrameMoneyFrame:Point("BOTTOMRIGHT", AuctionFrame, "BOTTOMLEFT", 181, 11)
+
+ -- Browse Frame
+ BrowseTitle:ClearAllPoints()
+ BrowseTitle:Point("TOP", AuctionFrame, "TOP", 0, -5)
+
+ BrowseScrollFrame:StripTextures()
+
+ BrowseFilterScrollFrame:StripTextures()
+
+ S:HandleScrollBar(BrowseFilterScrollFrameScrollBar)
+ BrowseFilterScrollFrameScrollBar:Point("TOPLEFT", BrowseFilterScrollFrame, "TOPRIGHT", 5, -19)
+ BrowseFilterScrollFrameScrollBar:Point("BOTTOMLEFT", BrowseFilterScrollFrame, "BOTTOMRIGHT", 5, 18)
+
+ S:HandleScrollBar(BrowseScrollFrameScrollBar)
+ BrowseScrollFrameScrollBar:ClearAllPoints()
+ BrowseScrollFrameScrollBar:Point("TOPRIGHT", BrowseScrollFrame, "TOPRIGHT", 25, -19)
+ BrowseScrollFrameScrollBar:Point("BOTTOMRIGHT", BrowseScrollFrame, "BOTTOMRIGHT", 0, 19)
+
+ S:HandleNextPrevButton(BrowsePrevPageButton, nil, nil, true)
+ BrowsePrevPageButton:Point("TOPLEFT", 640, -50)
+ BrowsePrevPageButton:Size(32)
+ BrowsePrevPageButton:SetHitRectInsets(6, 6, 6, 6)
+
+ S:HandleNextPrevButton(BrowseNextPageButton, nil, nil, true)
+ BrowseNextPageButton:Point("TOPRIGHT", 60, -50)
+ BrowseNextPageButton:Size(32)
+ BrowseNextPageButton:SetHitRectInsets(6, 6, 6, 6)
+
+ BrowseCloseButton:Point("BOTTOMRIGHT", 66, 6)
+ BrowseBuyoutButton:Point("RIGHT", BrowseCloseButton, "LEFT", -4, 0)
+ BrowseBidButton:Point("RIGHT", BrowseBuyoutButton, "LEFT", -4, 0)
+ BrowseResetButton:Point("TOPLEFT", 20, -74)
+ BrowseSearchButton:Point("TOPRIGHT", 10, -30)
+
+ BrowseNameText:Point("TOPLEFT", 18, -30)
+ BrowseName:Point("TOPLEFT", BrowseNameText, "BOTTOMLEFT", 3, -3)
+ BrowseName:Size(140, 18)
+
+ BrowseLevelText:Point("BOTTOMLEFT", AuctionFrameBrowse, "TOPLEFT", 200, -40)
+ BrowseMaxLevel:Point("LEFT", BrowseMinLevel, "RIGHT", 8, 0)
+
+ BrowseBidText:Point("RIGHT", BrowseBidPrice, "LEFT", -11, 0)
+ BrowseBidPrice:Point("BOTTOM", 25, 10)
+
+ -- Bid Frame
+ BidTitle:ClearAllPoints()
+ BidTitle:Point("TOP", AuctionFrame, "TOP", 0, -5)
+
+ BidScrollFrame:StripTextures()
+
+ BidBidText:ClearAllPoints()
+ BidBidText:Point("RIGHT", BidBidButton, "LEFT", -270, 2)
+
+ BidCloseButton:Point("BOTTOMRIGHT", 66, 6)
+ BidBuyoutButton:Point("RIGHT", BidCloseButton, "LEFT", -4, 0)
+ BidBidButton:Point("RIGHT", BidBuyoutButton, "LEFT", -4, 0)
+
+ BidBidPrice:Point("BOTTOM", 25, 10)
+
+ S:HandleScrollBar(BidScrollFrameScrollBar)
+ BidScrollFrameScrollBar:ClearAllPoints()
+ BidScrollFrameScrollBar:Point("TOPRIGHT", BidScrollFrame, "TOPRIGHT", 24, -19)
+ BidScrollFrameScrollBar:Point("BOTTOMRIGHT", BidScrollFrame, "BOTTOMRIGHT", 0, 17)
+
+ -- Auctions Frame
+ AuctionsTitle:ClearAllPoints()
+ AuctionsTitle:Point("TOP", AuctionFrame, "TOP", 0, -5)
+
+ AuctionsScrollFrame:StripTextures()
+
+ S:HandleScrollBar(AuctionsScrollFrameScrollBar)
+ AuctionsScrollFrameScrollBar:ClearAllPoints()
+ AuctionsScrollFrameScrollBar:Point("TOPRIGHT", AuctionsScrollFrame, "TOPRIGHT", 24, -21)
+ AuctionsScrollFrameScrollBar:Point("BOTTOMRIGHT", AuctionsScrollFrame, "BOTTOMRIGHT", 0, 19)
+
+ AuctionsCloseButton:Point("BOTTOMRIGHT", 66, 6)
+ AuctionsCancelAuctionButton:Point("RIGHT", AuctionsCloseButton, "LEFT", -4, 0)
+
+ AuctionsCreateAuctionButton:Width(181)
+ AuctionsCreateAuctionButton:Point("BOTTOMLEFT", AuctionFrameAuctions, "BOTTOMLEFT", 26, 39)
+
+ AuctionsStackSizeEntry.backdrop:SetAllPoints()
+ AuctionsNumStacksEntry.backdrop:SetAllPoints()
+
+ AuctionsItemButton:StripTextures()
+ AuctionsItemButton:SetTemplate("Default", true)
+ AuctionsItemButton:StyleButton()
+
+ AuctionsItemButton:HookScript("OnEvent", function(self, event)
+ local normalTexture = self:GetNormalTexture()
+
+ if event == "NEW_AUCTION_UPDATE" and normalTexture then
+ normalTexture:SetTexCoord(unpack(E.TexCoords))
+ normalTexture:SetInside()
+
+ local _, _, _, quality = GetAuctionSellItemInfo()
+
+ if quality then
+ self:SetBackdropBorderColor(GetItemQualityColor(quality))
+ else
+ self:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ else
+ self:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end)
+
+ S:HandleDropDownBox(BrowseDropDown, 155)
+ BrowseDropDown:Point("TOPLEFT", BrowseLevelText, "BOTTOMRIGHT", -5, 0)
+ S:HandleDropDownBox(PriceDropDown)
+ S:HandleDropDownBox(DurationDropDown)
+
+ -- Progress Frame
+ AuctionProgressFrame:StripTextures()
+ AuctionProgressFrame:SetTemplate("Transparent")
+
+ S:HandleButton(AuctionProgressFrameCancelButton)
+ AuctionProgressFrameCancelButton:SetHitRectInsets(0, 0, 0, 0)
+ AuctionProgressFrameCancelButton:GetNormalTexture():SetTexture(E.Media.Textures.Close)
+ AuctionProgressFrameCancelButton:GetNormalTexture():SetInside()
+ AuctionProgressFrameCancelButton:Size(28)
+ AuctionProgressFrameCancelButton:Point("LEFT", AuctionProgressBar, "RIGHT", 8, 0)
+
+ AuctionProgressBarIcon.backdrop = CreateFrame("Frame", nil, AuctionProgressBarIcon:GetParent())
+ AuctionProgressBarIcon.backdrop:SetTemplate("Default")
+ AuctionProgressBarIcon.backdrop:SetOutside(AuctionProgressBarIcon)
+
+ AuctionProgressBarIcon:SetTexCoord(unpack(E.TexCoords))
+ AuctionProgressBarIcon:SetParent(AuctionProgressBarIcon.backdrop)
+
+ AuctionProgressBarText:ClearAllPoints()
+ AuctionProgressBarText:SetPoint("CENTER")
+
+ AuctionProgressBar:StripTextures()
+ AuctionProgressBar:CreateBackdrop("Default")
+ AuctionProgressBar:SetStatusBarTexture(E.media.normTex)
+ AuctionProgressBar:SetStatusBarColor(1, 1, 0)
+
+ local frames = {
+ ["Browse"] = 8, -- NUM_BROWSE_TO_DISPLAY
+ ["Auctions"] = 9, -- NUM_AUCTIONS_TO_DISPLAY
+ ["Bid"] = 9 -- NUM_BIDS_TO_DISPLAY
+ }
+
+ for frameName, numButtons in pairs(frames) do
+ for i = 1, numButtons do
+ local button = _G[frameName.."Button"..i]
+ local itemButton = _G[frameName.."Button"..i.."Item"]
+ local name = _G[frameName.."Button"..i.."Name"]
+
+ if button then
+ button:StripTextures()
+
+ local highlight = _G[frameName.."Button"..i.."Highlight"]
+ highlight:SetTexture(E.Media.Textures.Highlight)
+ highlight:SetInside()
+
+ hooksecurefunc(name, "SetVertexColor", function(_, r, g, b)
+ highlight:SetVertexColor(r, g, b, 0.35)
+ end)
+ end
+
+ if itemButton then
+ itemButton:SetTemplate()
+ itemButton:StyleButton()
+ itemButton:GetNormalTexture():SetTexture("")
+ itemButton:Point("TOPLEFT", 0, -1)
+ itemButton:Size(34)
+
+ local texture = _G[frameName.."Button"..i.."ItemIconTexture"]
+ texture:SetTexCoord(unpack(E.TexCoords))
+ texture:SetInside()
+
+ hooksecurefunc(name, "SetVertexColor", function(_, r, g, b)
+ itemButton:SetBackdropBorderColor(r, g, b)
+ end)
+ hooksecurefunc(name, "Hide", function()
+ itemButton:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end)
+ end
+ end
+ end
+
+ -- Custom Backdrops
+ for _, frame in ipairs({AuctionFrameBrowse, AuctionFrameAuctions}) do
+ frame.LeftBackground = CreateFrame("Frame", nil, frame)
+ frame.LeftBackground:SetTemplate("Transparent")
+ frame.LeftBackground:SetFrameLevel(frame:GetFrameLevel() - 1)
+
+ frame.RightBackground = CreateFrame("Frame", nil, frame)
+ frame.RightBackground:SetTemplate("Transparent")
+ frame.RightBackground:SetFrameLevel(frame:GetFrameLevel() - 1)
+ end
+
+ AuctionFrameAuctions.LeftBackground:Point("TOPLEFT", 20, -72)
+ AuctionFrameAuctions.LeftBackground:Point("BOTTOMRIGHT", -545, 34)
+
+ AuctionFrameAuctions.RightBackground:Point("TOPLEFT", AuctionFrameAuctions.LeftBackground, "TOPRIGHT", 3, 0)
+ AuctionFrameAuctions.RightBackground:Point("BOTTOMRIGHT", AuctionFrame, -8, 34)
+
+ AuctionFrameBrowse.LeftBackground:Point("TOPLEFT", 20, -103)
+ AuctionFrameBrowse.LeftBackground:Point("BOTTOMRIGHT", -575, 34)
+
+ AuctionFrameBrowse.RightBackground:Point("TOPLEFT", AuctionFrameBrowse.LeftBackground, "TOPRIGHT", 4, 0)
+ AuctionFrameBrowse.RightBackground:Point("BOTTOMRIGHT", AuctionFrame, "BOTTOMRIGHT", -8, 34)
+
+ AuctionFrameBid.Background = CreateFrame("Frame", nil, AuctionFrameBid)
+ AuctionFrameBid.Background:SetTemplate("Transparent")
+ AuctionFrameBid.Background:Point("TOPLEFT", 20, -72)
+ AuctionFrameBid.Background:Point("BOTTOMRIGHT", 66, 34)
+ AuctionFrameBid.Background:SetFrameLevel(AuctionFrameBid:GetFrameLevel() - 1)
+
+ -- DressUpFrame
+ AuctionDressUpFrame:StripTextures()
+
+ S:HandleCloseButton(AuctionDressUpFrameCloseButton, AuctionDressUpFrame)
+
+ AuctionDressUpModel:CreateBackdrop()
+ AuctionDressUpModel.backdrop:SetOutside(AuctionDressUpModel)
+
+ SetAuctionDressUpBackground()
+ AuctionDressUpBackgroundTop:SetDesaturated(true)
+ AuctionDressUpBackgroundBot:SetDesaturated(true)
+
+ S:HandleRotateButton(AuctionDressUpModelRotateLeftButton)
+ S:HandleRotateButton(AuctionDressUpModelRotateRightButton)
+
+ S:HandleButton(AuctionDressUpFrameResetButton)
+
+ AuctionDressUpFrame:SetTemplate("Transparent")
+ AuctionDressUpFrame:Size(189, 401)
+ AuctionDressUpFrame:Point("TOPLEFT", AuctionFrame, "TOPRIGHT", -1, 0)
+
+ AuctionDressUpModel:Size(171, 365)
+ AuctionDressUpModel:Point("BOTTOM", AuctionDressUpFrame, "BOTTOM", 0, 9)
+
+ AuctionDressUpBackgroundTop:Point("TOPLEFT", AuctionDressUpFrame, "TOPLEFT", 9, -27)
+
+ AuctionDressUpModelRotateLeftButton:Point("TOPLEFT", AuctionDressUpFrame, "TOPLEFT", 12, -30)
+ AuctionDressUpModelRotateRightButton:Point("TOPLEFT", AuctionDressUpModelRotateLeftButton, "TOPRIGHT", 3, 0)
+
+ AuctionDressUpFrameResetButton:Point("BOTTOM", AuctionDressUpModel, "BOTTOM", 0, 7)
+
+ AuctionDressUpFrame:SetScript("OnShow", function()
+ S:SetUIPanelWindowInfo(AuctionFrame, "width", nil, 189)
+ PlaySound("igCharacterInfoOpen")
+ end)
+
+ AuctionDressUpFrame:SetScript("OnHide", function()
+ S:SetUIPanelWindowInfo(AuctionFrame, "width", nil, 1)
+ PlaySound("igCharacterInfoClose")
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/BGMap.lua b/ElvUI/Modules/Skins/Blizzard/BGMap.lua
new file mode 100644
index 0000000..577f256
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/BGMap.lua
@@ -0,0 +1,75 @@
+local E, L, V, P, G = unpack(ElvUI) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallbackForAddon("Blizzard_BattlefieldMinimap", "Skin_Blizzard_BattlefieldMinimap", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.bgmap then return end
+
+ BattlefieldMinimapCorner:Kill()
+ BattlefieldMinimapBackground:Kill()
+ BattlefieldMinimapTab:Kill()
+
+ BattlefieldMinimap:SetClampedToScreen(true)
+ BattlefieldMinimap:SetFrameStrata("LOW")
+ BattlefieldMinimap:CreateBackdrop("Default")
+ BattlefieldMinimap.backdrop:Point("BOTTOMRIGHT", E.Border - E:Scale(6), -(E.Border - E:Scale(4)))
+
+ S:SetBackdropHitRect(BattlefieldMinimap, nil, true)
+
+ S:HandleCloseButton(BattlefieldMinimapCloseButton, BattlefieldMinimap.backdrop)
+ BattlefieldMinimapCloseButton:SetFrameLevel(BattlefieldMinimap:GetFrameLevel() + 5)
+
+ BattlefieldMinimap:EnableMouse(true)
+ BattlefieldMinimap:SetMovable(true)
+
+ BattlefieldMinimap:SetScript("OnMouseUp", function(self, btn)
+ if btn == "LeftButton" then
+ if BattlefieldMinimapTab._moved then
+ BattlefieldMinimapTab:StopMovingOrSizing()
+ BattlefieldMinimapTab._moved = nil
+ end
+ elseif btn == "RightButton" then
+ ToggleDropDownMenu(1, nil, BattlefieldMinimapTabDropDown, self:GetName(), 0, -4)
+ end
+ end)
+
+ BattlefieldMinimap:SetScript("OnMouseDown", function(_, btn)
+ if btn == "LeftButton" then
+ if BattlefieldMinimapOptions and BattlefieldMinimapOptions.locked then return end
+
+ BattlefieldMinimapTab._moved = true
+ BattlefieldMinimapTab:StartMoving()
+ end
+ end)
+
+ hooksecurefunc("BattlefieldMinimap_UpdateOpacity", function()
+ BattlefieldMinimap.backdrop:SetAlpha(1.0 - BattlefieldMinimapOptions.opacity)
+ end)
+
+ local oldAlpha
+ BattlefieldMinimap:HookScript("OnEnter", function()
+ oldAlpha = BattlefieldMinimapOptions.opacity or 0
+ BattlefieldMinimap_UpdateOpacity(0)
+ end)
+
+ BattlefieldMinimap:HookScript("OnLeave", function()
+ if oldAlpha then
+ BattlefieldMinimap_UpdateOpacity(oldAlpha)
+ oldAlpha = nil
+ end
+ end)
+
+ BattlefieldMinimapCloseButton:HookScript("OnEnter", function()
+ oldAlpha = BattlefieldMinimapOptions.opacity or 0
+ BattlefieldMinimap_UpdateOpacity(0)
+ end)
+
+ BattlefieldMinimapCloseButton:HookScript("OnLeave", function()
+ if oldAlpha then
+ BattlefieldMinimap_UpdateOpacity(oldAlpha)
+ oldAlpha = nil
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/BGScore.lua b/ElvUI/Modules/Skins/Blizzard/BGScore.lua
new file mode 100644
index 0000000..0200345
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/BGScore.lua
@@ -0,0 +1,101 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local format, split = string.format, string.split
+--WoW API / Variables
+local FauxScrollFrame_GetOffset = FauxScrollFrame_GetOffset
+local GetBattlefieldScore = GetBattlefieldScore
+local IsActiveBattlefieldArena = IsActiveBattlefieldArena
+
+S:AddCallback("Skin_WorldStateScore", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.bgscore then return end
+
+ WorldStateScoreFrame:StripTextures()
+ WorldStateScoreFrame:CreateBackdrop("Transparent")
+ WorldStateScoreFrame.backdrop:Point("TOPLEFT", 10, -15)
+ WorldStateScoreFrame.backdrop:Point("BOTTOMRIGHT", -113, 67)
+
+ WorldStateScoreFrame:EnableMouse(true)
+ S:SetBackdropHitRect(WorldStateScoreFrame)
+
+ S:HandleCloseButton(WorldStateScoreFrameCloseButton, WorldStateScoreFrame.backdrop)
+
+ WorldStateScoreScrollFrame:StripTextures()
+ S:HandleScrollBar(WorldStateScoreScrollFrameScrollBar)
+
+ WorldStateScoreFrameKB:StyleButton()
+ WorldStateScoreFrameDeaths:StyleButton()
+ WorldStateScoreFrameHK:StyleButton()
+ WorldStateScoreFrameDamageDone:StyleButton()
+ WorldStateScoreFrameHealingDone:StyleButton()
+ WorldStateScoreFrameHonorGained:StyleButton()
+ WorldStateScoreFrameName:StyleButton()
+ WorldStateScoreFrameClass:StyleButton()
+ WorldStateScoreFrameTeam:StyleButton()
+-- WorldStateScoreFrameRatingChange:StyleButton()
+
+ S:HandleButton(WorldStateScoreFrameLeaveButton)
+
+ for i = 1, 3 do
+ S:HandleTab(_G["WorldStateScoreFrameTab"..i])
+ _G["WorldStateScoreFrameTab"..i.."Text"]:Point("CENTER", 0, 2)
+ end
+
+ WorldStateScoreFrameTab2:Point("LEFT", WorldStateScoreFrameTab1, "RIGHT", -15, 0)
+ WorldStateScoreFrameTab3:Point("LEFT", WorldStateScoreFrameTab2, "RIGHT", -15, 0)
+
+ WorldStateScoreScrollFrameScrollBar:Point("TOPLEFT", WorldStateScoreScrollFrame, "TOPRIGHT", 8, -21)
+ WorldStateScoreScrollFrameScrollBar:Point("BOTTOMLEFT", WorldStateScoreScrollFrame, "BOTTOMRIGHT", 8, 38)
+
+ for i = 1, 5 do
+ _G["WorldStateScoreColumn"..i]:StyleButton()
+ end
+
+ local myName = format("> %s <", E.myname)
+
+ hooksecurefunc("WorldStateScoreFrame_Update", function()
+ local inArena = IsActiveBattlefieldArena()
+ local offset = FauxScrollFrame_GetOffset(WorldStateScoreScrollFrame)
+
+ local _, name, faction, classToken, realm, classTextColor, nameText
+
+ for i = 1, MAX_WORLDSTATE_SCORE_BUTTONS do
+ name, _, _, _, _, faction, _, _, _, classToken = GetBattlefieldScore(offset + i)
+
+ if name then
+ name, realm = split("-", name, 2)
+
+ if name == E.myname then
+ name = myName
+ end
+
+ if realm then
+ local color
+
+ if inArena then
+ if faction == 1 then
+ color = "|cffffd100"
+ else
+ color = "|cff19ff19"
+ end
+ else
+ if faction == 1 then
+ color = "|cff00adf0"
+ else
+ color = "|cffff1919"
+ end
+ end
+
+ name = format("%s|cffffffff - |r%s%s|r", name, color, realm)
+ end
+
+ classTextColor = E.media.herocolor
+
+ nameText = _G["WorldStateScoreButton"..i.."NameText"]
+ nameText:SetText(name)
+ nameText:SetTextColor(classTextColor.r, classTextColor.g, classTextColor.b)
+ end
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Bags.lua b/ElvUI/Modules/Skins/Blizzard/Bags.lua
new file mode 100644
index 0000000..7a83ecf
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Bags.lua
@@ -0,0 +1,295 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local select = select
+local unpack = unpack
+--WoW API / Variables
+local ContainerIDToInventoryID = ContainerIDToInventoryID
+local GetContainerItemLink = GetContainerItemLink
+local GetContainerItemQuestInfo = GetContainerItemQuestInfo
+local GetContainerNumFreeSlots = GetContainerNumFreeSlots
+local GetInventoryItemLink = GetInventoryItemLink
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local GetInventoryItemID = GetInventoryItemID
+
+local BANK_CONTAINER = BANK_CONTAINER
+
+S:AddCallback("Skin_Bags", function()
+ if E.private.bags.enable then return end
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.bags then return end
+
+ local professionColors = {
+ [0x0001] = {E.db.bags.colors.profession.quiver.r, E.db.bags.colors.profession.quiver.g, E.db.bags.colors.profession.quiver.b},
+ [0x0002] = {E.db.bags.colors.profession.ammoPouch.r, E.db.bags.colors.profession.ammoPouch.g, E.db.bags.colors.profession.ammoPouch.b},
+ [0x0004] = {E.db.bags.colors.profession.soulBag.r, E.db.bags.colors.profession.soulBag.g, E.db.bags.colors.profession.soulBag.b},
+ [0x0008] = {E.db.bags.colors.profession.leatherworking.r, E.db.bags.colors.profession.leatherworking.g, E.db.bags.colors.profession.leatherworking.b},
+ [0x0010] = {E.db.bags.colors.profession.inscription.r, E.db.bags.colors.profession.inscription.g, E.db.bags.colors.profession.inscription.b},
+ [0x0020] = {E.db.bags.colors.profession.herbs.r, E.db.bags.colors.profession.herbs.g, E.db.bags.colors.profession.herbs.b},
+ [0x0040] = {E.db.bags.colors.profession.enchanting.r, E.db.bags.colors.profession.enchanting.g, E.db.bags.colors.profession.enchanting.b},
+ [0x0080] = {E.db.bags.colors.profession.engineering.r, E.db.bags.colors.profession.engineering.g, E.db.bags.colors.profession.engineering.b},
+ [0x0200] = {E.db.bags.colors.profession.gems.r, E.db.bags.colors.profession.gems.g, E.db.bags.colors.profession.gems.b},
+ [0x0400] = {E.db.bags.colors.profession.mining.r, E.db.bags.colors.profession.mining.g, E.db.bags.colors.profession.mining.b},
+ }
+
+ local questColors = {
+ ["questStarter"] = {E.db.bags.colors.items.questStarter.r, E.db.bags.colors.items.questStarter.g, E.db.bags.colors.items.questStarter.b},
+ ["questItem"] = {E.db.bags.colors.items.questItem.r, E.db.bags.colors.items.questItem.g, E.db.bags.colors.items.questItem.b}
+ }
+
+ -- ContainerFrame
+ for i = 1, NUM_CONTAINER_FRAMES do
+ local frame = _G["ContainerFrame"..i]
+ local closeButton = _G["ContainerFrame"..i.."CloseButton"]
+
+ frame:StripTextures(true)
+ frame:CreateBackdrop("Transparent")
+ frame.backdrop:Point("TOPLEFT", 9, -4)
+ frame.backdrop:Point("BOTTOMRIGHT", -4, 1)
+
+ S:HookScript(frame, "OnShow", function(self)
+ S:SetBackdropHitRect(self)
+ S:Unhook(self, "OnShow")
+ end)
+
+ S:HandleCloseButton(closeButton, frame.backdrop)
+
+ for j = 1, MAX_CONTAINER_ITEMS do
+ local item = _G["ContainerFrame"..i.."Item"..j]
+ local icon = _G["ContainerFrame"..i.."Item"..j.."IconTexture"]
+ local questIcon = _G["ContainerFrame"..i.."Item"..j.."IconQuestTexture"]
+ local cooldown = _G["ContainerFrame"..i.."Item"..j.."Cooldown"]
+
+ item:SetNormalTexture(nil)
+ item:SetTemplate("Default", true)
+ item:StyleButton()
+
+ icon:SetInside()
+ icon:SetTexCoord(unpack(E.TexCoords))
+
+ questIcon:SetTexture(E.Media.Textures.BagQuestIcon)
+ questIcon.SetTexture = E.noop
+ questIcon:SetTexCoord(0, 1, 0, 1)
+ questIcon:SetInside()
+
+ cooldown.CooldownOverride = "bags"
+ E:RegisterCooldown(cooldown)
+ end
+ end
+
+ BackpackTokenFrame:StripTextures()
+
+ for i = 1, MAX_WATCHED_TOKENS do
+ local token = _G["BackpackTokenFrameToken"..i]
+
+ token:CreateBackdrop("Default")
+ token.backdrop:SetOutside(token.icon)
+
+ token.icon:SetTexCoord(unpack(E.TexCoords))
+ token.icon:Point("LEFT", token.count, "RIGHT", 2, 0)
+ token.icon:Size(16)
+ end
+
+ local function setBagIcon(frame, texture)
+ if not frame.BagIcon then
+ local portraitButton = _G[frame:GetName().."PortraitButton"]
+
+ portraitButton:CreateBackdrop()
+ portraitButton:Size(32)
+ portraitButton:Point("TOPLEFT", 12, -7)
+ portraitButton:StyleButton(nil, true)
+ portraitButton.hover:SetAllPoints()
+
+ frame.BagIcon = portraitButton:CreateTexture()
+ frame.BagIcon:SetTexCoord(unpack(E.TexCoords))
+ frame.BagIcon:SetAllPoints()
+ end
+
+ frame.BagIcon:SetTexture(texture)
+ end
+
+ local bagIconCache = {
+ [-2] = "Interface\\ContainerFrame\\KeyRing-Bag-Icon",
+ [0] = "Interface\\Buttons\\Button-Backpack-Up"
+ }
+
+ hooksecurefunc("ContainerFrame_GenerateFrame", function(frame)
+ local id = frame:GetID()
+
+ if id > 0 then
+ local itemID = GetInventoryItemID("player", ContainerIDToInventoryID(id))
+
+ if not bagIconCache[itemID] then
+ bagIconCache[itemID] = select(10, GetItemInfo(itemID))
+ end
+
+ setBagIcon(frame, bagIconCache[itemID])
+ else
+ setBagIcon(frame, bagIconCache[id])
+ end
+ end)
+
+ hooksecurefunc("ContainerFrame_Update", function(frame)
+ local frameName = frame:GetName()
+ local id = frame:GetID()
+ local _, bagType = GetContainerNumFreeSlots(id)
+ local item, questIcon, link
+
+ for i = 1, frame.size do
+ item = _G[frameName.."Item"..i]
+ questIcon = _G[frameName.."Item"..i.."IconQuestTexture"]
+ link = GetContainerItemLink(id, item:GetID())
+
+ questIcon:Hide()
+
+ if professionColors[bagType] then
+ item:SetBackdropBorderColor(unpack(professionColors[bagType]))
+ item.ignoreBorderColors = true
+ elseif link then
+ local isQuestItem, questId, isActive = GetContainerItemQuestInfo(id, item:GetID())
+ local _, _, quality = GetItemInfo(link)
+
+ if questId and not isActive then
+ item:SetBackdropBorderColor(unpack(questColors.questStarter))
+ item.ignoreBorderColors = true
+ questIcon:Show()
+ elseif questId or isQuestItem then
+ item:SetBackdropBorderColor(unpack(questColors.questItem))
+ item.ignoreBorderColors = true
+ elseif quality then
+ item:SetBackdropBorderColor(GetItemQualityColor(quality))
+ item.ignoreBorderColors = true
+ else
+ item:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ item.ignoreBorderColors = nil
+ end
+ else
+ item:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ item.ignoreBorderColors = nil
+ end
+ end
+ end)
+
+ -- BankFrame
+ BankFrame:StripTextures(true)
+ BankFrame:CreateBackdrop("Transparent")
+ BankFrame.backdrop:Point("TOPLEFT", 11, -12)
+ BankFrame.backdrop:Point("BOTTOMRIGHT", -26, 76)
+
+ S:SetBackdropHitRect(BankFrame)
+
+ S:HandleCloseButton(BankCloseButton)
+
+ BankFrameItem1:Point("TOPLEFT", 39, -73)
+
+ for i = 1, NUM_BANKGENERIC_SLOTS do
+ local button = _G["BankFrameItem"..i]
+ local icon = _G["BankFrameItem"..i.."IconTexture"]
+ local quest = _G["BankFrameItem"..i.."IconQuestTexture"]
+ local cooldown = _G["BankFrameItem"..i.."Cooldown"]
+
+ button:SetNormalTexture(nil)
+ button:SetTemplate("Default", true)
+ button:StyleButton()
+
+ icon:SetInside()
+ icon:SetTexCoord(unpack(E.TexCoords))
+
+ quest:SetTexture(E.Media.Textures.BagQuestIcon)
+ quest.SetTexture = E.noop
+ quest:SetTexCoord(0, 1, 0, 1)
+ quest:SetInside()
+
+ cooldown.CooldownOverride = "bags"
+ E:RegisterCooldown(cooldown)
+ end
+
+ BankFrame.itemBackdrop = CreateFrame("Frame", "BankFrameItemBackdrop", BankFrame)
+ BankFrame.itemBackdrop:SetTemplate("Default")
+ BankFrame.itemBackdrop:SetOutside(BankFrameItem1, 6, 6, BankFrameItem28)
+ BankFrame.itemBackdrop:SetFrameLevel(BankFrame:GetFrameLevel())
+
+ for i = 1, NUM_BANKBAGSLOTS do
+ local button = _G["BankFrameBag"..i]
+ local icon = _G["BankFrameBag"..i.."IconTexture"]
+ local highlight = _G["BankFrameBag"..i.."HighlightFrameTexture"]
+
+ button:SetNormalTexture(nil)
+ button:SetTemplate("Default", true)
+ button:StyleButton()
+
+ icon:SetInside()
+ icon:SetTexCoord(unpack(E.TexCoords))
+
+ highlight:SetInside()
+ highlight:SetTexture(unpack(E.media.rgbvaluecolor), 0.3)
+ end
+
+ BankFrame.bagBackdrop = CreateFrame("Frame", "BankFrameBagBackdrop", BankFrame)
+ BankFrame.bagBackdrop:SetTemplate("Default")
+ BankFrame.bagBackdrop:SetOutside(BankFrameBag1, 6, 6, BankFrameBag7)
+ BankFrame.bagBackdrop:SetFrameLevel(BankFrame:GetFrameLevel())
+
+ S:HandleButton(BankFramePurchaseButton)
+
+ hooksecurefunc("BankFrameItemButton_Update", function(button)
+ local id = button:GetID()
+
+ if button.isBag then
+ local link = GetInventoryItemLink("player", ContainerIDToInventoryID(id))
+
+ if link then
+ local quality = select(3, GetItemInfo(link))
+
+ if quality then
+ button:SetBackdropBorderColor(GetItemQualityColor(quality))
+ button.ignoreBorderColors = true
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ button.ignoreBorderColors = nil
+ end
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ button.ignoreBorderColors = nil
+ end
+ else
+ local link = GetContainerItemLink(BANK_CONTAINER, id)
+ local questTexture = _G[button:GetName().."IconQuestTexture"]
+
+ if questTexture then
+ questTexture:Hide()
+ end
+
+ if link then
+ local isQuestItem, questId, isActive = GetContainerItemQuestInfo(BANK_CONTAINER, id)
+
+ if questId and not isActive then
+ button:SetBackdropBorderColor(unpack(questColors.questStarter))
+ button.ignoreBorderColors = true
+
+ if questTexture then
+ questTexture:Show()
+ end
+ elseif questId or isQuestItem then
+ button:SetBackdropBorderColor(unpack(questColors.questItem))
+ button.ignoreBorderColors = true
+ else
+ local quality = select(3, GetItemInfo(link))
+
+ if quality then
+ button:SetBackdropBorderColor(GetItemQualityColor(quality))
+ button.ignoreBorderColors = true
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ button.ignoreBorderColors = nil
+ end
+ end
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ button.ignoreBorderColors = nil
+ end
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Barber.lua b/ElvUI/Modules/Skins/Blizzard/Barber.lua
new file mode 100644
index 0000000..c9d69fa
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Barber.lua
@@ -0,0 +1,29 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallbackForAddon("Blizzard_BarbershopUI", "Skin_Blizzard_BarbershopUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.barber then return end
+
+ BarberShopFrame:CreateBackdrop("Transparent")
+ BarberShopFrame.backdrop:Point("TOPLEFT", 44, -70)
+ BarberShopFrame.backdrop:Point("BOTTOMRIGHT", -38, 42)
+
+ S:SetBackdropHitRect(BarberShopFrame)
+
+ BarberShopFrameBackground:Kill()
+
+ for i = 1, 4 do
+ S:HandleNextPrevButton(_G["BarberShopFrameSelector"..i.."Prev"])
+ S:HandleNextPrevButton(_G["BarberShopFrameSelector"..i.."Next"])
+ end
+
+ BarberShopFrameMoneyFrame:StripTextures()
+ BarberShopFrameMoneyFrame:CreateBackdrop()
+
+ S:HandleButton(BarberShopFrameOkayButton)
+ S:HandleButton(BarberShopFrameCancelButton)
+ S:HandleButton(BarberShopFrameResetButton)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Binding.lua b/ElvUI/Modules/Skins/Blizzard/Binding.lua
new file mode 100644
index 0000000..cbe8a18
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Binding.lua
@@ -0,0 +1,41 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallbackForAddon("Blizzard_BindingUI", "Skin_Blizzard_BindingUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.binding then return end
+
+ KeyBindingFrame:StripTextures()
+ KeyBindingFrame:CreateBackdrop("Transparent")
+ KeyBindingFrame.backdrop:Point("TOPLEFT", 2, 0)
+ KeyBindingFrame.backdrop:Point("BOTTOMRIGHT", -42, 13)
+
+ S:SetBackdropHitRect(KeyBindingFrame)
+
+ local bindingKey1, bindingKey2
+ for i = 1, KEY_BINDINGS_DISPLAYED do
+ bindingKey1 = _G["KeyBindingFrameBinding"..i.."Key1Button"]
+ bindingKey2 = _G["KeyBindingFrameBinding"..i.."Key2Button"]
+
+ S:HandleButton(bindingKey1)
+ S:HandleButton(bindingKey2)
+ bindingKey2:SetPoint("LEFT", bindingKey1, "RIGHT", 1, 0)
+ end
+
+ S:HandleScrollBar(KeyBindingFrameScrollFrameScrollBar)
+
+ S:HandleCheckBox(KeyBindingFrameCharacterButton)
+
+ S:HandleButton(KeyBindingFrameDefaultButton)
+ S:HandleButton(KeyBindingFrameCancelButton)
+ S:HandleButton(KeyBindingFrameOkayButton)
+ S:HandleButton(KeyBindingFrameUnbindButton)
+
+ KeyBindingFrameScrollFrameScrollBar:Point("TOPLEFT", KeyBindingFrameScrollFrame, "TOPRIGHT", 10, -21)
+ KeyBindingFrameScrollFrameScrollBar:Point("BOTTOMLEFT", KeyBindingFrameScrollFrame, "BOTTOMRIGHT", 10, 17)
+
+ KeyBindingFrameOkayButton:Point("RIGHT", KeyBindingFrameCancelButton, "LEFT", -3, 0)
+ KeyBindingFrameUnbindButton:Point("RIGHT", KeyBindingFrameOkayButton, "LEFT", -3, 0)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/BlizzardOptions.lua b/ElvUI/Modules/Skins/Blizzard/BlizzardOptions.lua
new file mode 100644
index 0000000..0fd6160
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/BlizzardOptions.lua
@@ -0,0 +1,624 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local ipairs = ipairs
+local find = string.find
+--WoW API / Variables
+local InCombatLockdown = InCombatLockdown
+local hooksecurefunc = hooksecurefunc
+
+S:AddCallback("Skin_BlizzardOptions", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.BlizzardOptions then return end
+
+ -- Game Menu Interface/Tabs
+ for i = 1, 2 do
+ local tab = _G["InterfaceOptionsFrameTab"..i]
+
+ tab:StripTextures()
+ S:HandleTab(tab)
+
+ tab.backdrop:SetTemplate("Transparent")
+ tab.backdrop:Point("TOPLEFT", 10, E.PixelMode and -4 or -6)
+ tab.backdrop:Point("BOTTOMRIGHT", -10, 1)
+
+ S:SetBackdropHitRect(tab)
+
+ if i == 1 then
+ tab:Point("BOTTOMLEFT", InterfaceOptionsFrameCategories, "TOPLEFT", -11, -2)
+ end
+ end
+
+ -- Game Menu Plus / Minus Buttons
+ for _, button in ipairs(InterfaceOptionsFrameAddOns.buttons) do
+ button.toggle:SetNormalTexture("")
+ button.toggle.SetNormalTexture = E.noop
+ button.toggle:SetPushedTexture("")
+ button.toggle.SetPushedTexture = E.noop
+ button.toggle:SetHighlightTexture(nil)
+
+ local text = button.toggle:CreateFontString(nil, "OVERLAY")
+ text:FontTemplate(nil, 22)
+ text:SetPoint("CENTER")
+ text:SetText("+")
+ button.toggle.text = text
+
+ hooksecurefunc(button.toggle, "SetNormalTexture", function(self, texture)
+ if find(texture, "MinusButton") then
+ self.text:SetText("-")
+ else
+ self.text:SetText("+")
+ end
+ end)
+ end
+
+ -- Interface Options Frame
+ local frames = {
+ InterfaceOptionsFrame,
+ AudioOptionsFrame,
+ VideoOptionsFrame
+ }
+ for _, frame in ipairs(frames) do
+ frame:SetTemplate("Transparent")
+ frame:SetClampedToScreen(true)
+ frame:SetMovable(true)
+ frame:EnableMouse(true)
+ frame:RegisterForDrag("LeftButton", "RightButton")
+ frame:SetScript("OnDragStart", function(self)
+ if InCombatLockdown() then return end
+
+ self:StartMoving()
+ end)
+ frame:SetScript("OnDragStop", function(self)
+ self:StopMovingOrSizing()
+ end)
+ end
+
+ local optionHeaders = {
+ InterfaceOptionsFrameHeader,
+ AudioOptionsFrameHeader,
+ VideoOptionsFrameHeader,
+ }
+ for _, header in ipairs(optionHeaders) do
+ header:SetTexture("")
+ header:SetPoint("TOP", 0, 0)
+ end
+
+ local optionFrames = {
+ "InterfaceOptionsFrameCategories",
+ "InterfaceOptionsFrameAddOns",
+ "InterfaceOptionsFramePanelContainer",
+
+ "AudioOptionsFrameCategoryFrame",
+ "AudioOptionsFramePanelContainer",
+ "AudioOptionsSoundPanelPlayback",
+ "AudioOptionsSoundPanelHardware",
+ "AudioOptionsSoundPanelVolume",
+
+ "VideoOptionsFrameCategoryFrame",
+ "VideoOptionsFramePanelContainer",
+ "VideoOptionsResolutionPanelBrightness",
+ "VideoOptionsEffectsPanelQuality",
+ "VideoOptionsEffectsPanelShaders",
+ }
+ for _, frame in ipairs(optionFrames) do
+ frame = _G[frame]
+ if frame then
+ frame:StripTextures()
+ frame:CreateBackdrop("Transparent")
+
+ if frame == VideoOptionsFramePanelContainer or frame == InterfaceOptionsFramePanelContainer then
+ frame.backdrop:Point("TOPLEFT", 0, 0)
+ frame.backdrop:Point("BOTTOMRIGHT", 0, 0)
+ else
+ frame.backdrop:Point("TOPLEFT", -1, 0)
+ frame.backdrop:Point("BOTTOMRIGHT", 0, 1)
+ end
+ end
+ end
+
+ local checkboxes = {
+ "InterfaceOptionsControlsPanelStickyTargeting",
+ "InterfaceOptionsControlsPanelAutoDismount",
+ "InterfaceOptionsControlsPanelAutoClearAFK",
+ "InterfaceOptionsControlsPanelBlockTrades",
+ "InterfaceOptionsControlsPanelLootAtMouse",
+ "InterfaceOptionsControlsPanelAutoLootCorpse",
+ "InterfaceOptionsCombatPanelAttackOnAssist",
+ "InterfaceOptionsCombatPanelAutoRange",
+ "InterfaceOptionsCombatPanelStopAutoAttack",
+ "InterfaceOptionsCombatPanelNameplateClassColors",
+ "InterfaceOptionsCombatPanelAutoSelfCast",
+ "InterfaceOptionsCombatPanelTargetOfTarget",
+ "InterfaceOptionsCombatPanelEnemyCastBarsOnPortrait",
+ "InterfaceOptionsCombatPanelEnemyCastBarsOnNameplates",
+ "InterfaceOptionsDisplayPanelShowCloak",
+ "InterfaceOptionsDisplayPanelShowHelm",
+ "InterfaceOptionsDisplayPanelShowAggroPercentage",
+ "InterfaceOptionsDisplayPanelPlayAggroSounds",
+ "InterfaceOptionsDisplayPanelDetailedLootInfo",
+ "InterfaceOptionsDisplayPanelShowFreeBagSpace",
+ "InterfaceOptionsDisplayPanelCinematicSubtitles",
+ "InterfaceOptionsDisplayPanelRotateMinimap",
+ "InterfaceOptionsDisplayPanelScreenEdgeFlash",
+ "InterfaceOptionsDisplayPanelShowClock",
+ "InterfaceOptionsDisplayPanelColorblindMode",
+ "InterfaceOptionsDisplayPanelShowItemLevel",
+ "InterfaceOptionsObjectivesPanelInstantQuestText",
+ "InterfaceOptionsObjectivesPanelAutoQuestTracking",
+ "InterfaceOptionsObjectivesPanelAutoQuestProgress",
+ "InterfaceOptionsObjectivesPanelMapQuestDifficulty",
+ "InterfaceOptionsObjectivesPanelAdvancedWorldMap",
+ "InterfaceOptionsObjectivesPanelWatchFrameWidth",
+ "InterfaceOptionsSocialPanelProfanityFilter",
+ "InterfaceOptionsSocialPanelSpamFilter",
+ "InterfaceOptionsSocialPanelChatBubbles",
+ "InterfaceOptionsSocialPanelPartyChat",
+ "InterfaceOptionsSocialPanelChatHoverDelay",
+ "InterfaceOptionsSocialPanelGuildMemberAlert",
+ "InterfaceOptionsSocialPanelGuildRecruitment",
+ "InterfaceOptionsSocialPanelChatMouseScroll",
+ "InterfaceOptionsSocialPanelWholeChatWindowClickable",
+ "InterfaceOptionsActionBarsPanelLockActionBars",
+ "InterfaceOptionsActionBarsPanelSecureAbilityToggle",
+ "InterfaceOptionsActionBarsPanelAlwaysShowActionBars",
+ "InterfaceOptionsActionBarsPanelBottomLeft",
+ "InterfaceOptionsActionBarsPanelBottomRight",
+ "InterfaceOptionsActionBarsPanelRight",
+ "InterfaceOptionsActionBarsPanelRightTwo",
+ "InterfaceOptionsNamesPanelMyName",
+ "InterfaceOptionsNamesPanelFriendlyPlayerNames",
+ "InterfaceOptionsNamesPanelFriendlyPets",
+ "InterfaceOptionsNamesPanelFriendlyGuardians",
+ "InterfaceOptionsNamesPanelFriendlyTotems",
+ "InterfaceOptionsNamesPanelUnitNameplatesFriends",
+ "InterfaceOptionsNamesPanelUnitNameplatesFriendlyGuardians",
+ "InterfaceOptionsNamesPanelUnitNameplatesFriendlyPets",
+ "InterfaceOptionsNamesPanelUnitNameplatesFriendlyTotems",
+ "InterfaceOptionsNamesPanelGuilds",
+ "InterfaceOptionsNamesPanelNPCNames",
+ "InterfaceOptionsNamesPanelUnitNameplatesAllowOverlap",
+ "InterfaceOptionsNamesPanelTitles",
+ "InterfaceOptionsNamesPanelNonCombatCreature",
+ "InterfaceOptionsNamesPanelEnemyPlayerNames",
+ "InterfaceOptionsNamesPanelEnemyPets",
+ "InterfaceOptionsNamesPanelEnemyGuardians",
+ "InterfaceOptionsNamesPanelEnemyTotems",
+ "InterfaceOptionsNamesPanelUnitNameplatesEnemyPets",
+ "InterfaceOptionsNamesPanelUnitNameplatesEnemies",
+ "InterfaceOptionsNamesPanelUnitNameplatesEnemyGuardians",
+ "InterfaceOptionsNamesPanelUnitNameplatesEnemyTotems",
+ "InterfaceOptionsCombatTextPanelTargetDamage",
+ "InterfaceOptionsCombatTextPanelPeriodicDamage",
+ "InterfaceOptionsCombatTextPanelPetDamage",
+ "InterfaceOptionsCombatTextPanelHealing",
+ "InterfaceOptionsCombatTextPanelTargetEffects",
+ "InterfaceOptionsCombatTextPanelOtherTargetEffects",
+ "InterfaceOptionsCombatTextPanelEnableFCT",
+ "InterfaceOptionsCombatTextPanelDodgeParryMiss",
+ "InterfaceOptionsCombatTextPanelDamageReduction",
+ "InterfaceOptionsCombatTextPanelRepChanges",
+ "InterfaceOptionsCombatTextPanelReactiveAbilities",
+ "InterfaceOptionsCombatTextPanelFriendlyHealerNames",
+ "InterfaceOptionsCombatTextPanelCombatState",
+ "InterfaceOptionsCombatTextPanelComboPoints",
+ "InterfaceOptionsCombatTextPanelLowManaHealth",
+ "InterfaceOptionsCombatTextPanelEnergyGains",
+ "InterfaceOptionsCombatTextPanelPeriodicEnergyGains",
+ "InterfaceOptionsCombatTextPanelHonorGains",
+ "InterfaceOptionsCombatTextPanelAuras",
+ "InterfaceOptionsBuffsPanelBuffDurations",
+ "InterfaceOptionsBuffsPanelDispellableDebuffs",
+ "InterfaceOptionsBuffsPanelCastableBuffs",
+ "InterfaceOptionsBuffsPanelConsolidateBuffs",
+ "InterfaceOptionsBuffsPanelShowCastableDebuffs",
+ "InterfaceOptionsCameraPanelFollowTerrain",
+ "InterfaceOptionsCameraPanelHeadBob",
+ "InterfaceOptionsCameraPanelWaterCollision",
+ "InterfaceOptionsCameraPanelSmartPivot",
+ "InterfaceOptionsMousePanelInvertMouse",
+ "InterfaceOptionsMousePanelClickToMove",
+ "InterfaceOptionsMousePanelWoWMouse",
+ "InterfaceOptionsHelpPanelShowTutorials",
+ "InterfaceOptionsHelpPanelLoadingScreenTips",
+ "InterfaceOptionsHelpPanelEnhancedTooltips",
+ "InterfaceOptionsHelpPanelBeginnerTooltips",
+ "InterfaceOptionsHelpPanelShowLuaErrors",
+ "InterfaceOptionsStatusTextPanelPlayer",
+ "InterfaceOptionsStatusTextPanelPet",
+ "InterfaceOptionsStatusTextPanelParty",
+ "InterfaceOptionsStatusTextPanelTarget",
+ "InterfaceOptionsStatusTextPanelPercentages",
+ "InterfaceOptionsStatusTextPanelXP",
+ "InterfaceOptionsUnitFramePanelPartyBackground",
+ "InterfaceOptionsUnitFramePanelPartyPets",
+ "InterfaceOptionsUnitFramePanelArenaEnemyFrames",
+ "InterfaceOptionsUnitFramePanelArenaEnemyCastBar",
+ "InterfaceOptionsUnitFramePanelArenaEnemyPets",
+ "InterfaceOptionsUnitFramePanelPartyInRaid",
+ "InterfaceOptionsUnitFramePanelRaidRange",
+ "InterfaceOptionsUnitFramePanelFullSizeFocusFrame",
+ "InterfaceOptionsFeaturesPanelPreviewTalentChanges",
+ "InterfaceOptionsFeaturesPanelEquipmentManager",
+
+ "AudioOptionsSoundPanelEnableSound",
+ "AudioOptionsSoundPanelSoundEffects",
+ "AudioOptionsSoundPanelErrorSpeech",
+ "AudioOptionsSoundPanelEmoteSounds",
+ "AudioOptionsSoundPanelPetSounds",
+ "AudioOptionsSoundPanelMusic",
+ "AudioOptionsSoundPanelLoopMusic",
+ "AudioOptionsSoundPanelAmbientSounds",
+ "AudioOptionsSoundPanelSoundInBG",
+ "AudioOptionsSoundPanelReverb",
+ "AudioOptionsSoundPanelHRTF",
+ "AudioOptionsSoundPanelEnableDSPs",
+ "AudioOptionsSoundPanelUseHardware",
+
+ "VideoOptionsResolutionPanelVSync",
+ "VideoOptionsResolutionPanelTripleBuffer",
+ "VideoOptionsResolutionPanelHardwareCursor",
+ "VideoOptionsResolutionPanelFixInputLag",
+ "VideoOptionsResolutionPanelUseUIScale",
+ "VideoOptionsResolutionPanelWindowed",
+ "VideoOptionsResolutionPanelMaximized",
+ "VideoOptionsResolutionPanelDisableResize",
+ "VideoOptionsResolutionPanelDesktopGamma",
+ "VideoOptionsEffectsPanelSpecularLighting",
+ "VideoOptionsEffectsPanelFullScreenGlow",
+ "VideoOptionsEffectsPanelDeathEffect",
+ "VideoOptionsEffectsPanelProjectedTextures",
+ }
+ for _, checkbox in ipairs(checkboxes) do
+ checkbox = _G[checkbox]
+ if checkbox then
+ S:HandleCheckBox(checkbox)
+ end
+ end
+
+ local sliders = {
+ "InterfaceOptionsCameraPanelMaxDistanceSlider",
+ "InterfaceOptionsCameraPanelFollowSpeedSlider",
+ "InterfaceOptionsMousePanelMouseLookSpeedSlider",
+ "InterfaceOptionsMousePanelMouseSensitivitySlider",
+
+ "AudioOptionsSoundPanelSoundQuality",
+ "AudioOptionsSoundPanelSoundChannels",
+ "AudioOptionsSoundPanelMasterVolume",
+ "AudioOptionsSoundPanelSoundVolume",
+ "AudioOptionsSoundPanelMusicVolume",
+ "AudioOptionsSoundPanelAmbienceVolume",
+
+ "VideoOptionsResolutionPanelUIScaleSlider",
+ "VideoOptionsEffectsPanelQualitySlider",
+ "VideoOptionsEffectsPanelViewDistance",
+ "VideoOptionsEffectsPanelEnvironmentDetail",
+ "VideoOptionsEffectsPanelTextureResolution",
+ "VideoOptionsEffectsPanelTerrainDetail",
+ "VideoOptionsEffectsPanelClutterDensity",
+ "VideoOptionsEffectsPanelTextureFiltering",
+ "VideoOptionsEffectsPanelParticleDensity",
+ "VideoOptionsEffectsPanelShadowQuality",
+ "VideoOptionsEffectsPanelClutterRadius",
+ "VideoOptionsEffectsPanelWeatherIntensity",
+ "VideoOptionsEffectsPanelPlayerTexture",
+ "VideoOptionsResolutionPanelGammaSlider",
+ }
+ for _, slider in ipairs(sliders) do
+ S:HandleSliderFrame(_G[slider])
+ end
+
+ local buttons = {
+ "InterfaceOptionsFrameDefaults",
+ "InterfaceOptionsFrameOkay",
+ "InterfaceOptionsFrameCancel",
+ --"InterfaceOptionsHelpPanelResetTutorials",
+
+ "AudioOptionsFrameDefaults",
+ "AudioOptionsFrameOkay",
+ "AudioOptionsFrameCancel",
+
+ "VideoOptionsFrameDefaults",
+ "VideoOptionsFrameOkay",
+ "VideoOptionsFrameCancel",
+ "VideoOptionsFrameApply",
+ }
+ for _, button in ipairs(buttons) do
+ S:HandleButton(_G[button])
+ end
+
+ local dropdowns = {
+ "InterfaceOptionsControlsPanelAutoLootKeyDropDown",
+ "InterfaceOptionsCombatPanelTOTDropDown",
+ "InterfaceOptionsCombatPanelFocusCastKeyDropDown",
+ "InterfaceOptionsCombatPanelSelfCastKeyDropDown",
+ "InterfaceOptionsDisplayPanelAggroWarningDisplay",
+ "InterfaceOptionsDisplayPanelWorldPVPObjectiveDisplay",
+ "InterfaceOptionsSocialPanelChatStyle",
+ "InterfaceOptionsSocialPanelTimestamps",
+ "InterfaceOptionsCombatTextPanelFCTDropDown",
+ "InterfaceOptionsCameraPanelStyleDropDown",
+ "InterfaceOptionsMousePanelClickMoveStyleDropDown",
+ "InterfaceOptionsLanguagesPanelLocaleDropDown",
+
+ "AudioOptionsSoundPanelHardwareDropDown",
+
+ "VideoOptionsResolutionPanelResolutionDropDown",
+ "VideoOptionsResolutionPanelRefreshDropDown",
+ }
+ for _, dropdown in ipairs(dropdowns) do
+ dropdown = _G[dropdown]
+ if dropdown then
+ S:HandleDropDownBox(dropdown)
+ end
+ end
+
+ InterfaceOptionsFrameCategoriesList:StripTextures()
+ InterfaceOptionsFrameAddOnsList:StripTextures()
+
+ S:HandleScrollBar(InterfaceOptionsFrameCategoriesListScrollBar)
+ S:HandleScrollBar(InterfaceOptionsFrameAddOnsListScrollBar)
+
+ InterfaceOptionsFrameCategoriesListScrollBar:Point("TOPRIGHT", 0, -20)
+ InterfaceOptionsFrameCategoriesListScrollBar:Point("BOTTOMLEFT", 6, 19)
+
+ InterfaceOptionsFrameAddOnsListScrollBar:Point("TOPRIGHT", 1, -18)
+ InterfaceOptionsFrameAddOnsListScrollBar:Point("BOTTOMLEFT", 7, 19)
+
+ S:HandleDropDownBox(VideoOptionsResolutionPanelMultiSampleDropDown, 195)
+
+ VideoOptionsFrameDefaults:Point("BOTTOMLEFT", 21, 16)
+ VideoOptionsFrameApply:Point("BOTTOMRIGHT", -22, 16)
+ VideoOptionsFrameCancel:Point("BOTTOMRIGHT", VideoOptionsFrameApply, "BOTTOMLEFT", -3, 0)
+ VideoOptionsFrameOkay:Point("BOTTOMRIGHT", VideoOptionsFrameCancel, "BOTTOMLEFT", -3, 0)
+
+ AudioOptionsFrameDefaults:Point("BOTTOMLEFT", 21, 16)
+ AudioOptionsFrameCancel:Point("BOTTOMRIGHT", -22, 16)
+ AudioOptionsFrameOkay:Point("BOTTOMRIGHT", AudioOptionsFrameCancel, "BOTTOMLEFT", -3, 0)
+
+ InterfaceOptionsFrameDefaults:Point("BOTTOMLEFT", 21, 16)
+ InterfaceOptionsFrameCancel:Point("BOTTOMRIGHT", -22, 16)
+ InterfaceOptionsFrameOkay:Point("BOTTOMRIGHT", InterfaceOptionsFrameCancel, "BOTTOMLEFT", -3, 0)
+
+ VideoOptionsResolutionPanelBrightnessGrayScale:SetTexture("Interface\\OptionsFrame\\21stepgrayscale")
+
+ -- Mac Menu
+ if IsMacClient() then
+ S:HandleButton(GameMenuButtonMacOptions)
+
+ -- Skin main frame and reposition the header
+ MacOptionsFrame:SetTemplate("Default", true)
+ MacOptionsFrameHeader:SetTexture("")
+ MacOptionsFrameHeader:SetPoint("TOP", 0, 0)
+
+ S:HandleDropDownBox(MacOptionsFrameResolutionDropDown)
+ S:HandleDropDownBox(MacOptionsFrameFramerateDropDown)
+ S:HandleDropDownBox(MacOptionsFrameCodecDropDown)
+
+ S:HandleSliderFrame(MacOptionsFrameQualitySlider)
+
+ for i = 1, 8 do
+ S:HandleCheckBox(_G["MacOptionsFrameCheckButton"..i])
+ end
+
+ -- Skin internal frames
+ MacOptionsFrameMovieRecording:SetTemplate("Default", true)
+ MacOptionsITunesRemote:SetTemplate("Default", true)
+
+ -- Skin buttons
+ S:HandleButton(MacOptionsFrameCancel)
+ S:HandleButton(MacOptionsFrameOkay)
+ S:HandleButton(MacOptionsButtonKeybindings)
+ S:HandleButton(MacOptionsFrameDefaults)
+ S:HandleButton(MacOptionsButtonCompress)
+
+ -- Reposition and resize buttons
+ MacOptionsButtonCompress:Width(136)
+ MacOptionsButtonCompress:Point("TOPLEFT", MacOptionsFrameCheckButton6, "BOTTOMLEFT", 4, -1)
+
+ MacOptionsFrameCancel:Size(96, 22)
+ MacOptionsFrameCancel:Point("BOTTOMRIGHT", -14, 16)
+
+ MacOptionsFrameOkay:ClearAllPoints()
+ MacOptionsFrameOkay:Size(96, 22)
+ MacOptionsFrameOkay:Point("LEFT", MacOptionsFrameCancel, -99, 0)
+
+ MacOptionsButtonKeybindings:ClearAllPoints()
+ MacOptionsButtonKeybindings:Size(96, 22)
+ MacOptionsButtonKeybindings:Point("LEFT", MacOptionsFrameOkay, -99, 0)
+
+ MacOptionsFrameDefaults:Size(96, 22)
+
+ MacOptionsCompressFrame:SetTemplate("Default", true)
+
+ MacOptionsCompressFrameHeader:SetTexture("")
+ MacOptionsCompressFrameHeader:SetPoint("TOP", 0, 0)
+
+ S:HandleButton(MacOptionsCompressFrameDelete)
+ S:HandleButton(MacOptionsCompressFrameSkip)
+ S:HandleButton(MacOptionsCompressFrameCompress)
+
+ MacOptionsCancelFrame:SetTemplate("Default", true)
+
+ MacOptionsCancelFrameHeader:SetTexture("")
+ MacOptionsCancelFrameHeader:SetPoint("TOP", 0, 0)
+
+ S:HandleButton(MacOptionsCancelFrameNo)
+ S:HandleButton(MacOptionsCancelFrameYes)
+ end
+
+ -- Chat Config
+ ChatConfigFrame:StripTextures()
+ ChatConfigFrame:SetTemplate("Transparent")
+ ChatConfigCategoryFrame:SetTemplate("Transparent")
+ ChatConfigBackgroundFrame:SetTemplate("Transparent")
+
+ ChatConfigChatSettingsClassColorLegend:SetTemplate("Transparent")
+ ChatConfigChannelSettingsClassColorLegend:SetTemplate("Transparent")
+
+ ChatConfigCombatSettingsFilters:SetTemplate("Transparent")
+
+ ChatConfigCombatSettingsFiltersScrollFrame:StripTextures()
+
+ S:HandleScrollBar(ChatConfigCombatSettingsFiltersScrollFrameScrollBar)
+ ChatConfigCombatSettingsFiltersScrollFrameScrollBarBorder:Kill()
+
+ S:HandleButton(ChatConfigCombatSettingsFiltersDeleteButton)
+ S:HandleButton(ChatConfigCombatSettingsFiltersAddFilterButton)
+ S:HandleButton(ChatConfigCombatSettingsFiltersCopyFilterButton)
+
+ ChatConfigCombatSettingsFiltersDeleteButton:Point("TOPRIGHT", ChatConfigCombatSettingsFilters, "BOTTOMRIGHT", 0, -1)
+ ChatConfigCombatSettingsFiltersAddFilterButton:Point("RIGHT", ChatConfigCombatSettingsFiltersDeleteButton, "LEFT", -1, 0)
+ ChatConfigCombatSettingsFiltersCopyFilterButton:Point("RIGHT", ChatConfigCombatSettingsFiltersAddFilterButton, "LEFT", -1, 0)
+
+ S:HandleNextPrevButton(ChatConfigMoveFilterUpButton)
+ ChatConfigMoveFilterUpButton:Size(26)
+ ChatConfigMoveFilterUpButton:Point("TOPLEFT", ChatConfigCombatSettingsFilters, "BOTTOMLEFT", 3, -1)
+ ChatConfigMoveFilterUpButton:SetHitRectInsets(0, 0, 0, 0)
+
+ S:HandleNextPrevButton(ChatConfigMoveFilterDownButton)
+ ChatConfigMoveFilterDownButton:Size(26)
+ ChatConfigMoveFilterDownButton:Point("LEFT", ChatConfigMoveFilterUpButton, "RIGHT", 1, 0)
+ ChatConfigMoveFilterDownButton:SetHitRectInsets(0, 0, 0, 0)
+
+ CombatConfigColorsHighlighting:StripTextures()
+ CombatConfigColorsColorizeUnitName:StripTextures()
+ CombatConfigColorsColorizeSpellNames:StripTextures()
+
+ CombatConfigColorsColorizeDamageNumber:StripTextures()
+ CombatConfigColorsColorizeDamageSchool:StripTextures()
+ CombatConfigColorsColorizeEntireLine:StripTextures()
+
+ S:HandleEditBox(CombatConfigSettingsNameEditBox)
+
+ S:HandleButton(CombatConfigSettingsSaveButton)
+
+ local combatCheckboxes = {
+ "CombatConfigColorsHighlightingLine",
+ "CombatConfigColorsHighlightingAbility",
+ "CombatConfigColorsHighlightingDamage",
+ "CombatConfigColorsHighlightingSchool",
+ "CombatConfigColorsColorizeUnitNameCheck",
+ "CombatConfigColorsColorizeSpellNamesCheck",
+ "CombatConfigColorsColorizeSpellNamesSchoolColoring",
+ "CombatConfigColorsColorizeDamageNumberCheck",
+ "CombatConfigColorsColorizeDamageNumberSchoolColoring",
+ "CombatConfigColorsColorizeDamageSchoolCheck",
+ "CombatConfigColorsColorizeEntireLineCheck",
+ "CombatConfigFormattingShowTimeStamp",
+ "CombatConfigFormattingShowBraces",
+ "CombatConfigFormattingUnitNames",
+ "CombatConfigFormattingSpellNames",
+ "CombatConfigFormattingItemNames",
+ "CombatConfigFormattingFullText",
+ "CombatConfigSettingsShowQuickButton",
+ "CombatConfigSettingsSolo",
+ "CombatConfigSettingsParty",
+ "CombatConfigSettingsRaid"
+ }
+ for i = 1, #combatCheckboxes do
+ S:HandleCheckBox(_G[combatCheckboxes[i]])
+ end
+
+ for i = 1, 5 do
+ local tab = _G["CombatConfigTab"..i]
+
+ tab:StripTextures()
+ tab:CreateBackdrop("Default", true)
+ tab.backdrop:Point("TOPLEFT", 1, -10)
+ tab.backdrop:Point("BOTTOMRIGHT", -1, 2)
+
+ tab:HookScript("OnEnter", S.SetModifiedBackdrop)
+ tab:HookScript("OnLeave", S.SetOriginalBackdrop)
+ end
+
+ S:HandleButton(ChatConfigFrameDefaultButton)
+ S:HandleButton(CombatLogDefaultButton)
+ S:HandleButton(ChatConfigFrameCancelButton)
+ S:HandleButton(ChatConfigFrameOkayButton)
+
+ ChatConfigFrameDefaultButton:Width(125)
+ ChatConfigFrameDefaultButton:Point("BOTTOMLEFT", 12, 8)
+
+ ChatConfigFrameCancelButton:Point("BOTTOMRIGHT", -1, 8)
+
+ S:HandleColorSwatch(CombatConfigColorsColorizeSpellNamesColorSwatch)
+ S:HandleColorSwatch(CombatConfigColorsColorizeDamageNumberColorSwatch)
+
+ hooksecurefunc("ChatConfig_CreateCheckboxes", function(frame, checkBoxTable, checkBoxTemplate)
+ frame:SetTemplate("Transparent")
+
+ local checkBoxNameString = frame:GetName().."CheckBox"
+ local checkBoxName, checkbox
+
+ for index in ipairs(checkBoxTable) do
+ checkBoxName = checkBoxNameString..index
+ checkbox = _G[checkBoxName]
+
+ if not checkbox.backdrop then
+ checkbox:StripTextures()
+ checkbox:CreateBackdrop()
+ checkbox.backdrop:Point("TOPLEFT", 3, -1)
+ checkbox.backdrop:Point("BOTTOMRIGHT", -3, 1)
+ checkbox.backdrop:SetFrameLevel(checkbox:GetParent():GetFrameLevel() + 1)
+
+ S:HandleCheckBox(_G[checkBoxName.."Check"])
+
+ if checkBoxTemplate == "ChatConfigCheckBoxWithSwatchTemplate" or checkBoxTemplate == "ChatConfigCheckBoxWithSwatchAndClassColorTemplate" then
+ if checkBoxTemplate == "ChatConfigCheckBoxWithSwatchAndClassColorTemplate" then
+ S:HandleCheckBox(_G[checkBoxName.."ColorClasses"])
+ end
+
+ S:HandleColorSwatch(_G[checkBoxName.."ColorSwatch"])
+ end
+ end
+ end
+ end)
+
+ hooksecurefunc("ChatConfig_CreateTieredCheckboxes", function(frame, checkBoxTable)
+ local checkBoxNameString = frame:GetName().."CheckBox"
+ local checkBoxName
+
+ for index, value in ipairs(checkBoxTable) do
+ checkBoxName = checkBoxNameString..index
+
+ if _G[checkBoxName] then
+ S:HandleCheckBox(_G[checkBoxName])
+
+ if value.subTypes then
+ local subCheckBox
+
+ for i in ipairs(value.subTypes) do
+ subCheckBox = _G[checkBoxName.."_"..i]
+
+ if subCheckBox then
+ S:HandleCheckBox(subCheckBox)
+ end
+ end
+ end
+ end
+ end
+ end)
+
+ hooksecurefunc("ChatConfig_CreateColorSwatches", function(frame, swatchTable)
+ frame:SetTemplate("Transparent")
+
+ local nameString = frame:GetName().."Swatch"
+ local swatch
+
+ for index in ipairs(swatchTable) do
+ swatch = _G[nameString..index]
+
+ if not swatch.backdrop then
+ swatch:StripTextures()
+ swatch:CreateBackdrop()
+ swatch.backdrop:Point("TOPLEFT", 3, -1)
+ swatch.backdrop:Point("BOTTOMRIGHT", -3, 1)
+ swatch.backdrop:SetFrameLevel(swatch:GetParent():GetFrameLevel() + 1)
+
+ S:HandleColorSwatch(_G[nameString..index.."ColorSwatch"])
+ end
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Calendar.lua b/ElvUI/Modules/Skins/Blizzard/Calendar.lua
new file mode 100644
index 0000000..4773883
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Calendar.lua
@@ -0,0 +1,395 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+local fmod = math.fmod
+--WoW API / Variables
+local hooksecurefunc = hooksecurefunc
+local CLASS_SORT_ORDER = CLASS_SORT_ORDER
+
+S:AddCallbackForAddon("Blizzard_Calendar", "Skin_Blizzard_Calendar", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.calendar then return end
+
+ CalendarFrame:StripTextures()
+ CalendarFrame:CreateBackdrop("Transparent")
+ CalendarFrame.backdrop:Point("TOPLEFT", 3, -7)
+ CalendarFrame.backdrop:Point("BOTTOMRIGHT", -2, -4)
+
+ S:SecureHook("Calendar_Show", function()
+ S:SetUIPanelWindowInfo(CalendarFrame, "xoffset", 8, nil, true)
+ S:SetUIPanelWindowInfo(CalendarFrame, "yoffset", -5, nil, true)
+ S:SetUIPanelWindowInfo(CalendarFrame, "width", nil, -8)
+ S:SetBackdropHitRect(CalendarFrame)
+ S:Unhook("Calendar_Show")
+ end)
+
+ CalendarFrameModalOverlay:SetFrameStrata("DIALOG")
+ CalendarModalDummy:SetAllPoints(CalendarFrameModalOverlay)
+ CalendarFrameBlocker:SetAllPoints(CalendarFrameModalOverlay)
+
+ CalendarFrame:EnableMouseWheel(true)
+ CalendarFrame:SetScript("OnMouseWheel", function(_, value)
+ if value > 0 then
+ if CalendarPrevMonthButton:IsEnabled() == 1 then
+ CalendarPrevMonthButton_OnClick()
+ end
+ else
+ if CalendarNextMonthButton:IsEnabled() == 1 then
+ CalendarNextMonthButton_OnClick()
+ end
+ end
+ end)
+
+ S:HandleCloseButton(CalendarCloseButton, CalendarFrame.backdrop)
+
+ S:HandleNextPrevButton(CalendarPrevMonthButton)
+ S:HandleNextPrevButton(CalendarNextMonthButton)
+
+ CalendarPrevMonthButton:Point("RIGHT", CalendarMonthBackground, "LEFT", 0, -8)
+ CalendarNextMonthButton:Point("LEFT", CalendarMonthBackground, "RIGHT", 0, -8)
+
+ do
+ local frame = CalendarFilterFrame
+ local button = CalendarFilterButton
+ local text = CalendarFilterFrameText
+
+ frame:StripTextures()
+ frame:Width(155)
+ frame:Point("TOPRIGHT", -32, -24)
+
+ text:Point("RIGHT", -34, 3)
+
+ button:Point("RIGHT", frame, "RIGHT", -10, 3)
+ button.SetPoint = E.noop
+
+ S:HandleNextPrevButton(button)
+
+ frame:CreateBackdrop("Default")
+ frame.backdrop:Point("TOPLEFT", 20, 4)
+ frame.backdrop:Point("BOTTOMRIGHT", button, "BOTTOMRIGHT", 2, -2)
+ end
+
+ local bg = CreateFrame("Frame", "CalendarFrameBackdrop", CalendarFrame)
+ bg:SetTemplate("Default")
+ bg:SetOutside(CalendarDayButton1, 3, 3, CalendarDayButton42)
+
+ CalendarContextMenu:SetTemplate("Transparent")
+ CalendarContextMenu.SetBackdropColor = E.noop
+ CalendarContextMenu.SetBackdropBorderColor = E.noop
+
+ CalendarInviteStatusContextMenu:SetTemplate("Transparent")
+ CalendarInviteStatusContextMenu.SetBackdropColor = E.noop
+ CalendarInviteStatusContextMenu.SetBackdropBorderColor = E.noop
+
+ for i = 1, 7 do
+ _G["CalendarContextMenuButton"..i]:StyleButton()
+ end
+
+ for i = 1, 42 do
+ local button = _G["CalendarDayButton"..i]
+ local eventTexture = _G["CalendarDayButton"..i.."EventTexture"]
+ local overlayFrame = _G["CalendarDayButton"..i.."OverlayFrame"]
+ button:SetFrameLevel(button:GetFrameLevel() + 1)
+ button:Size(91 - E.Border)
+ button:SetTemplate("Default", nil, true)
+ button:SetBackdropColor(0, 0, 0, 0)
+ button:GetNormalTexture():SetInside()
+ button:GetNormalTexture():SetDrawLayer("BACKGROUND")
+ button:GetHighlightTexture():SetInside()
+ button:GetHighlightTexture():SetTexture(1, 1, 1, 0.3)
+ eventTexture:SetInside()
+ overlayFrame:SetInside()
+
+ hooksecurefunc(eventTexture, "SetTexCoord", function(self, left, right, top, bottom)
+ if left == 0 and right == 1 and top == 0 and bottom == 1 then
+ if self._blocked then return end
+
+ self._blocked = true
+ self:SetTexCoord(unpack(E.TexCoords))
+ self._blocked = nil
+ end
+ end)
+
+ for j = 1, 4 do
+ local EventButton = _G["CalendarDayButton"..i.."EventButton"..j]
+ EventButton:StripTextures()
+ EventButton:StyleButton()
+ end
+
+ button:ClearAllPoints()
+ if i == 1 then
+ button:SetPoint("TOPLEFT", CalendarWeekday1Background, "BOTTOMLEFT", 0, 0)
+ elseif fmod(i, 7) == 1 then
+ button:SetPoint("TOPLEFT", _G["CalendarDayButton"..(i - 7)], "BOTTOMLEFT", 0, -E.Border)
+ else
+ button:SetPoint("TOPLEFT", _G["CalendarDayButton"..(i - 1)], "TOPRIGHT", E.Border, 0)
+ end
+ end
+
+ CalendarTodayFrame:StripTextures()
+ CalendarTodayFrame:SetTemplate("Default")
+ CalendarTodayFrame:Size(CalendarDayButton1:GetWidth(), CalendarDayButton1:GetHeight())
+ CalendarTodayFrame:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
+ local value = E.db.general.valuecolor
+ CalendarTodayFrame:SetBackdropColor(value.r, value.g, value.b, 0.5)
+ CalendarTodayFrame:HookScript("OnUpdate", function(self) self:SetAlpha(CalendarTodayTextureGlow:GetAlpha()) end)
+ CalendarTodayFrame:CreateShadow()
+ CalendarTodayFrame.shadow:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
+
+ CalendarCreateEventFrame:StripTextures()
+ CalendarCreateEventFrame:SetTemplate("Transparent")
+ CalendarCreateEventFrame:Point("TOPLEFT", CalendarFrame, "TOPRIGHT", -3, -7)
+ CalendarCreateEventTitleFrame:StripTextures()
+
+ CalendarCreateEventFrameModalOverlay:SetAllPoints(CalendarCreateEventFrame)
+ CalendarCreateEventFrameModalOverlay:SetFrameStrata("DIALOG")
+ CalendarEventFrameBlocker:SetAllPoints(CalendarCreateEventFrameModalOverlay)
+
+ S:HandleButton(CalendarCreateEventCreateButton, true)
+ S:HandleButton(CalendarCreateEventMassInviteButton, true)
+ S:HandleButton(CalendarCreateEventInviteButton, true)
+ CalendarCreateEventInviteButton:Point("TOPLEFT", CalendarCreateEventInviteEdit, "TOPRIGHT", 4, 1)
+ CalendarCreateEventInviteEdit:Width(CalendarCreateEventInviteEdit:GetWidth() - 2)
+
+ CalendarCreateEventInviteList:StripTextures()
+ CalendarCreateEventInviteList:SetTemplate("Default")
+
+ S:HandleEditBox(CalendarCreateEventInviteEdit)
+ S:HandleEditBox(CalendarCreateEventTitleEdit)
+ S:HandleDropDownBox(CalendarCreateEventTypeDropDown, 157)
+
+ CalendarCreateEventDescriptionContainer:StripTextures()
+ CalendarCreateEventDescriptionContainer:SetTemplate("Default")
+
+ S:HandleCloseButton(CalendarCreateEventCloseButton, CalendarCreateEventFrame)
+
+ S:HandleCheckBox(CalendarCreateEventLockEventCheck)
+
+ S:HandleDropDownBox(CalendarCreateEventHourDropDown, 68)
+ S:HandleDropDownBox(CalendarCreateEventMinuteDropDown, 68)
+ S:HandleDropDownBox(CalendarCreateEventAMPMDropDown, 68)
+ S:HandleDropDownBox(CalendarCreateEventRepeatOptionDropDown, 157)
+
+ CalendarCreateEventIcon:CreateBackdrop()
+ CalendarCreateEventIcon:Point("TOPLEFT", 14, -26)
+ CalendarCreateEventIcon:SetTexCoord(unpack(E.TexCoords))
+ CalendarCreateEventIcon.SetTexCoord = E.noop
+
+ CalendarCreateEventTitleEdit:Size(160, 18)
+ CalendarCreateEventTitleEdit:Point("TOPLEFT", 14, -85)
+
+ CalendarCreateEventTypeDropDown:Point("TOPLEFT", 158, -81)
+
+ CalendarCreateEventHourDropDown:Point("TOPLEFT", -7, -108)
+ CalendarCreateEventMinuteDropDown:Point("LEFT", CalendarCreateEventHourDropDown, "RIGHT", -23, 0)
+ CalendarCreateEventAMPMDropDown:Point("LEFT", CalendarCreateEventMinuteDropDown, "RIGHT", -23, 0)
+
+ CalendarCreateEventRepeatOptionDropDown:Point("TOPLEFT", 158, -108)
+
+ CalendarCreateEventDescriptionContainer:Size(294, 68)
+ CalendarCreateEventDescriptionContainer:Point("TOPLEFT", 13, -138)
+
+ CalendarCreateEventLockEventCheck:Point("TOPRIGHT", -122, 1)
+
+ CalendarCreateEventInviteList:Point("TOP", 0, -43)
+ CalendarCreateEventInviteEdit:Point("TOPLEFT", CalendarCreateEventInviteList, "BOTTOMLEFT", 1, -8)
+ CalendarCreateEventMassInviteButton:Point("BOTTOMLEFT", 13, 13)
+ CalendarCreateEventCreateButton:Point("BOTTOMRIGHT", -13, 13)
+
+ CalendarCreateEventInviteListSection:StripTextures()
+
+ CalendarClassButtonContainer:HookScript("OnShow", function()
+ for i, class in ipairs(CLASS_SORT_ORDER) do
+ local button = _G["CalendarClassButton"..i]
+ button:StripTextures()
+ button:CreateBackdrop("Default")
+ button:Size(23)
+
+ local coords = CLASS_ICON_TCOORDS[class]
+ local buttonIcon = button:GetNormalTexture()
+ buttonIcon:SetTexture("Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Classes")
+ buttonIcon:SetTexCoord(coords[1] + 0.02, coords[2] - 0.02, coords[3] + 0.02, coords[4] - 0.02)
+ end
+
+ CalendarClassButton1:Point("TOPLEFT", 2, 0)
+
+ CalendarClassTotalsButton:StripTextures()
+ CalendarClassTotalsButton:CreateBackdrop("Default")
+ CalendarClassTotalsButton:Size(23)
+ end)
+
+ -- Texture Picker Frame
+ CalendarTexturePickerFrame:StripTextures()
+ CalendarTexturePickerTitleFrame:StripTextures()
+
+ CalendarTexturePickerFrame:SetTemplate("Transparent")
+ CalendarTexturePickerFrame:Width(280)
+ CalendarTexturePickerFrame:ClearAllPoints()
+ CalendarTexturePickerFrame:Point("TOPLEFT", CalendarEventFrameBlocker, "TOPRIGHT", 31, 0)
+
+ S:HandleScrollBar(CalendarTexturePickerScrollBar)
+ S:HandleButton(CalendarTexturePickerAcceptButton, true)
+ S:HandleButton(CalendarTexturePickerCancelButton, true)
+ S:HandleButton(CalendarCreateEventInviteButton, true)
+ S:HandleButton(CalendarCreateEventRaidInviteButton, true)
+
+ for i = 1, 16 do
+ _G["CalendarTexturePickerScrollFrameButton"..i]:StyleButton()
+ end
+
+ CalendarTexturePickerScrollFrame:CreateBackdrop("Transparent")
+ CalendarTexturePickerScrollFrame.backdrop:Point("TOPLEFT", -2, 2)
+ CalendarTexturePickerScrollFrame.backdrop:Point("BOTTOMRIGHT", 2, -4)
+
+ CalendarTexturePickerScrollFrame:Point("TOPLEFT", 10, -20)
+
+ CalendarTexturePickerScrollBar:Point("TOPLEFT", CalendarTexturePickerScrollFrame, "TOPRIGHT", 5, -17)
+ CalendarTexturePickerScrollBar:Point("BOTTOMLEFT", CalendarTexturePickerScrollFrame, "BOTTOMRIGHT", 5, 15)
+
+ CalendarTexturePickerCancelButton:Point("BOTTOMRIGHT", -8, 8)
+
+ -- Mass Invite Frame
+ CalendarMassInviteFrame:StripTextures()
+ CalendarMassInviteFrame:SetTemplate("Transparent")
+
+ S:HandleCloseButton(CalendarMassInviteCloseButton, CalendarMassInviteFrame)
+
+ CalendarMassInviteTitleFrame:StripTextures()
+
+ S:HandleDropDownBox(CalendarMassInviteGuildRankMenu, 140)
+
+ S:HandleEditBox(CalendarMassInviteGuildMinLevelEdit)
+ S:HandleEditBox(CalendarMassInviteGuildMaxLevelEdit)
+
+ S:HandleButton(CalendarMassInviteGuildAcceptButton)
+ S:HandleButton(CalendarMassInviteArenaButton2)
+ S:HandleButton(CalendarMassInviteArenaButton3)
+ S:HandleButton(CalendarMassInviteArenaButton5)
+
+ CalendarMassInviteFrame:Size(307, 179)
+ CalendarMassInviteFrame:ClearAllPoints()
+ CalendarMassInviteFrame:Point("TOPLEFT", CalendarCreateEventFrame, "TOPRIGHT", 31, 0)
+
+ CalendarMassInviteGuildLevelText:Point("TOPLEFT", 40, -53)
+
+ CalendarMassInviteFrameLevelDivider:Point("TOPLEFT", 51, -74)
+ CalendarMassInviteGuildMinLevelEdit:Height(18)
+ CalendarMassInviteGuildMinLevelEdit:Point("TOPLEFT", 20, -72)
+ CalendarMassInviteGuildMaxLevelEdit:Height(18)
+ CalendarMassInviteGuildMaxLevelEdit:Point("TOPLEFT", 65, -72)
+
+ CalendarMassInviteGuildRankText:Point("TOPLEFT", 188, -53)
+ CalendarMassInviteGuildRankMenu:Point("TOPLEFT", 167, -68)
+
+ CalendarMassInviteGuildAcceptButton:Point("TOPRIGHT", -8, -100)
+
+ CalendarMassInviteArenaButton2:Point("TOPLEFT", 8, -149)
+ CalendarMassInviteArenaButton3:Point("TOP", 0, -149)
+ CalendarMassInviteArenaButton5:Point("TOPRIGHT", -8, -149)
+
+ select(6, CalendarMassInviteFrame:GetRegions()):Point("TOP", 0, -130)
+
+ -- Raid View
+ CalendarViewRaidFrame:StripTextures()
+ CalendarViewRaidFrame:SetTemplate("Transparent")
+ CalendarViewRaidFrame:Point("TOPLEFT", CalendarFrame, "TOPRIGHT", -3, -7)
+
+ S:HandleCloseButton(CalendarViewRaidCloseButton, CalendarViewRaidFrame)
+
+ CalendarViewRaidTitleFrame:StripTextures()
+
+ -- Holiday View
+ CalendarViewHolidayFrame:StripTextures(true)
+ CalendarViewHolidayFrame:SetTemplate("Transparent")
+ CalendarViewHolidayFrame:Point("TOPLEFT", CalendarFrame, "TOPRIGHT", -3, -7)
+ CalendarViewHolidayTitleFrame:StripTextures()
+ S:HandleCloseButton(CalendarViewHolidayCloseButton, CalendarViewHolidayFrame)
+
+ -- Event View
+ CalendarViewEventFrame:StripTextures()
+ CalendarViewEventFrame:SetTemplate("Transparent")
+ CalendarViewEventFrame:Point("TOPLEFT", CalendarFrame, "TOPRIGHT", -3, -7)
+
+ S:HandleCloseButton(CalendarViewEventCloseButton, CalendarViewEventFrame)
+
+ CalendarViewEventTitleFrame:StripTextures()
+
+ CalendarViewEventDescriptionContainer:StripTextures()
+ CalendarViewEventDescriptionContainer:SetTemplate("Transparent")
+
+ CalendarViewEventInviteList:StripTextures()
+ CalendarViewEventInviteList:SetTemplate("Transparent")
+ CalendarViewEventInviteListSection:StripTextures()
+
+ S:HandleScrollBar(CalendarViewEventDescriptionScrollFrameScrollBar)
+ S:HandleScrollBar(CalendarViewEventInviteListScrollFrameScrollBar)
+
+ CalendarViewEventFrameModalOverlay:SetAllPoints(CalendarViewEventFrame)
+ CalendarViewEventFrameModalOverlay:SetFrameStrata("DIALOG")
+
+ S:HandleButton(CalendarViewEventAcceptButton)
+ S:HandleButton(CalendarViewEventTentativeButton)
+ S:HandleButton(CalendarViewEventRemoveButton)
+ S:HandleButton(CalendarViewEventDeclineButton)
+
+ CalendarViewEventIcon:CreateBackdrop()
+ CalendarViewEventIcon:SetTexCoord(unpack(E.TexCoords))
+ CalendarViewEventIcon.SetTexCoord = E.noop
+
+ CalendarViewEventDescriptionContainer:Size(294, 68)
+ CalendarViewEventDescriptionContainer:Point("TOPLEFT", 13, -94)
+
+ CalendarViewEventDescriptionScrollFrameScrollBar:Point("TOPLEFT", CalendarViewEventDescriptionScrollFrame, "TOPRIGHT", 4, -15)
+ CalendarViewEventDescriptionScrollFrameScrollBar:Point("BOTTOMLEFT", CalendarViewEventDescriptionScrollFrame, "BOTTOMRIGHT", 4, 15)
+
+ CalendarViewEventInviteListScrollFrameScrollBar:Point("TOPLEFT", CalendarViewEventInviteListScrollFrame, "TOPRIGHT", 7, -16)
+ CalendarViewEventInviteListScrollFrameScrollBar:Point("BOTTOMLEFT", CalendarViewEventInviteListScrollFrame, "BOTTOMRIGHT", 7, 16)
+
+ CalendarViewEventIcon:Point("TOPLEFT", 14, -26)
+
+ CalendarViewEventInviteListSection:Point("TOPLEFT", 0, -177)
+
+ -- Event Picker Frame
+ CalendarEventPickerFrame:StripTextures()
+ CalendarEventPickerTitleFrame:StripTextures()
+
+ CalendarEventPickerFrame:SetTemplate("Transparent")
+ CalendarEventPickerFrame:SetFrameLevel(CalendarFrameModalOverlay:GetFrameLevel() + 10)
+
+ S:HandleScrollBar(CalendarEventPickerScrollBar)
+ S:HandleButton(CalendarEventPickerCloseButton, true)
+
+ CalendarEventPickerScrollFrame:Width(253)
+ CalendarEventPickerScrollFrame:Point("TOPLEFT", 8, -22)
+
+ CalendarEventPickerScrollBar:Point("TOPLEFT", CalendarEventPickerScrollFrame, "TOPRIGHT", 3, -19)
+ CalendarEventPickerScrollBar:Point("BOTTOMLEFT", CalendarEventPickerScrollFrame, "BOTTOMRIGHT", 3, 17)
+
+ CalendarEventPickerCloseButton:Point("BOTTOMRIGHT", -8, 8)
+
+ -- Create Event
+ S:HandleScrollBar(CalendarCreateEventDescriptionScrollFrameScrollBar)
+ S:HandleScrollBar(CalendarCreateEventInviteListScrollFrameScrollBar)
+
+ CalendarCreateEventDescriptionScrollFrameScrollBar:Point("TOPLEFT", CalendarCreateEventDescriptionScrollFrame, "TOPRIGHT", 4, -15)
+ CalendarCreateEventDescriptionScrollFrameScrollBar:Point("BOTTOMLEFT", CalendarCreateEventDescriptionScrollFrame, "BOTTOMRIGHT", 4, 15)
+
+ CalendarCreateEventInviteListScrollFrameScrollBar:Point("TOPLEFT", CalendarCreateEventInviteListScrollFrame, "TOPRIGHT", 7, -16)
+ CalendarCreateEventInviteListScrollFrameScrollBar:Point("BOTTOMLEFT", CalendarCreateEventInviteListScrollFrame, "BOTTOMRIGHT", 7, 16)
+
+ if CalendarCreateEventInviteListScrollFrame.buttons then
+ for _, button in ipairs(CalendarCreateEventInviteListScrollFrame.buttons) do
+ S:HandleButtonHighlight(button)
+ end
+ else
+ CalendarCreateEventInviteList:HookScript("OnEvent", function(self, event)
+ if event == "ADDON_LOADED" then
+ for _, button in ipairs(self.scrollFrame.buttons) do
+ S:HandleButtonHighlight(button)
+ end
+ end
+ end)
+ end
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Character.lua b/ElvUI/Modules/Skins/Blizzard/Character.lua
new file mode 100644
index 0000000..a8947df
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Character.lua
@@ -0,0 +1,810 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local getmetatable = getmetatable
+local ipairs = ipairs
+local select = select
+local unpack = unpack
+local find = string.find
+--WoW API / Variables
+local GetCurrencyListInfo = GetCurrencyListInfo
+local GetInventoryItemQuality = GetInventoryItemQuality
+local GetInventoryItemTexture = GetInventoryItemTexture
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local GetNumFactions = GetNumFactions
+local GetPetHappiness = GetPetHappiness
+local HasPetUI = HasPetUI
+local UnitFactionGroup = UnitFactionGroup
+local hooksecurefunc = hooksecurefunc
+
+local NUM_COMPANIONS_PER_PAGE = NUM_COMPANIONS_PER_PAGE
+local NUM_FACTIONS_DISPLAYED = NUM_FACTIONS_DISPLAYED
+local NUM_GEARSET_ICONS_PER_ROW = NUM_GEARSET_ICONS_PER_ROW
+
+S:AddCallback("Skin_Character", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.character then return end
+
+ -- CharacterFrame
+ CharacterFrame:StripTextures(true)
+ CharacterFrame:CreateBackdrop("Transparent")
+ CharacterFrame.backdrop:Point("TOPLEFT", 11, -12)
+ CharacterFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(CharacterFrame, "width")
+
+ S:SetBackdropHitRect(PaperDollFrame, CharacterFrame.backdrop)
+ S:SetBackdropHitRect(PetPaperDollFrame, CharacterFrame.backdrop)
+ S:SetBackdropHitRect(PetPaperDollFrameCompanionFrame, CharacterFrame.backdrop)
+ S:SetBackdropHitRect(PetPaperDollFramePetFrame, CharacterFrame.backdrop)
+ S:SetBackdropHitRect(ReputationFrame, CharacterFrame.backdrop)
+ S:SetBackdropHitRect(SkillFrame, CharacterFrame.backdrop)
+ S:SetBackdropHitRect(TokenFrame, CharacterFrame.backdrop)
+
+ S:HandleCloseButton(CharacterFrameCloseButton, CharacterFrame.backdrop)
+
+ PaperDollFrame:StripTextures(true)
+
+ for i = 1, #CHARACTERFRAME_SUBFRAMES do
+ S:HandleTab(_G["CharacterFrameTab"..i])
+ end
+
+ hooksecurefunc("PetPaperDollFrame_UpdateIsAvailable", function()
+ if not PetPaperDollFrame.hidden then
+ CharacterFrameTab3:Point("LEFT", "CharacterFrameTab2", "RIGHT", -15, 0)
+ end
+ end)
+
+ -- PaperDollFrame
+ PlayerTitleFrame:StripTextures()
+ PlayerTitleFrame:CreateBackdrop("Default")
+ PlayerTitleFrame.backdrop:Point("TOPLEFT", 20, 3)
+ PlayerTitleFrame.backdrop:Point("BOTTOMRIGHT", -16, 15)
+ PlayerTitleFrame.backdrop:SetFrameLevel(PlayerTitleFrame:GetFrameLevel())
+
+ S:HandleNextPrevButton(PlayerTitleFrameButton)
+ PlayerTitleFrameButton:Size(16)
+ PlayerTitleFrameButton:Point("TOPRIGHT", PlayerTitleFrameRight, "TOPRIGHT", -18, -16)
+
+ PlayerTitlePickerFrame:StripTextures()
+ PlayerTitlePickerFrame:CreateBackdrop("Transparent")
+ PlayerTitlePickerFrame.backdrop:Point("TOPLEFT", 6, -10)
+ PlayerTitlePickerFrame.backdrop:Point("BOTTOMRIGHT", -13, 6)
+ PlayerTitlePickerFrame.backdrop:SetFrameLevel(PlayerTitlePickerFrame:GetFrameLevel())
+
+ S:HandleScrollBar(PlayerTitlePickerScrollFrameScrollBar)
+
+ PlayerTitlePickerScrollFrameScrollBar:Point("TOPLEFT", PlayerTitlePickerScrollFrame, "TOPRIGHT", 1, -14)
+ PlayerTitlePickerScrollFrameScrollBar:Point("BOTTOMLEFT", PlayerTitlePickerScrollFrame, "BOTTOMRIGHT", 1, 15)
+
+ for _, button in ipairs(PlayerTitlePickerScrollFrame.buttons) do
+ button.text:FontTemplate()
+ S:HandleButtonHighlight(button)
+ end
+
+ S:HandleRotateButton(CharacterModelFrameRotateLeftButton)
+ S:HandleRotateButton(CharacterModelFrameRotateRightButton)
+
+ PlayerStatFrameLeftDropDown:Point("BOTTOMLEFT", PlayerStatLeftTop, "TOPLEFT", -19, -8)
+
+ S:HandleDropDownBox(PlayerStatFrameLeftDropDown, 140, "down")
+ S:HandleDropDownBox(PlayerStatFrameRightDropDown, 140, "down")
+
+ CharacterAttributesFrame:StripTextures()
+
+ PaperDollFrameItemFlyoutButtons:EnableMouse(false)
+ PaperDollFrameItemFlyoutHighlight:Kill()
+
+ GearManagerToggleButton:Size(25, 29)
+ GearManagerToggleButton:Point("TOPRIGHT", -46, -40)
+ GearManagerToggleButton:CreateBackdrop("Default")
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 64, 64, 40, 46, 13, 10
+ GearManagerToggleButton:GetNormalTexture():SetTexCoord(0.203125, 0.828125, 0.15625, 0.875)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 64, 64, 40, 46, 12, 12
+ GearManagerToggleButton:GetPushedTexture():SetTexCoord(0.1875, 0.8125, 0.1875, 0.90625)
+ GearManagerToggleButton:GetHighlightTexture():SetTexture(1, 1, 1, 0.3)
+ GearManagerToggleButton:GetHighlightTexture():SetAllPoints()
+
+ PlayerTitleFrame:Point("TOP", CharacterLevelText, "BOTTOM", -7, -7)
+ PlayerTitlePickerFrame:Point("TOPLEFT", PlayerTitleFrame, "BOTTOMLEFT", 14, 26)
+
+ CharacterModelFrame:Size(237, 217)
+ CharacterModelFrame:Point("TOPLEFT", 63, -76)
+
+ CharacterModelFrameRotateLeftButton:Point("TOPLEFT", 4, -4)
+ CharacterModelFrameRotateRightButton:Point("TOPLEFT", CharacterModelFrameRotateLeftButton, "TOPRIGHT", 3, 0)
+
+ CharacterResistanceFrame:Point("TOPRIGHT", PaperDollFrame, "TOPLEFT", 300, -81)
+
+ CharacterHeadSlot:Point("TOPLEFT", 19, -76)
+ CharacterHandsSlot:Point("TOPLEFT", 307, -76)
+ CharacterMainHandSlot:Point("TOPLEFT", PaperDollFrame, "BOTTOMLEFT", 110, 131)
+
+ CharacterAttributesFrame:Point("TOPLEFT", 66, -292)
+
+ local popoutButtonOnEnter = function(self) self.icon:SetVertexColor(unpack(E.media.rgbvaluecolor)) end
+ local popoutButtonOnLeave = function(self) self.icon:SetVertexColor(1, 1, 1) end
+
+ local slots = {
+ [1] = CharacterHeadSlot,
+ [2] = CharacterNeckSlot,
+ [3] = CharacterShoulderSlot,
+ [4] = CharacterShirtSlot,
+ [5] = CharacterChestSlot,
+ [6] = CharacterWaistSlot,
+ [7] = CharacterLegsSlot,
+ [8] = CharacterFeetSlot,
+ [9] = CharacterWristSlot,
+ [10] = CharacterHandsSlot,
+ [11] = CharacterFinger0Slot,
+ [12] = CharacterFinger1Slot,
+ [13] = CharacterTrinket0Slot,
+ [14] = CharacterTrinket1Slot,
+ [15] = CharacterBackSlot,
+ [16] = CharacterMainHandSlot,
+ [17] = CharacterSecondaryHandSlot,
+ [18] = CharacterRangedSlot,
+ [19] = CharacterTabardSlot,
+ [20] = CharacterAmmoSlot, -- 0
+ }
+
+ for i, slotFrame in ipairs(slots) do
+ local slotFrameName = slotFrame:GetName()
+ local icon = _G[slotFrameName.."IconTexture"]
+
+ slotFrame:StripTextures()
+ slotFrame:StyleButton(false)
+ slotFrame:SetTemplate("Default", true, true)
+
+ icon:SetInside()
+ icon:SetTexCoord(unpack(E.TexCoords))
+
+ slotFrame:SetFrameLevel(PaperDollFrame:GetFrameLevel() + 2)
+
+ if i ~= 20 then
+ local cooldown = _G[slotFrameName.."Cooldown"]
+ local popout = _G[slotFrameName.."PopoutButton"]
+
+ E:RegisterCooldown(cooldown)
+
+ popout:StripTextures()
+ popout:HookScript("OnEnter", popoutButtonOnEnter)
+ popout:HookScript("OnLeave", popoutButtonOnLeave)
+
+ popout.icon = popout:CreateTexture(nil, "ARTWORK")
+ popout.icon:Size(24)
+ popout.icon:Point("CENTER")
+ popout.icon:SetTexture(E.Media.Textures.ArrowUp)
+
+ if slotFrame.verticalFlyout then
+ popout.icon:SetRotation(S.ArrowRotation.down)
+ else
+ popout.icon:SetRotation(S.ArrowRotation.right)
+ end
+ end
+ end
+
+ local function updateSlotFrame(self, event, slotID, exist)
+ if event then
+ self = slots[slotID]
+ end
+
+ if exist then
+ local quality = GetInventoryItemQuality("player", slotID)
+
+ if quality then
+ self:SetBackdropBorderColor(GetItemQualityColor(quality))
+ else
+ self:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ else
+ self:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end
+
+ local function colorItemBorder()
+ for _, slotFrame in ipairs(slots) do
+ local slotID = slotFrame:GetID()
+ updateSlotFrame(slotFrame, nil, slotID, GetInventoryItemTexture("player", slotID) ~= nil)
+ end
+ end
+
+ hooksecurefunc(CharacterAmmoSlotIconTexture, "SetTexture", function(self, texture)
+ updateSlotFrame(self:GetParent(), nil, 0, texture ~= "Interface\\PaperDoll\\UI-PaperDoll-Slot-Ranged")
+ end)
+
+ local f = CreateFrame("Frame")
+ f:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
+ f:SetScript("OnEvent", updateSlotFrame)
+
+ CharacterFrame:HookScript("OnShow", colorItemBorder)
+ colorItemBorder()
+
+ local nStripped = 0
+ hooksecurefunc("PaperDollFrameItemFlyout_Show", function()
+ if nStripped < PaperDollFrameItemFlyoutButtons.numBGs then
+ nStripped = PaperDollFrameItemFlyoutButtons.numBGs
+ PaperDollFrameItemFlyoutButtons:StripTextures()
+ end
+ end)
+
+ hooksecurefunc("PaperDollFrameItemPopoutButton_SetReversed", function(self, isReversed)
+ if self:GetParent().verticalFlyout then
+ if isReversed then
+ self.icon:SetRotation(S.ArrowRotation.up)
+ else
+ self.icon:SetRotation(S.ArrowRotation.down)
+ end
+ else
+ if isReversed then
+ self.icon:SetRotation(S.ArrowRotation.left)
+ else
+ self.icon:SetRotation(S.ArrowRotation.right)
+ end
+ end
+ end)
+
+ hooksecurefunc("PaperDollFrameItemFlyout_DisplayButton", function(button)
+ if not button.isSkinned then
+ button.icon = _G[button:GetName().."IconTexture"]
+
+ button:GetNormalTexture():SetTexture(nil)
+ button:SetTemplate("Default")
+ button:StyleButton()
+
+ button.icon:SetInside()
+ button.icon:SetTexCoord(unpack(E.TexCoords))
+
+ E:RegisterCooldown(button.cooldown)
+ end
+
+ if not button.location or button.location >= PDFITEMFLYOUT_FIRST_SPECIAL_LOCATION then return end
+
+ local id = EquipmentManager_GetItemInfoByLocation(button.location)
+ local _, _, quality = GetItemInfo(id)
+
+ button:SetBackdropBorderColor(GetItemQualityColor(quality))
+ end)
+
+ local function handleResistanceFrame(frameName)
+ for i = 1, 5 do
+ local frame = _G[frameName..i]
+ frame:Size(24)
+ frame:SetTemplate("Default")
+
+ if i ~= 1 then
+ frame:ClearAllPoints()
+ frame:Point("TOP", _G[frameName..i-1], "BOTTOM", 0, -(E.Border + E.Spacing))
+ end
+
+ local texture, text = frame:GetRegions()
+
+ texture:SetInside()
+ texture:SetDrawLayer("ARTWORK")
+
+ text:SetDrawLayer("OVERLAY")
+ text:Point("CENTER", -1, 0)
+
+ if i == 1 then -- Arcane
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 32, 256, 18, 18, 8, 64
+ texture:SetTexCoord(0.25, 0.8125, 0.25, 0.3203125)
+ elseif i == 2 then -- Fire
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 32, 256, 18, 18, 8, 6
+ texture:SetTexCoord(0.25, 0.8125, 0.0234375, 0.09375)
+ elseif i == 3 then -- Nature
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 32, 256, 18, 18, 8, 35
+ texture:SetTexCoord(0.25, 0.8125, 0.13671875, 0.20703125)
+ elseif i == 4 then -- Frost
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 32, 256, 18, 18, 8, 94
+ texture:SetTexCoord(0.25, 0.8125, 0.3671875, 0.4375)
+ elseif i == 5 then -- Shadow
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 32, 256, 18, 18, 8, 122
+ texture:SetTexCoord(0.25, 0.8125, 0.4765625, 0.546875)
+ end
+ end
+ end
+
+ handleResistanceFrame("MagicResFrame")
+
+ -- GearManager Dialog
+ GearManagerDialog:StripTextures()
+ GearManagerDialog:CreateBackdrop("Transparent")
+ GearManagerDialog.backdrop:Point("TOPLEFT", 5, -2)
+ GearManagerDialog.backdrop:Point("BOTTOMRIGHT", -3, 4)
+
+ S:SetBackdropHitRect(GearManagerDialog)
+
+ S:HandleCloseButton(GearManagerDialogClose, GearManagerDialog.backdrop)
+
+ for i, button in ipairs(GearManagerDialog.buttons) do
+ button:StripTextures()
+ button:CreateBackdrop("Default")
+ button.backdrop:SetAllPoints()
+
+ button:StyleButton(nil, true)
+
+ button.icon:SetInside()
+ button.icon:SetTexCoord(unpack(E.TexCoords))
+ end
+
+ S:HandleButton(GearManagerDialogDeleteSet)
+ S:HandleButton(GearManagerDialogEquipSet)
+ S:HandleButton(GearManagerDialogSaveSet)
+
+ GearSetButton1:Point("TOPLEFT", 15, -29)
+ GearSetButton6:Point("TOP", GearSetButton1, "BOTTOM", 0, -13)
+
+ GearManagerDialogDeleteSet:Point("BOTTOMLEFT", 11, 12)
+ GearManagerDialogEquipSet:Point("BOTTOMLEFT", 92, 12)
+ GearManagerDialogSaveSet:Point("BOTTOMRIGHT", -10, 12)
+
+ -- GearManager DialogPopup
+ GearManagerDialogPopup:EnableMouse(true)
+ GearManagerDialogPopup:StripTextures()
+ GearManagerDialogPopup:CreateBackdrop("Transparent")
+ GearManagerDialogPopup.backdrop:Point("TOPLEFT", 5, -10)
+ GearManagerDialogPopup.backdrop:Point("BOTTOMRIGHT", -39, 8)
+
+ S:SetBackdropHitRect(GearManagerDialogPopup)
+
+ GearManagerDialogPopupScrollFrame:StripTextures()
+ S:HandleScrollBar(GearManagerDialogPopupScrollFrameScrollBar)
+
+ S:HandleEditBox(GearManagerDialogPopupEditBox)
+
+ for i, button in ipairs(GearManagerDialogPopup.buttons) do
+ button:StripTextures()
+ button:SetFrameLevel(button:GetFrameLevel() + 2)
+ button:CreateBackdrop("Default")
+ button.backdrop:SetAllPoints()
+
+ button:StyleButton(true, true)
+
+ button.icon:SetInside()
+ button.icon:SetTexCoord(unpack(E.TexCoords))
+
+ if i > 1 then
+ local lastPos = (i - 1) / NUM_GEARSET_ICONS_PER_ROW
+
+ if lastPos == math.floor(lastPos) then
+ button:SetPoint("TOPLEFT", GearManagerDialogPopup.buttons[i-NUM_GEARSET_ICONS_PER_ROW], "BOTTOMLEFT", 0, -7)
+ else
+ button:SetPoint("TOPLEFT", GearManagerDialogPopup.buttons[i-1], "TOPRIGHT", 7, 0)
+ end
+ end
+ end
+
+ S:HandleButton(GearManagerDialogPopupOkay)
+ S:HandleButton(GearManagerDialogPopupCancel)
+
+ local text1, text2 = select(5, GearManagerDialogPopup:GetRegions())
+ text1:Point("TOPLEFT", 24, -19)
+ text2:Point("TOPLEFT", 24, -63)
+
+ if GetLocale() == "ruRU" then
+ text1:SetText(string.utf8sub(GEARSETS_POPUP_TEXT, 0, -7) .. "):")
+ end
+
+ GearManagerDialogPopupEditBox:Point("TOPLEFT", 24, -36)
+
+ GearManagerDialogPopupButton1:Point("TOPLEFT", 17, -83)
+
+ GearManagerDialogPopupScrollFrame:SetTemplate("Transparent")
+ GearManagerDialogPopupScrollFrame:Size(216, 130)
+ GearManagerDialogPopupScrollFrame:Point("TOPRIGHT", -68, -79)
+ GearManagerDialogPopupScrollFrameScrollBar:Point("TOPLEFT", GearManagerDialogPopupScrollFrame, "TOPRIGHT", 3, -19)
+ GearManagerDialogPopupScrollFrameScrollBar:Point("BOTTOMLEFT", GearManagerDialogPopupScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ GearManagerDialogPopupOkay:Point("BOTTOMRIGHT", GearManagerDialogPopupCancel, "BOTTOMLEFT", -3, 0)
+ GearManagerDialogPopupCancel:Point("BOTTOMRIGHT", -47, 16)
+
+ -- PetPaperDollFrame
+ PetPaperDollFrame:StripTextures(true)
+
+ for i = 1, 3 do
+ local tab = _G["PetPaperDollFrameTab"..i]
+ tab:StripTextures()
+ tab:CreateBackdrop("Default", true)
+ tab.backdrop:Point("TOPLEFT", 2, -7)
+ tab.backdrop:Point("BOTTOMRIGHT", -1, -1)
+ S:SetBackdropHitRect(tab)
+
+ tab:HookScript("OnEnter", S.SetModifiedBackdrop)
+ tab:HookScript("OnLeave", S.SetOriginalBackdrop)
+ end
+
+ -- PetPaperDollFrame PetFrame
+ S:HandleRotateButton(PetModelFrameRotateLeftButton)
+ S:HandleRotateButton(PetModelFrameRotateRightButton)
+
+ handleResistanceFrame("PetMagicResFrame")
+
+ PetAttributesFrame:StripTextures()
+
+ PetPaperDollFrameExpBar:StripTextures()
+ PetPaperDollFrameExpBar:CreateBackdrop("Default")
+ PetPaperDollFrameExpBar:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(PetPaperDollFrameExpBar)
+
+ S:HandleButton(PetPaperDollCloseButton)
+
+ local function updateHappiness(self)
+ local _, isHunterPet = HasPetUI()
+ local happiness = GetPetHappiness()
+ if not isHunterPet or not happiness then return end
+
+ if happiness == 1 then
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 128, 64, 16, 16, 52, 4
+ self:GetRegions():SetTexCoord(0.40625, 0.53125, 0.0625, 0.3125)
+ elseif happiness == 2 then
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 128, 64, 16, 16, 28, 4
+ self:GetRegions():SetTexCoord(0.21875, 0.34375, 0.0625, 0.3125)
+ elseif happiness == 3 then
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 128, 64, 16, 16, 52, 4
+ self:GetRegions():SetTexCoord(0.03125, 0.15625, 0.0625, 0.3125)
+ end
+ end
+
+ PetModelFrame:Width(325)
+ PetModelFrame:Point("TOPLEFT", 19, -71)
+
+ PetModelFrameRotateLeftButton:Point("TOPLEFT", PetPaperDollFrame, "TOPLEFT", 23, -75)
+ PetModelFrameRotateRightButton:Point("TOPLEFT", PetModelFrameRotateLeftButton, "TOPRIGHT", 3, 0)
+
+ PetResistanceFrame:Point("TOPRIGHT", PetPaperDollFrame, "TOPLEFT", 344, -75)
+
+ PetPaperDollPetInfo:SetFrameLevel(PetModelFrame:GetFrameLevel() + 2)
+ PetPaperDollPetInfo:CreateBackdrop("Default")
+ PetPaperDollPetInfo:Size(25)
+ PetPaperDollPetInfo:Point("TOPLEFT", PetModelFrameRotateLeftButton, "BOTTOMLEFT", 10, -4)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 128, 64, 16, 16, 52, 4
+ PetPaperDollPetInfo:GetRegions():SetTexCoord(0.03125, 0.15625, 0.0625, 0.3125)
+
+ PetPaperDollPetInfo:RegisterEvent("UNIT_HAPPINESS")
+ PetPaperDollPetInfo:SetScript("OnEvent", updateHappiness)
+ PetPaperDollPetInfo:SetScript("OnShow", updateHappiness)
+ updateHappiness(PetPaperDollPetInfo)
+
+ PetLevelText:Point("CENTER", 0, -50)
+ PetAttributesFrame:Point("TOPLEFT", 67, -310)
+
+ PetPaperDollFrameExpBar:Width(323)
+ PetPaperDollFrameExpBar:Point("BOTTOMLEFT", 20, 112)
+
+ PetPaperDollCloseButton:Point("CENTER", PetPaperDollFramePetFrame, "TOPLEFT", 304, -417)
+
+ -- PetPaperDollFrame CompanionFrame
+ PetPaperDollFrameCompanionFrame:StripTextures()
+
+ S:HandleRotateButton(CompanionModelFrameRotateLeftButton)
+ S:HandleRotateButton(CompanionModelFrameRotateRightButton)
+
+ S:HandleButton(CompanionSummonButton)
+
+ S:HandleNextPrevButton(CompanionPrevPageButton)
+ S:HandleNextPrevButton(CompanionNextPageButton)
+
+ hooksecurefunc("PetPaperDollFrame_UpdateCompanions", function()
+ for i = 1, NUM_COMPANIONS_PER_PAGE do
+ local button = _G["CompanionButton"..i]
+
+ if button.creatureID then
+ local iconNormal = button:GetNormalTexture()
+ iconNormal:SetTexCoord(unpack(E.TexCoords))
+ iconNormal:SetInside()
+ end
+ end
+ end)
+
+ for i = 1, NUM_COMPANIONS_PER_PAGE do
+ local button = _G["CompanionButton"..i]
+ local iconDisabled = button:GetDisabledTexture()
+ local activeTexture = _G["CompanionButton"..i.."ActiveTexture"]
+
+ button:StyleButton(nil, true)
+ button:SetTemplate("Default", true)
+
+ iconDisabled:SetAlpha(0)
+
+ activeTexture:SetInside(button)
+ activeTexture:SetTexture(1, 1, 1, .15)
+
+ if i == 7 then
+ button:Point("TOP", CompanionButton1, "BOTTOM", 0, -5)
+ elseif i ~= 1 then
+ button:Point("LEFT", _G["CompanionButton"..i-1], "RIGHT", 5, 0)
+ end
+ end
+
+ CompanionModelFrame:Size(325, 174)
+ CompanionModelFrame:Point("TOPLEFT", 19, -71)
+
+ CompanionModelFrameRotateLeftButton:Point("TOPLEFT", PetPaperDollFrame, "TOPLEFT", 23, -75)
+ CompanionModelFrameRotateRightButton:Point("TOPLEFT", CompanionModelFrameRotateLeftButton, "TOPRIGHT", 3, 0)
+
+ CompanionButton1:Point("TOPLEFT", 58, -308)
+
+ CompanionSummonButton:Width(149)
+ CompanionSummonButton:Point("CENTER", -11, -24)
+
+ CompanionPrevPageButton:Point("BOTTOMLEFT", 122, 92)
+ CompanionNextPageButton:Point("LEFT", CompanionPrevPageButton, "RIGHT", 83, 0)
+
+ CompanionPageNumber:Point("CENTER", -10, -155)
+
+ -- Reputation Frame
+ ReputationFrame:StripTextures(true)
+
+ for i = 1, NUM_FACTIONS_DISPLAYED do
+ local factionRow = _G["ReputationBar"..i]
+ local factionBar = _G["ReputationBar"..i.."ReputationBar"]
+ local factionButton = _G["ReputationBar"..i.."ExpandOrCollapseButton"]
+
+ factionRow:StripTextures(true)
+
+ factionBar:StripTextures()
+ factionBar:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(factionBar)
+ factionBar:CreateBackdrop("Default")
+
+ factionButton:SetNormalTexture(E.Media.Textures.Minus)
+ factionButton.SetNormalTexture = E.noop
+ factionButton:GetNormalTexture():Size(15)
+ factionButton:SetHighlightTexture(nil)
+ end
+
+ hooksecurefunc("ReputationFrame_Update", function()
+ local factionOffset = FauxScrollFrame_GetOffset(ReputationListScrollFrame)
+ local numFactions = GetNumFactions()
+ local factionIndex, factionButton
+
+ for i = 1, NUM_FACTIONS_DISPLAYED do
+ factionIndex = factionOffset + i
+
+ if factionIndex <= numFactions then
+ factionButton = _G["ReputationBar"..i.."ExpandOrCollapseButton"]
+
+ if _G["ReputationBar"..i].isCollapsed then
+ factionButton:GetNormalTexture():SetTexture(E.Media.Textures.Plus)
+ else
+ factionButton:GetNormalTexture():SetTexture(E.Media.Textures.Minus)
+ end
+ end
+ end
+ end)
+
+ ReputationListScrollFrame:StripTextures()
+ S:HandleScrollBar(ReputationListScrollFrameScrollBar)
+
+ ReputationFrameFactionLabel:Point("TOPLEFT", 70, -60)
+ ReputationFrameStandingLabel:Point("TOPLEFT", 235, -60)
+
+ ReputationBar1:Point("TOPRIGHT", -51, -81)
+
+ ReputationListScrollFrame:Width(304)
+ ReputationListScrollFrame:Point("TOPRIGHT", -61, -74)
+ ReputationListScrollFrameScrollBar:Point("TOPLEFT", ReputationListScrollFrame, "TOPRIGHT", 3, -19)
+ ReputationListScrollFrameScrollBar:Point("BOTTOMLEFT", ReputationListScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ ReputationListScrollFrame:SetScript("OnShow", function()
+ ReputationBar1:Point("TOPRIGHT", -75, -81)
+ end)
+ ReputationListScrollFrame:SetScript("OnHide", function()
+ ReputationBar1:Point("TOPRIGHT", -51, -81)
+ end)
+
+ -- Reputation DetailFrame
+ ReputationDetailFrame:StripTextures()
+ ReputationDetailFrame:SetTemplate("Transparent")
+ ReputationDetailFrame:Point("TOPLEFT", ReputationFrame, "TOPRIGHT", -33, -12)
+
+ S:HandleCloseButton(ReputationDetailCloseButton, ReputationDetailFrame)
+
+ S:HandleCheckBox(ReputationDetailAtWarCheckBox)
+ ReputationDetailAtWarCheckBox:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-SwordCheck")
+ S:HandleCheckBox(ReputationDetailInactiveCheckBox)
+ S:HandleCheckBox(ReputationDetailMainScreenCheckBox)
+
+ -- Skill Frame
+ SkillFrame:StripTextures(true)
+
+ SkillFrameExpandButtonFrame:StripTextures()
+
+ SkillFrameCollapseAllButton:SetNormalTexture(E.Media.Textures.Plus)
+ SkillFrameCollapseAllButton.SetNormalTexture = E.noop
+ SkillFrameCollapseAllButton:GetNormalTexture():Size(16)
+ SkillFrameCollapseAllButton:SetHighlightTexture(nil)
+
+ hooksecurefunc(SkillFrameCollapseAllButton, "SetNormalTexture", function(self, texture)
+ if find(texture, "MinusButton") then
+ SkillFrameCollapseAllButton:GetNormalTexture():SetTexture(E.Media.Textures.Minus)
+ else
+ SkillFrameCollapseAllButton:GetNormalTexture():SetTexture(E.Media.Textures.Plus)
+ end
+ end)
+
+ for i = 1, SKILLS_TO_DISPLAY do
+ local statusBar = _G["SkillRankFrame"..i]
+ local statusBarBorder = _G["SkillRankFrame"..i.."Border"]
+ local statusBarBackground = _G["SkillRankFrame"..i.."Background"]
+ local skillTypeLabelText = _G["SkillTypeLabel"..i]
+
+ statusBar:Width(276)
+ statusBar:CreateBackdrop("Default")
+ statusBar:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(statusBar)
+
+ statusBarBorder:StripTextures()
+ statusBarBackground:SetTexture(nil)
+
+ skillTypeLabelText:SetNormalTexture(E.Media.Textures.Plus)
+ skillTypeLabelText.SetNormalTexture = E.noop
+ skillTypeLabelText:GetNormalTexture():Size(16)
+ skillTypeLabelText:SetHighlightTexture(nil)
+
+ hooksecurefunc(skillTypeLabelText, "SetNormalTexture", function(self, texture)
+ if find(texture, "MinusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Minus)
+ else
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Plus)
+ end
+ end)
+ end
+
+ SkillDetailStatusBar:StripTextures()
+ SkillDetailStatusBar:SetParent(SkillDetailScrollFrame)
+ SkillDetailStatusBar:CreateBackdrop("Default")
+ SkillDetailStatusBar:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(SkillDetailStatusBar)
+
+ S:HandleCloseButton(SkillDetailStatusBarUnlearnButton)
+ SkillDetailStatusBarUnlearnButton:SetPoint("LEFT", SkillDetailStatusBarBorder, "RIGHT")
+ SkillDetailStatusBarUnlearnButton.Texture:Size(16)
+ SkillDetailStatusBarUnlearnButton.Texture:SetVertexColor(1, 0, 0)
+ SkillDetailStatusBarUnlearnButton:HookScript("OnEnter", function(btn) btn.Texture:SetVertexColor(1, 1, 1) end)
+ SkillDetailStatusBarUnlearnButton:HookScript("OnLeave", function(btn) btn.Texture:SetVertexColor(1, 0, 0) end)
+
+ SkillListScrollFrame:StripTextures()
+ S:HandleScrollBar(SkillListScrollFrameScrollBar)
+
+ SkillDetailScrollFrame:StripTextures()
+ S:HandleScrollBar(SkillDetailScrollFrameScrollBar)
+
+ S:HandleButton(SkillFrameCancelButton)
+
+ SkillFrameExpandButtonFrame:Point("TOPLEFT", 30, -50)
+
+ SkillTypeLabel1:Point("LEFT", SkillFrame, "TOPLEFT", 22, -85)
+ SkillRankFrame1:Point("TOPLEFT", 38, -78)
+
+ SkillListScrollFrame:Width(304)
+ SkillListScrollFrame:Point("TOPRIGHT", -61, -74)
+
+ SkillListScrollFrameScrollBar:Point("TOPLEFT", SkillListScrollFrame, "TOPRIGHT", 3, -19)
+ SkillListScrollFrameScrollBar:Point("BOTTOMLEFT", SkillListScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ SkillDetailScrollFrame:Size(304, 98)
+ SkillDetailScrollFrame:Point("TOPLEFT", SkillListScrollFrame, "BOTTOMLEFT", 0, -7)
+
+ SkillDetailScrollFrameScrollBar:Point("TOPLEFT", SkillDetailScrollFrame, "TOPRIGHT", 3, -19)
+ SkillDetailScrollFrameScrollBar:Point("BOTTOMLEFT", SkillDetailScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ SkillFrameCancelButton:Point("CENTER", SkillFrame, "TOPLEFT", 304, -417)
+
+ -- Token Frame
+ TokenFrame:StripTextures(true)
+
+ select(4, TokenFrame:GetChildren()):Hide()
+
+ S:HandleScrollBar(TokenFrameContainerScrollBar)
+
+ S:HandleButton(TokenFrameCancelButton)
+
+ TokenFrameContainer:Size(304, 360)
+ TokenFrameContainer:Point("TOPLEFT", 19, -39)
+
+ TokenFrameContainerScrollBar:Point("TOPLEFT", TokenFrameContainer, "TOPRIGHT", 3, -19)
+ TokenFrameContainerScrollBar:Point("BOTTOMLEFT", TokenFrameContainer, "BOTTOMRIGHT", 3, 19)
+
+ TokenFrameMoneyFrame:Point("BOTTOMRIGHT", -115, 88)
+
+ TokenFrameCancelButton:Point("CENTER", TokenFrame, "TOPLEFT", 304, -417)
+
+ TokenFrameContainerScrollBar.Show = function(self)
+ TokenFrameContainer:SetWidth(304)
+ for _, button in ipairs(TokenFrameContainer.buttons) do
+ button:SetWidth(300)
+ end
+ getmetatable(self).__index.Show(self)
+ end
+
+ TokenFrameContainerScrollBar.Hide = function(self)
+ TokenFrameContainer:SetWidth(325)
+ for _, button in ipairs(TokenFrameContainer.buttons) do
+ button:SetWidth(325)
+ end
+ getmetatable(self).__index.Hide(self)
+ end
+
+ local function skinTokenButton(button)
+ if not button.isSkinned then
+ button.categoryLeft:Kill()
+ button.categoryRight:Kill()
+ button.highlight:Kill()
+
+ button.expandIcon:Size(16)
+ button.expandIcon:SetTexCoord(0, 1, 0, 1)
+ button.expandIcon.SetTexCoord = E.noop
+
+ button.isSkinned = true
+ end
+ end
+
+ local tokenSkinned = 0
+
+ local function updateTokenContainer()
+ local offset = HybridScrollFrame_GetOffset(TokenFrameContainer)
+ local buttons = TokenFrameContainer.buttons
+ local numButtons = #buttons
+ local index, button
+ local _, name, isHeader, isExpanded, extraCurrencyType, icon
+
+ if numButtons > tokenSkinned then
+ for i = tokenSkinned + 1, numButtons do
+ skinTokenButton(TokenFrameContainer.buttons[i])
+ end
+
+ tokenSkinned = numButtons
+ end
+
+ for i = 1, numButtons do
+ index = offset + i
+ button = buttons[i]
+
+ name, isHeader, isExpanded, _, _, _, extraCurrencyType, icon = GetCurrencyListInfo(index)
+
+ if name then
+ if isHeader then
+ if isExpanded then
+ button.expandIcon:SetTexture(E.Media.Textures.Minus)
+ else
+ button.expandIcon:SetTexture(E.Media.Textures.Plus)
+ end
+ else
+ if extraCurrencyType == 1 then
+ button.icon:SetTexCoord(unpack(E.TexCoords))
+ elseif extraCurrencyType == 2 then
+ local factionGroup = UnitFactionGroup("player")
+
+ if factionGroup then
+ button.icon:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..factionGroup)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 64, 64, 36, 36, 4, 1
+ button.icon:SetTexCoord(0.0625, 0.625, 0.015625, 0.578125)
+ else
+ button.icon:SetTexCoord(unpack(E.TexCoords))
+ end
+ else
+ button.icon:SetTexture(icon)
+ button.icon:SetTexCoord(unpack(E.TexCoords))
+ end
+ end
+ end
+ end
+ end
+
+ hooksecurefunc("TokenFrame_Update", updateTokenContainer)
+ hooksecurefunc(TokenFrameContainer, "update", updateTokenContainer)
+
+ -- Token Frame Popup
+ TokenFramePopup:StripTextures()
+ TokenFramePopup:SetTemplate("Transparent")
+
+ S:HandleCloseButton(TokenFramePopupCloseButton, TokenFramePopup)
+
+ S:HandleCheckBox(TokenFramePopupInactiveCheckBox)
+ S:HandleCheckBox(TokenFramePopupBackpackCheckBox)
+
+ TokenFramePopup:Point("TOPLEFT", TokenFrame, "TOPRIGHT", -33, -12)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Debug.lua b/ElvUI/Modules/Skins/Blizzard/Debug.lua
new file mode 100644
index 0000000..ebf2dd7
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Debug.lua
@@ -0,0 +1,60 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local unpack = unpack
+--WoW API / Variables
+
+S:AddCallbackForAddon("Blizzard_DebugTools", "Skin_Blizzard_DebugTools", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.debug then return end
+
+ ScriptErrorsFrame:SetParent(E.UIParent)
+ ScriptErrorsFrame:StripTextures()
+ ScriptErrorsFrame:SetTemplate("Transparent")
+
+ S:HandleScrollBar(ScriptErrorsFrameScrollFrameScrollBar)
+ S:HandleCloseButton(ScriptErrorsFrameClose, ScriptErrorsFrame)
+
+ ScriptErrorsFrameScrollFrameText:FontTemplate(nil, 13)
+ ScriptErrorsFrameScrollFrameText:Width(461)
+
+ ScriptErrorsFrameScrollFrame:CreateBackdrop("Default")
+ ScriptErrorsFrameScrollFrame.backdrop:Point("BOTTOMRIGHT", 1, -2)
+ ScriptErrorsFrameScrollFrame:SetFrameLevel(ScriptErrorsFrameScrollFrame:GetFrameLevel() + 2)
+ ScriptErrorsFrameScrollFrame:Width(461)
+ ScriptErrorsFrameScrollFrame:Point("TOPLEFT", 9, -30)
+
+ ScriptErrorsFrameScrollFrameScrollBar:Point("TOPLEFT", ScriptErrorsFrameScrollFrame, "TOPRIGHT", 4, -18)
+ ScriptErrorsFrameScrollFrameScrollBar:Point("BOTTOMLEFT", ScriptErrorsFrameScrollFrame, "BOTTOMRIGHT", 4, 17)
+
+ EventTraceFrame:StripTextures()
+ EventTraceFrame:SetTemplate("Transparent")
+ S:HandleSliderFrame(EventTraceFrameScroll)
+
+ for i = 1, ScriptErrorsFrame:GetNumChildren() do
+ local child = select(i, ScriptErrorsFrame:GetChildren())
+ if child:GetObjectType() == "Button" and not child:GetName() then
+ S:HandleButton(child)
+ end
+ end
+
+ FrameStackTooltip:HookScript("OnShow", function(self)
+ local noscalemult = E.mult * GetCVar("uiScale")
+
+ self:SetBackdrop({
+ bgFile = E.media.blankTex,
+ edgeFile = E.media.blankTex,
+ tile = false, tileSize = 0, edgeSize = noscalemult,
+ insets = {left = -noscalemult, right = -noscalemult, top = -noscalemult, bottom = -noscalemult}
+ })
+
+ self:SetBackdropColor(unpack(E.media.backdropfadecolor))
+ self:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end)
+
+ EventTraceTooltip:HookScript("OnShow", function(self)
+ self:SetTemplate("Transparent")
+ end)
+
+ S:HandleCloseButton(EventTraceFrameCloseButton, EventTraceFrame)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/DressingRoom.lua b/ElvUI/Modules/Skins/Blizzard/DressingRoom.lua
new file mode 100644
index 0000000..a3900af
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/DressingRoom.lua
@@ -0,0 +1,50 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallback("Skin_DressingRoom", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.dressingroom then return end
+
+ DressUpFrame:StripTextures()
+ DressUpFrame:CreateBackdrop("Transparent")
+ DressUpFrame.backdrop:Point("TOPLEFT", 11, -12)
+ DressUpFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(DressUpFrame, "width")
+ S:SetBackdropHitRect(DressUpFrame)
+
+ DressUpFramePortrait:Kill()
+
+ SetDressUpBackground()
+ DressUpBackgroundTopLeft:SetDesaturated(true)
+ DressUpBackgroundTopRight:SetDesaturated(true)
+ DressUpBackgroundBotLeft:SetDesaturated(true)
+ DressUpBackgroundBotRight:SetDesaturated(true)
+
+ S:HandleCloseButton(DressUpFrameCloseButton, DressUpFrame.backdrop)
+
+ S:HandleRotateButton(DressUpModelRotateLeftButton)
+ S:HandleRotateButton(DressUpModelRotateRightButton)
+
+ S:HandleButton(DressUpFrameCancelButton)
+ S:HandleButton(DressUpFrameResetButton)
+
+ DressUpModel:CreateBackdrop("Default")
+ DressUpModel.backdrop:SetOutside(DressUpModel)
+
+ DressUpFrameDescriptionText:Point("CENTER", DressUpFrameTitleText, "BOTTOM", 10, -18)
+
+ DressUpModelRotateLeftButton:Point("TOPLEFT", DressUpFrame, 29, -76)
+ DressUpModelRotateRightButton:Point("TOPLEFT", DressUpModelRotateLeftButton, "TOPRIGHT", 3, 0)
+
+ DressUpModel:Size(323, 331)
+ DressUpModel:ClearAllPoints()
+ DressUpModel:Point("TOPLEFT", 20, -67)
+
+ DressUpBackgroundTopLeft:Point("TOPLEFT", 23, -67)
+
+ DressUpFrameCancelButton:Point("CENTER", DressUpFrame, "TOPLEFT", 304, -417)
+ DressUpFrameResetButton:Point("RIGHT", DressUpFrameCancelButton, "LEFT", -3, 0)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Friends.lua b/ElvUI/Modules/Skins/Blizzard/Friends.lua
new file mode 100644
index 0000000..8e4d9be
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Friends.lua
@@ -0,0 +1,685 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local ipairs = ipairs
+local unpack = unpack
+--WoW API / Variables
+local GetGuildRosterInfo = GetGuildRosterInfo
+local GetNumRaidMembers = GetNumRaidMembers
+local GetNumWhoResults = GetNumWhoResults
+local GetWhoInfo = GetWhoInfo
+local PlaySound = PlaySound
+
+local GUILDMEMBERS_TO_DISPLAY = GUILDMEMBERS_TO_DISPLAY
+local WHOS_TO_DISPLAY = WHOS_TO_DISPLAY
+
+S:AddCallback("Skin_Friends", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.friends then return end
+
+ -- Friends Frame
+ FriendsFrame:StripTextures(true)
+ FriendsFrame:CreateBackdrop("Transparent")
+ FriendsFrame.backdrop:Point("TOPLEFT", 11, -12)
+ FriendsFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(FriendsFrame, "width")
+ S:SetBackdropHitRect(FriendsFrame)
+
+ S:HandleCloseButton(FriendsFrameCloseButton, FriendsFrame.backdrop)
+
+ S:HandleDropDownBox(FriendsFrameStatusDropDown, 70)
+
+ S:HandleEditBox(FriendsFrameBroadcastInput)
+
+ for i = 1, 2 do
+ local tab = _G["FriendsTabHeaderTab"..i]
+ tab:StripTextures()
+ tab:CreateBackdrop("Default", true)
+ tab.backdrop:Point("TOPLEFT", 3, -7)
+ tab.backdrop:Point("BOTTOMRIGHT", -2, -1)
+
+ tab:HookScript("OnEnter", S.SetModifiedBackdrop)
+ tab:HookScript("OnLeave", S.SetOriginalBackdrop)
+ end
+
+ for i = 1, 5 do
+ S:HandleTab(_G["FriendsFrameTab"..i])
+ end
+
+ FriendsFrameStatusDropDown:Point("TOPLEFT", FriendsListFrame, "TOPLEFT", 0, -37)
+
+ FriendsFrameStatusDropDownMouseOver:Size(22, 18)
+ FriendsFrameStatusDropDownMouseOver:Point("TOPLEFT", 21, -4)
+
+ FriendsFrameStatusDropDownStatus:Point("LEFT", 25, 3)
+
+ FriendsFrameBroadcastInput:Width(241)
+ FriendsFrameBroadcastInput:Point("TOPLEFT", FriendsFrameStatusDropDown, "TOPRIGHT", 11, -3)
+
+ FriendsTabHeaderTab1:Point("TOPLEFT", 30, -60)
+
+ -- Friends List Frame
+ for i = 1, FRIENDS_FRIENDS_TO_DISPLAY do
+ _G["FriendsFrameFriendsScrollFrameButton"..i.."SummonButton"]:StyleButton()
+ _G["FriendsFrameFriendsScrollFrameButton"..i.."SummonButtonIcon"]:SetTexCoord(unpack(E.TexCoords))
+ _G["FriendsFrameFriendsScrollFrameButton"..i.."SummonButtonNormalTexture"]:SetAlpha(0)
+ end
+
+ S:HandleScrollBar(FriendsFrameFriendsScrollFrameScrollBar)
+
+ S:HandleButton(FriendsFrameAddFriendButton, true)
+ S:HandleButton(FriendsFrameSendMessageButton, true)
+
+ FriendsFrameFriendsScrollFrame:Width(304)
+ FriendsFrameFriendsScrollFrame:Point("TOPLEFT", FriendsFrame, 19, -92)
+
+ FriendsFrameFriendsScrollFrameScrollBar:Point("TOPRIGHT", FriendsFrame, "TOPRIGHT", -40, -111)
+ FriendsFrameFriendsScrollFrameScrollBar:Point("BOTTOMLEFT", FriendsFrameFriendsScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ FriendsFrameAddFriendButton:Height(22)
+ FriendsFrameAddFriendButton:Point("BOTTOMLEFT", FriendsFrame, 19, 84)
+
+ FriendsFrameSendMessageButton:Height(22)
+ FriendsFrameSendMessageButton:Point("BOTTOMRIGHT", FriendsFrame, -40, 84)
+
+ -- Ignore List Frame
+ S:HandleScrollBar(FriendsFrameIgnoreScrollFrameScrollBar)
+
+ S:HandleButton(FriendsFrameIgnorePlayerButton, true)
+ S:HandleButton(FriendsFrameUnsquelchButton, true)
+
+ for i = 1, IGNORES_TO_DISPLAY do
+ S:HandleButtonHighlight(_G["FriendsFrameIgnoreButton"..i])
+ end
+
+ FriendsFrameIgnoreButton1:Point("TOPLEFT", FriendsFrame, "TOPLEFT", 22, -95)
+
+ FriendsFrameIgnoreScrollFrame:Width(304)
+ FriendsFrameIgnoreScrollFrame:Point("TOPRIGHT", FriendsFrame, "TOPRIGHT", -61, -92)
+
+ FriendsFrameIgnoreScrollFrameScrollBar:Point("TOPLEFT", FriendsFrameIgnoreScrollFrame, "TOPRIGHT", 3, -19)
+ FriendsFrameIgnoreScrollFrameScrollBar:Point("BOTTOMLEFT", FriendsFrameIgnoreScrollFrame, "BOTTOMRIGHT", 3, 21)
+
+ FriendsFrameIgnorePlayerButton:Height(22)
+ FriendsFrameIgnorePlayerButton:Point("BOTTOMLEFT", FriendsFrame, 19, 84)
+
+ FriendsFrameUnsquelchButton:Height(22)
+ FriendsFrameUnsquelchButton:Point("BOTTOMRIGHT", FriendsFrame, -40, 84)
+
+ -- Who Frame
+ S:HandleDropDownBox(WhoFrameDropDown)
+ S:SetBackdropHitRect(WhoFrameDropDown)
+
+ for i = 1, 4 do
+ local header = _G["WhoFrameColumnHeader"..i]
+ header:StripTextures()
+ header:StyleButton()
+ end
+
+ for i = 1, WHOS_TO_DISPLAY do
+ local button = _G["WhoFrameButton"..i]
+ local level = _G["WhoFrameButton"..i.."Level"]
+ local name = _G["WhoFrameButton"..i.."Name"]
+ local class = _G["WhoFrameButton"..i.."Class"]
+
+ button.icon = button:CreateTexture("$parentIcon", "ARTWORK")
+ button.icon:Size(15)
+ button.icon:Point("LEFT", 45, 0)
+ button.icon:SetTexture("Interface\\WorldStateFrame\\Icons-Classes")
+
+ button:CreateBackdrop("Default", true)
+ button.backdrop:SetAllPoints(button.icon)
+ S:HandleButtonHighlight(button)
+
+ level:ClearAllPoints()
+ level:SetPoint("TOPLEFT", 11, -1)
+
+ name:Size(100, 14)
+ name:ClearAllPoints()
+ name:Point("LEFT", 85, 0)
+
+ class:Hide()
+ end
+
+ WhoListScrollFrame:StripTextures()
+ S:HandleScrollBar(WhoListScrollFrameScrollBar)
+
+ S:HandleEditBox(WhoFrameEditBox)
+
+ S:HandleButton(WhoFrameWhoButton)
+ S:HandleButton(WhoFrameAddFriendButton)
+ S:HandleButton(WhoFrameGroupInviteButton)
+
+ WhoFrameColumnHeader3:ClearAllPoints()
+ WhoFrameColumnHeader3:Point("TOPLEFT", 20, -48)
+
+ WhoFrameColumnHeader4:ClearAllPoints()
+ WhoFrameColumnHeader4:Point("LEFT", WhoFrameColumnHeader3, "RIGHT", -2, 0)
+ WhoFrameColumn_SetWidth(WhoFrameColumnHeader4, 48)
+
+ WhoFrameColumnHeader1:ClearAllPoints()
+ WhoFrameColumnHeader1:Point("LEFT", WhoFrameColumnHeader4, "RIGHT", -2, 0)
+ WhoFrameColumn_SetWidth(WhoFrameColumnHeader1, 105)
+
+ WhoFrameColumnHeader2:ClearAllPoints()
+ WhoFrameColumnHeader2:Point("LEFT", WhoFrameColumnHeader1, "RIGHT", -6, 1)
+
+ WhoFrameButton1:Point("TOPLEFT", 17, -75)
+
+ WhoListScrollFrame:Size(304, 284)
+ WhoListScrollFrame:Point("TOPRIGHT", FriendsFrame, "TOPRIGHT", -61, -71)
+
+ WhoListScrollFrameScrollBar:Point("TOPLEFT", WhoListScrollFrame, "TOPRIGHT", 3, -19)
+ WhoListScrollFrameScrollBar:Point("BOTTOMLEFT", WhoListScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ WhoFrameTotals:Point("BOTTOM", -10, 137)
+
+ WhoFrameEditBox:Size(323, 18)
+ WhoFrameEditBox:Point("BOTTOM", -11, 114)
+
+ WhoFrameGroupInviteButton:Width(117)
+ WhoFrameAddFriendButton:Width(117)
+ WhoFrameGroupInviteButton:Point("BOTTOMRIGHT", -40, 84)
+ WhoFrameAddFriendButton:Point("RIGHT", WhoFrameGroupInviteButton, "LEFT", -3, 0)
+ WhoFrameWhoButton:Point("RIGHT", WhoFrameAddFriendButton, "LEFT", -3, 0)
+
+ hooksecurefunc("WhoList_Update", function()
+ local numWhos = GetNumWhoResults()
+ if numWhos == 0 then return end
+
+ numWhos = numWhos > WHOS_TO_DISPLAY and WHOS_TO_DISPLAY or numWhos
+
+ local _, level, classFileName
+ local button, buttonText, classTextColor, levelTextColor
+
+ for i = 1, numWhos do
+ button = _G["WhoFrameButton"..i]
+ _, _, level, _, _, _, classFileName = GetWhoInfo(button.whoIndex)
+
+ if classFileName then
+ classTextColor = E.media.herocolor
+ button.icon:Show()
+ button.icon:SetTexCoord(unpack(CLASS_ICON_TCOORDS[classFileName]))
+ else
+ classTextColor = HIGHLIGHT_FONT_COLOR
+ button.icon:Hide()
+ end
+
+ levelTextColor = GetQuestDifficultyColor(level)
+
+ buttonText = _G["WhoFrameButton"..i.."Name"]
+ buttonText:SetTextColor(classTextColor.r, classTextColor.g, classTextColor.b)
+ buttonText = _G["WhoFrameButton"..i.."Level"]
+ buttonText:SetTextColor(levelTextColor.r, levelTextColor.g, levelTextColor.b)
+ buttonText = _G["WhoFrameButton"..i.."Class"]
+ buttonText:SetTextColor(1.0, 1.0, 1.0)
+ end
+ end)
+
+ -- Guild Frame
+ S:HandleCheckBox(GuildFrameLFGButton)
+
+ GuildFrameLFGFrame:StripTextures()
+ GuildFrameLFGFrame:SetTemplate("Default")
+
+ GuildListScrollFrame:StripTextures()
+ S:HandleScrollBar(GuildListScrollFrameScrollBar)
+
+ S:HandleNextPrevButton(GuildFrameGuildListToggleButton)
+
+ S:HandleButton(GuildFrameGuildInformationButton)
+ S:HandleButton(GuildFrameAddMemberButton)
+ S:HandleButton(GuildFrameControlButton)
+
+ for i = 1, GUILDMEMBERS_TO_DISPLAY do
+ local button = _G["GuildFrameButton"..i]
+ local level = _G["GuildFrameButton"..i.."Level"]
+ local name = _G["GuildFrameButton"..i.."Name"]
+ local class = _G["GuildFrameButton"..i.."Class"]
+ local statusButton = _G["GuildFrameGuildStatusButton"..i]
+ local statusName = _G["GuildFrameGuildStatusButton"..i.."Name"]
+
+ button.icon = button:CreateTexture("$parentIcon", "ARTWORK")
+ button.icon:Size(15)
+ button.icon:Point("LEFT", 48, 0)
+ button.icon:SetTexture("Interface\\WorldStateFrame\\Icons-Classes")
+
+ button:CreateBackdrop("Default", true)
+ button.backdrop:SetAllPoints(button.icon)
+
+ S:HandleButtonHighlight(button)
+ S:HandleButtonHighlight(statusButton)
+
+ level:ClearAllPoints()
+ level:Point("TOPLEFT", 10, -1)
+
+ name:Size(100, 14)
+ name:ClearAllPoints()
+ name:Point("LEFT", 85, 0)
+
+ class:Hide()
+
+ statusName:ClearAllPoints()
+ statusName:SetPoint("LEFT", 10, 0)
+ end
+
+ for i = 1, 4 do
+ local header = _G["GuildFrameColumnHeader"..i]
+ header:StripTextures()
+ header:StyleButton()
+
+ header = _G["GuildFrameGuildStatusColumnHeader"..i]
+ header:StripTextures()
+ header:StyleButton()
+ end
+
+ GuildFrameColumnHeader3:ClearAllPoints()
+ GuildFrameColumnHeader3:Point("TOPLEFT", 20, -66)
+ WhoFrameColumn_SetWidth(GuildFrameColumnHeader3, 32)
+
+ GuildFrameColumnHeader4:ClearAllPoints()
+ GuildFrameColumnHeader4:Point("LEFT", GuildFrameColumnHeader3, "RIGHT", -2, 0)
+ WhoFrameColumn_SetWidth(GuildFrameColumnHeader4, 48)
+
+ GuildFrameColumnHeader1:ClearAllPoints()
+ GuildFrameColumnHeader1:Point("LEFT", GuildFrameColumnHeader4, "RIGHT", -2, 0)
+ WhoFrameColumn_SetWidth(GuildFrameColumnHeader1, 105)
+
+ GuildFrameColumnHeader2:ClearAllPoints()
+ GuildFrameColumnHeader2:Point("LEFT", GuildFrameColumnHeader1, "RIGHT", -2, 0)
+ WhoFrameColumn_SetWidth(GuildFrameColumnHeader2, 127)
+
+ GuildFrameGuildStatusColumnHeader1:Point("TOPLEFT", 20, -66)
+
+ GuildFrameButton1:Point("TOPLEFT", GuildFrame, "TOPLEFT", 17, -93)
+ GuildFrameGuildStatusButton1:Point("TOPLEFT", GuildFrame, "TOPLEFT", 17, -93)
+
+ GuildListScrollFrame:Size(304, 220)
+ GuildListScrollFrame:Point("TOPRIGHT", -61, -89)
+
+ GuildListScrollFrameScrollBar:Point("TOPLEFT", GuildListScrollFrame, "TOPRIGHT", 3, -19)
+ GuildListScrollFrameScrollBar:Point("BOTTOMLEFT", GuildListScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ GuildFrameTotals:Point("BOTTOM", GuildFrame, "LEFT", 82, -77)
+
+ GuildFrameGuildListToggleButton:Point("LEFT", 305, -69)
+ GuildFrameGuildListToggleButton.SetPoint = E.noop
+
+ GuildFrameNotesLabel:Point("TOPLEFT", 19, -340)
+ GuildFrameNotesText:Width(325)
+
+ GuildFrameGuildInformationButton:Width(121)
+ GuildFrameControlButton:Width(100)
+ GuildFrameGuildInformationButton:Point("RIGHT", GuildFrameAddMemberButton, "LEFT", -3, 0)
+ GuildFrameAddMemberButton:Point("RIGHT", GuildFrameControlButton, "LEFT", -3, 0)
+ GuildFrameControlButton:Point("BOTTOMRIGHT", -40, 84)
+
+ hooksecurefunc("GuildStatus_Update", function()
+ local _, online, classFileName, button, classTextColor
+
+ if FriendsFrame.playerStatusFrame then
+ local level, buttonText, levelTextColor
+
+ for i = 1, GUILDMEMBERS_TO_DISPLAY do
+ button = _G["GuildFrameButton"..i]
+ _, _, _, level, _, _, _, _, online, _, classFileName = GetGuildRosterInfo(button.guildIndex)
+ if classFileName then
+ if online then
+ classTextColor = E.media.herocolor
+ levelTextColor = GetQuestDifficultyColor(level)
+ buttonText = _G["GuildFrameButton"..i.."Name"]
+ buttonText:SetTextColor(classTextColor.r, classTextColor.g, classTextColor.b)
+ buttonText = _G["GuildFrameButton"..i.."Level"]
+ buttonText:SetTextColor(levelTextColor.r, levelTextColor.g, levelTextColor.b)
+ end
+ button.icon:SetTexCoord(unpack(CLASS_ICON_TCOORDS[classFileName]))
+ end
+ end
+ else
+ for i = 1, GUILDMEMBERS_TO_DISPLAY do
+ button = _G["GuildFrameGuildStatusButton"..i]
+ _, _, _, _, _, _, _, _, online, _, classFileName = GetGuildRosterInfo(button.guildIndex)
+ if classFileName then
+ if online then
+ classTextColor = E.media.herocolor
+ _G["GuildFrameGuildStatusButton"..i.."Name"]:SetTextColor(classTextColor.r, classTextColor.g, classTextColor.b)
+ _G["GuildFrameGuildStatusButton"..i.."Online"]:SetTextColor(1.0, 1.0, 1.0)
+ end
+ end
+ end
+ end
+ end)
+
+ -- Member Detail Frame
+ GuildMemberDetailFrame:StripTextures()
+ GuildMemberDetailFrame:CreateBackdrop("Transparent")
+ GuildMemberDetailFrame:Point("TOPLEFT", GuildFrame, "TOPRIGHT", -32, -13)
+
+ S:HandleCloseButton(GuildMemberDetailCloseButton, GuildMemberDetailFrame)
+
+ S:HandleNextPrevButton(GuildFramePromoteButton)
+ S:HandleNextPrevButton(GuildFrameDemoteButton)
+
+ GuildMemberNoteBackground:SetTemplate("Default")
+ GuildMemberOfficerNoteBackground:SetTemplate("Default")
+
+ S:HandleButton(GuildMemberRemoveButton)
+ S:HandleButton(GuildMemberGroupInviteButton)
+
+ GuildFramePromoteButton:Point("LEFT", GuildMemberDetailFrame, "RIGHT", -55, 46)
+ GuildFrameDemoteButton:Point("LEFT", GuildFramePromoteButton, "RIGHT", 3, 0)
+
+ GuildMemberRemoveButton:Point("BOTTOMLEFT", 7, 7)
+ GuildMemberGroupInviteButton:SetPoint("LEFT", GuildMemberRemoveButton, "RIGHT", 6, 0)
+
+ GUILD_DETAIL_NORM_HEIGHT = 203 -- orig 195
+
+ -- Info Frame
+ GuildInfoFrame:StripTextures()
+ GuildInfoFrame:CreateBackdrop("Transparent")
+ GuildInfoFrame.backdrop:Point("TOPLEFT", 4, -6)
+ GuildInfoFrame.backdrop:Point("BOTTOMRIGHT", -2, 0)
+
+ S:SetBackdropHitRect(GuildInfoFrame)
+
+ S:HandleCloseButton(GuildInfoCloseButton, GuildInfoFrame.backdrop)
+
+ GuildInfoTextBackground:SetTemplate("Default")
+ S:HandleScrollBar(GuildInfoFrameScrollFrameScrollBar)
+
+ S:HandleButton(GuildInfoSaveButton)
+ S:HandleButton(GuildInfoCancelButton)
+ S:HandleButton(GuildInfoGuildEventButton)
+
+ GuildInfoEditBox:Size(246, 312)
+
+ GuildInfoTextBackground:Size(254, 228)
+ GuildInfoTextBackground:Point("TOPLEFT", 12, -33)
+
+ GuildInfoFrameScrollFrame:Width(252)
+ GuildInfoFrameScrollFrame:Point("TOPLEFT", 2, -5)
+
+ GuildInfoFrameScrollFrameScrollBar:Point("TOPLEFT", GuildInfoFrameScrollFrame, "TOPRIGHT", 3, -14)
+ GuildInfoFrameScrollFrameScrollBar:Point("BOTTOMLEFT", GuildInfoFrameScrollFrame, "BOTTOMRIGHT", 3, 14)
+
+ GuildInfoSaveButton:Point("BOTTOMLEFT", 104, 8)
+ GuildInfoCancelButton:Point("LEFT", GuildInfoSaveButton, "RIGHT", 3, 0)
+ GuildInfoGuildEventButton:Point("RIGHT", GuildInfoSaveButton, "LEFT", -27, 0)
+
+ -- GuildEventLog Frame
+ GuildEventLogFrame:StripTextures()
+ GuildEventLogFrame:CreateBackdrop("Transparent")
+ GuildEventLogFrame.backdrop:Point("TOPLEFT", 4, -6)
+ GuildEventLogFrame.backdrop:Point("BOTTOMRIGHT", -1, 5)
+
+ S:SetBackdropHitRect(GuildEventLogFrame)
+
+ S:HandleCloseButton(GuildEventLogCloseButton, GuildEventLogFrame.backdrop)
+
+ GuildEventFrame:SetTemplate("Default")
+ S:HandleScrollBar(GuildEventLogScrollFrameScrollBar)
+
+ S:HandleButton(GuildEventLogCancelButton)
+
+ GuildEventFrame:Size(353, 361)
+ GuildEventFrame:Point("TOPLEFT", GuildEventLogFrame, "TOPLEFT", 12, -32)
+
+ GuildEventLogScrollFrame:Size(347, 353)
+ GuildEventLogScrollFrame:Point("TOPRIGHT", -3, -4)
+
+ GuildEventLogScrollFrameScrollBar:Point("TOPLEFT", GuildEventLogScrollFrame, "TOPRIGHT", 6, -15)
+ GuildEventLogScrollFrameScrollBar:Point("BOTTOMLEFT", GuildEventLogScrollFrame, "BOTTOMRIGHT", 6, 15)
+
+ -- Control Frame
+ GuildControlPopupFrame:StripTextures()
+ GuildControlPopupFrame:CreateBackdrop("Transparent")
+ GuildControlPopupFrame.backdrop:Point("TOPLEFT", 4, -6)
+ GuildControlPopupFrame.backdrop:Point("BOTTOMRIGHT", -27, 27)
+
+ S:SetBackdropHitRect(GuildControlPopupFrame)
+
+ S:HandleDropDownBox(GuildControlPopupFrameDropDown, 185)
+ GuildControlPopupFrameDropDownButton:Size(16)
+
+ local function SkinPlusMinus(f, minus)
+ f:SetNormalTexture("")
+ f.SetNormalTexture = E.noop
+ f:SetPushedTexture("")
+ f.SetPushedTexture = E.noop
+ f:SetHighlightTexture("")
+ f.SetHighlightTexture = E.noop
+ f:SetDisabledTexture("")
+ f.SetDisabledTexture = E.noop
+
+ f.Text = f:CreateFontString(nil, "OVERLAY")
+ f.Text:FontTemplate(nil, 22)
+ f.Text:Point("LEFT", 5, 0)
+ if minus then
+ f.Text:SetText("-")
+ else
+ f.Text:SetText("+")
+ end
+ end
+
+ SkinPlusMinus(GuildControlPopupFrameAddRankButton)
+ SkinPlusMinus(GuildControlPopupFrameRemoveRankButton, true)
+
+ S:HandleEditBox(GuildControlPopupFrameEditBox)
+ GuildControlPopupFrameEditBox.backdrop:Point("TOPLEFT", 0, -5)
+ GuildControlPopupFrameEditBox.backdrop:Point("BOTTOMRIGHT", 0, 5)
+
+ S:HandleCheckBox(GuildControlTabPermissionsViewTab)
+ S:HandleCheckBox(GuildControlTabPermissionsDepositItems)
+ S:HandleCheckBox(GuildControlTabPermissionsUpdateText)
+
+ for i = 1, 17 do
+ local checkbox = _G["GuildControlPopupFrameCheckbox"..i]
+ if checkbox then
+ S:HandleCheckBox(checkbox)
+ end
+ end
+
+ S:HandleEditBox(GuildControlWithdrawGoldEditBox)
+ GuildControlWithdrawGoldEditBox.backdrop:Point("TOPLEFT", 0, -5)
+ GuildControlWithdrawGoldEditBox.backdrop:Point("BOTTOMRIGHT", 0, 5)
+
+ for i = 1, MAX_GUILDBANK_TABS do
+ local tab = _G["GuildBankTabPermissionsTab"..i]
+
+ tab:StripTextures()
+ tab:CreateBackdrop("Default")
+ tab.backdrop:Point("TOPLEFT", 3, -10)
+ tab.backdrop:Point("BOTTOMRIGHT", -2, 4)
+ end
+
+ S:HandleEditBox(GuildControlWithdrawItemsEditBox)
+ GuildControlWithdrawItemsEditBox.backdrop:Point("TOPLEFT", 0, -5)
+ GuildControlWithdrawItemsEditBox.backdrop:Point("BOTTOMRIGHT", 0, 5)
+
+ S:HandleButton(GuildControlPopupAcceptButton)
+ S:HandleButton(GuildControlPopupFrameCancelButton)
+
+ GuildControlPopupFrameDropDown:Point("TOP", 0, -41)
+ GuildControlPopupFrameAddRankButton:Point("LEFT", GuildControlPopupFrameDropDown, "RIGHT", -8, 3)
+
+ GuildControlPopupFrameEditBox:Point("TOP", 35, -67)
+
+ select(8, GuildControlPopupFrame:GetRegions()):Point("TOP", -10, -100)
+
+ GuildControlPopupFrameCheckboxes:Point("TOPRIGHT", -22, 9)
+
+ GuildControlPopupFrameTabPermissions:SetTemplate("Transparent")
+ GuildControlPopupFrameTabPermissions:Width(273)
+ GuildControlPopupFrameTabPermissions:Point("BOTTOMLEFT", 12, 64)
+
+ GuildControlPopupFrameCancelButton:Point("BOTTOMRIGHT", -35, 35)
+ GuildControlPopupAcceptButton:Point("RIGHT", GuildControlPopupFrameCancelButton, "LEFT", -3, 0)
+
+ -- Channel Frame
+ ChannelFrameVerticalBar:Kill()
+
+ S:HandleCheckBox(ChannelFrameAutoJoinParty)
+ S:HandleCheckBox(ChannelFrameAutoJoinBattleground)
+
+ for i = 1, MAX_DISPLAY_CHANNEL_BUTTONS do
+ local button = _G["ChannelButton"..i]
+ local text = _G["ChannelButton"..i.."Text"]
+
+ button:StripTextures()
+ S:HandleButtonHighlight(button)
+
+ -- fix font template
+ if not text:GetFontObject() then
+ text:SetFontObject("GameTooltipTextSmall")
+ end
+
+ _G["ChannelButton"..i.."Collapsed"]:SetTextColor(1, 1, 1)
+ end
+
+ for i = 1, 22 do
+ S:HandleButtonHighlight(_G["ChannelMemberButton"..i])
+ end
+
+ ChannelListScrollFrame:StripTextures()
+ S:HandleScrollBar(ChannelListScrollFrameScrollBar)
+
+ ChannelRosterScrollFrame:StripTextures()
+ S:HandleScrollBar(ChannelRosterScrollFrameScrollBar)
+
+ S:HandleButton(ChannelFrameNewButton)
+
+ ChannelListScrollFrame:Size(161, 381)
+ ChannelListScrollFrame:Point("TOPLEFT", 19, -47)
+
+ ChannelListScrollFrameScrollBar:Point("TOPLEFT", ChannelListScrollFrame, "TOPRIGHT", 3, -19)
+ ChannelListScrollFrameScrollBar:Point("BOTTOMLEFT", ChannelListScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ ChannelRoster:Point("TOPLEFT", ChannelFrame, "TOP", 126, -70)
+ ChannelRoster.SetPoint = E.noop
+
+ ChannelMemberButton1:Point("TOPLEFT", ChannelFrame, "TOPLEFT", 186, -66)
+ ChannelMemberButton1.SetPoint = E.noop
+
+ ChannelRosterScrollFrame:Size(138, 352)
+ ChannelRosterScrollFrame:Point("TOPRIGHT", ChannelFrame, "TOPRIGHT", -32, -47)
+
+ ChannelRosterScrollFrameScrollBar:Point("TOPLEFT", ChannelRosterScrollFrame, "TOPRIGHT", 3, -19)
+ ChannelRosterScrollFrameScrollBar:Point("BOTTOMLEFT", ChannelRosterScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ ChannelFrameNewButton:Point("BOTTOMRIGHT", -11, 84)
+
+ hooksecurefunc("ChannelList_SetScroll", function()
+ local buttonWidth
+
+ if ChannelListScrollFrame.scrolling then
+ buttonWidth = 135
+ ChannelListScrollFrame:Width(138)
+ else
+ buttonWidth = 155
+ ChannelListScrollFrame:Width(161)
+ end
+
+ for i = 1, MAX_CHANNEL_BUTTONS do
+ _G["ChannelButton"..i]:Width(buttonWidth)
+ end
+ end)
+
+ -- Channel Frame DaughterFrame
+ ChannelFrameDaughterFrame:StripTextures()
+ ChannelFrameDaughterFrame:SetTemplate("Transparent")
+
+ S:HandleCloseButton(ChannelFrameDaughterFrameDetailCloseButton, ChannelFrameDaughterFrame)
+
+ S:HandleEditBox(ChannelFrameDaughterFrameChannelName)
+ S:HandleEditBox(ChannelFrameDaughterFrameChannelPassword)
+
+ S:HandleButton(ChannelFrameDaughterFrameOkayButton)
+ S:HandleButton(ChannelFrameDaughterFrameCancelButton)
+
+ ChannelFrameDaughterFrame:Width(211)
+
+ ChannelFrameDaughterFrameChannelName:Width(175)
+ ChannelFrameDaughterFrameChannelName:Point("TOPLEFT", 18, -60)
+
+ ChannelFrameDaughterFrameChannelPassword:Width(175)
+
+ ChannelFrameDaughterFrameOkayButton:Point("BOTTOMLEFT", 8, 8)
+ ChannelFrameDaughterFrameCancelButton:Point("LEFT", ChannelFrameDaughterFrameOkayButton, "RIGHT", 3, 0)
+
+ -- Raid Frame
+ S:HandleButton(RaidFrameConvertToRaidButton)
+ S:HandleButton(RaidFrameRaidInfoButton)
+ S:HandleButton(RaidFrameNotInRaidRaidBrowserButton)
+
+ RaidFrameConvertToRaidButton:Point("TOPLEFT", 45, -33)
+ RaidFrameRaidInfoButton:Point("LEFT", RaidFrameConvertToRaidButton, "RIGHT", 69, 0)
+
+ -- Raid Info Frame
+ RaidInfoFrame:StripTextures(true)
+ RaidInfoFrame:SetTemplate("Transparent")
+
+ RaidInfoInstanceLabel:StripTextures()
+ RaidInfoIDLabel:StripTextures()
+
+ S:HandleCloseButton(RaidInfoCloseButton, RaidInfoFrame)
+
+ S:HandleScrollBar(RaidInfoScrollFrameScrollBar)
+
+ S:HandleButton(RaidInfoExtendButton)
+ S:HandleButton(RaidInfoCancelButton)
+
+ RaidInfoInstanceLabel:Point("TOPLEFT", 13, -10)
+
+ RaidInfoScrollFrame:CreateBackdrop("Transparent")
+ RaidInfoScrollFrame.backdrop:Point("TOPLEFT", -1, 1)
+ RaidInfoScrollFrame.backdrop:Point("BOTTOMRIGHT", 1, -2)
+
+ RaidInfoScrollFrame:Height(182)
+ RaidInfoScrollFrame:Point("TOPLEFT", 9, -31)
+
+ RaidInfoScrollFrameScrollBar:Point("TOPLEFT", RaidInfoScrollFrame, "TOPRIGHT", 4, -18)
+ RaidInfoScrollFrameScrollBar:Point("BOTTOMLEFT", RaidInfoScrollFrame, "BOTTOMRIGHT", 4, 17)
+
+ for _, button in ipairs(RaidInfoScrollFrame.buttons) do
+ S:HandleButtonHighlight(button)
+ end
+
+ RaidInfoExtendButton:Point("BOTTOMLEFT", 8, 8)
+ RaidInfoCancelButton:Point("BOTTOMRIGHT", -8, 8)
+
+ RaidInfoFrame:SetScript("OnShow", function(self)
+ if GetNumRaidMembers() > 0 then
+ self:Point("TOPLEFT", "RaidFrame", "TOPRIGHT", -5, -12)
+ else
+ self:Point("TOPLEFT", "RaidFrame", "TOPRIGHT", -33, -12)
+ end
+
+ PlaySound("UChatScrollButton")
+ end)
+
+ RaidInfoScrollFrameScrollBar:SetScript("OnShow", function(self)
+ local parent = self:GetParent()
+ parent:Width(306)
+ RaidInfoInstanceLabel:Width(153)
+
+ for _, frame in ipairs(parent.buttons) do
+ frame:Width(296)
+ frame.name:Width(141)
+ end
+ end)
+
+ RaidInfoScrollFrameScrollBar:SetScript("OnHide", function(self)
+ local parent = self:GetParent()
+ parent:Width(327)
+ RaidInfoInstanceLabel:Width(173)
+
+ for _, frame in ipairs(parent.buttons) do
+ frame:Width(317)
+ frame.name:Width(162)
+ end
+ end)
+
+ RaidInfoScrollFrameScrollBar:GetScript("OnHide")(RaidInfoScrollFrameScrollBar)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/GMChat.lua b/ElvUI/Modules/Skins/Blizzard/GMChat.lua
new file mode 100644
index 0000000..450a6b7
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/GMChat.lua
@@ -0,0 +1,118 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+local IsShiftKeyDown = IsShiftKeyDown
+
+S:AddCallbackForAddon("Blizzard_GMChatUI", "Skin_Blizzard_GMChatUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.gmchat then return end
+
+ GMChatFrame:StripTextures()
+ GMChatFrame:CreateBackdrop("Transparent")
+ GMChatFrame.backdrop:Point("TOPLEFT", -2, 7)
+ GMChatFrame.backdrop:Point("BOTTOMRIGHT", 2, -6)
+
+ GMChatFrame:SetClampRectInsets(-6, 6, 33, -10)
+ GMChatFrame:Size(LeftChatPanel:GetWidth() - 4, 120)
+ GMChatFrame:Point("BOTTOMLEFT", LeftChatPanel, "TOPLEFT", 2, 5)
+ GMChatFrame:EnableMouseWheel(true)
+
+ GMChatTab:StripTextures()
+ GMChatTab:CreateBackdrop("Default")
+ GMChatTab.backdrop:Point("TOPLEFT", -2, 0)
+ GMChatTab.backdrop:Point("BOTTOMRIGHT", 2, 3)
+
+ GMChatTabText:Point("LEFT", GMChatTab, 17, 2)
+ GMChatTabText:FontTemplate(E.LSM:Fetch("font", E.db.chat.tabFont), E.db.chat.tabFontSize, E.db.chat.tabFontOutline)
+
+ GMChatTabText:SetTextColor(unpack(E.media.rgbvaluecolor))
+
+ S:HandleCloseButton(GMChatFrameCloseButton)
+ GMChatFrameCloseButton:Point("RIGHT", GMChatTab, 6, 2)
+
+ GMChatFrameButtonFrame:Kill()
+
+ local numScrollMessages = E.db.chat.numScrollMessages or 3
+ GMChatFrame:SetScript("OnMouseWheel", function(self, delta)
+ if delta < 0 then
+ if IsShiftKeyDown() then
+ self:ScrollToBottom()
+ else
+ for i = 1, numScrollMessages do
+ self:ScrollDown()
+ end
+ end
+ elseif delta > 0 then
+ if IsShiftKeyDown() then
+ self:ScrollToTop()
+ else
+ for i = 1, numScrollMessages do
+ self:ScrollUp()
+ end
+ end
+ end
+ end)
+
+ local statusFrame = select(2, GMChatStatusFrame:GetChildren())
+ statusFrame:StripTextures()
+ statusFrame:CreateBackdrop("Transparent")
+ statusFrame.backdrop:Point("TOPLEFT", 0, 1)
+ statusFrame.backdrop:Point("BOTTOMRIGHT", 0, 0)
+
+ GMChatStatusFramePulse:SetTexture("Interface\\GMChatFrame\\UI-GMStatusFrame-Pulse")
+ GMChatStatusFramePulse:Point("TOPLEFT", -25, 21)
+ GMChatStatusFramePulse:Point("BOTTOMRIGHT", 25, -19)
+
+ GMChatStatusFrame:HookScript("OnShow", function(self)
+ if TicketStatusFrame and TicketStatusFrame:IsShown() then
+ self:Point("TOPLEFT", TicketStatusFrame, "BOTTOMLEFT", 0, 1)
+ else
+ self:SetAllPoints(TicketStatusFrame)
+ end
+ end)
+
+ TicketStatusFrame:HookScript("OnShow", function(self)
+ GMChatStatusFrame:Point("TOPLEFT", self, "BOTTOMLEFT", 0, 1)
+ end)
+ TicketStatusFrame:HookScript("OnHide", function(self)
+ GMChatStatusFrame:SetAllPoints(self)
+ end)
+end)
+
+S:AddCallbackForAddon("Blizzard_GMSurveyUI", "Skin_Blizzard_GMSurveyUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.gmchat then return end
+
+ GMSurveyFrame:StripTextures()
+ GMSurveyFrame:CreateBackdrop("Transparent")
+ GMSurveyFrame.backdrop:Point("TOPLEFT", 11, 4)
+ GMSurveyFrame.backdrop:Point("BOTTOMRIGHT", -49, 10)
+
+ GMSurveyFrame:EnableMouse(true)
+ S:SetBackdropHitRect(GMSurveyFrame)
+
+ GMSurveyHeader:StripTextures()
+ S:HandleCloseButton(GMSurveyCloseButton, GMSurveyFrame.backdrop)
+
+ GMSurveyScrollFrame:StripTextures()
+ S:HandleScrollBar(GMSurveyScrollFrameScrollBar)
+
+ S:HandleButton(GMSurveyCancelButton)
+ S:HandleButton(GMSurveySubmitButton)
+
+ for i = 1, 7 do
+ local frame = _G["GMSurveyQuestion"..i]
+ frame:StripTextures()
+ frame:SetTemplate("Transparent")
+ end
+
+ GMSurveyCommentFrame:StripTextures()
+ GMSurveyCommentFrame:SetTemplate("Transparent")
+
+ GMSurveyScrollFrameScrollBar:Point("TOPLEFT", GMSurveyScrollFrame, "TOPRIGHT", 5, -19)
+ GMSurveyScrollFrameScrollBar:Point("BOTTOMLEFT", GMSurveyScrollFrame, "BOTTOMRIGHT", 5, 18)
+
+ GMSurveySubmitButton:Height(22)
+ GMSurveySubmitButton:Point("BOTTOMRIGHT", -57, 18)
+ GMSurveyCancelButton:Point("BOTTOMLEFT", 19, 18)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Glyph.lua b/ElvUI/Modules/Skins/Blizzard/Glyph.lua
new file mode 100644
index 0000000..a6425bd
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Glyph.lua
@@ -0,0 +1,101 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+--WoW API / Variables
+
+S:AddCallbackForAddon("Blizzard_GlyphUI", "Skin_Blizzard_GlyphUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.talent then return end
+
+ if not PlayerTalentFrame then
+ TalentFrame_LoadUI()
+ end
+
+ GlyphFrame:StripTextures()
+
+ GlyphFrameBackground:Size(323, 349)
+ GlyphFrameBackground:Point("TOPLEFT", 20, -59)
+ GlyphFrameBackground:CreateBackdrop()
+
+ S:HookScript(GlyphFrame, "OnShow", function(self)
+ S:SetBackdropHitRect(self, PlayerTalentFrame.backdrop)
+ S:Unhook(self, "OnShow")
+ end)
+
+ GlyphFrameBackground:SetTexture("Interface\\Spellbook\\UI-GlyphFrame")
+ GlyphFrameGlow:SetTexture("Interface\\Spellbook\\UI-GlyphFrame-Glow")
+ GlyphFrameGlow:SetAllPoints(GlyphFrameBackground)
+
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 512, 512, 315, 340, 21, 72
+ GlyphFrameBackground:SetTexCoord(0.041015625, 0.65625, 0.140625, 0.8046875)
+
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 512, 512, 315, 340, 30, 34
+ GlyphFrameGlow:SetTexCoord(0.05859375, 0.673828125, 0.06640625, 0.73046875)
+
+ local glyphBGScale = 1.0253968
+ local glyphPositions = {
+ {"CENTER", -1, 126},
+ {"CENTER", -1, -119},
+ {"TOPLEFT", 8, -62},
+ {"BOTTOMRIGHT", -10, 70},
+ {"TOPRIGHT", -8, -62},
+ {"BOTTOMLEFT", 7, 70}
+ }
+
+ local glyphFrameLevel = GlyphFrame:GetFrameLevel() + 1
+ for i = 1, 6 do
+ local frame = _G["GlyphFrameGlyph"..i]
+ frame:SetParent(GlyphFrameBackground.backdrop)
+ frame:SetFrameLevel(glyphFrameLevel)
+ frame:SetScale(glyphBGScale)
+ frame:Point(unpack(glyphPositions[i]))
+ end
+
+ GlyphFrame:HookScript("OnShow", function()
+ PlayerTalentFrameTitleText:Hide()
+ PlayerTalentFramePointsBar:Hide()
+ PlayerTalentFrameScrollFrame:Hide()
+ PlayerTalentFrameStatusFrame:Hide()
+ PlayerTalentFrameActivateButton:Hide()
+ end)
+
+ GlyphFrame:SetScript("OnHide", function()
+ PlayerTalentFrameTitleText:Show()
+ PlayerTalentFramePointsBar:Show()
+ PlayerTalentFrameScrollFrame:Show()
+ end)
+
+ hooksecurefunc(PlayerTalentFrame, "updateFunction", function()
+ if GlyphFrame:IsShown() then
+ PlayerTalentFramePreviewBar:Hide()
+ end
+ end)
+
+ do
+ local slotAnimations = {}
+ local TOPLEFT, TOP, TOPRIGHT, BOTTOMRIGHT, BOTTOM, BOTTOMLEFT = 3, 1, 5, 4, 2, 6
+ slotAnimations[TOPLEFT] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = -85, ["yStart"] = 17, ["yStop"] = 60}
+ slotAnimations[TOP] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = -13, ["yStart"] = 17, ["yStop"] = 100}
+ slotAnimations[TOPRIGHT] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = 59, ["yStart"] = 17, ["yStop"] = 60}
+ slotAnimations[BOTTOM] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = -13, ["yStart"] = 17, ["yStop"] = -64}
+ slotAnimations[BOTTOMLEFT] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = -87, ["yStart"] = 18, ["yStop"] = -27}
+ slotAnimations[BOTTOMRIGHT] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = 61, ["yStart"] = 18, ["yStop"] = -27}
+
+ for _, animData in pairs(slotAnimations) do
+ animData.xStart = animData.xStart + 3
+ animData.yStart = animData.yStart + 8
+ animData.xStop = (animData.xStop + 3) * glyphBGScale
+ animData.yStop = (animData.yStop + 8) * glyphBGScale
+ end
+
+ hooksecurefunc("GlyphFrame_StartSlotAnimation", function(slotID, duration, size)
+ local sparkle = _G["GlyphFrameSparkle"..slotID]
+ local animation = slotAnimations[slotID]
+
+ sparkle:SetPoint("CENTER", GlyphFrame, animation.point, animation.xStart, animation.yStart)
+ sparkle.animGroup.translate:SetOffset(animation.xStop - animation.xStart, animation.yStop - animation.yStart)
+ end)
+ end
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Gossip.lua b/ElvUI/Modules/Skins/Blizzard/Gossip.lua
new file mode 100644
index 0000000..6897722
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Gossip.lua
@@ -0,0 +1,93 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local select = select
+local find, gsub = string.find, string.gsub
+--WoW API / Variables
+
+S:AddCallback("Skin_Gossip", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.gossip then return end
+
+ -- Gossip
+ GossipFramePortrait:Kill()
+ GossipFrameGreetingPanel:StripTextures()
+
+ GossipFrame:CreateBackdrop("Transparent")
+ GossipFrame.backdrop:Point("TOPLEFT", 11, -12)
+ GossipFrame.backdrop:Point("BOTTOMRIGHT", -32, 0)
+
+ S:SetUIPanelWindowInfo(GossipFrame, "width")
+ S:SetBackdropHitRect(GossipFrame)
+
+ GossipGreetingText:SetTextColor(1, 1, 1)
+
+ S:HandleCloseButton(GossipFrameCloseButton, GossipFrame.backdrop)
+
+ S:HandleScrollBar(GossipGreetingScrollFrameScrollBar)
+ S:HandleButton(GossipFrameGreetingGoodbyeButton)
+
+ for i = 1, NUMGOSSIPBUTTONS do
+ local button = _G["GossipTitleButton"..i]
+ S:HandleButtonHighlight(button)
+ select(3, button:GetRegions()):SetTextColor(1, 1, 1)
+ end
+
+ GossipFrameNpcNameText:ClearAllPoints()
+ GossipFrameNpcNameText:Point("TOP", GossipFrame, "TOP", -6, -15)
+
+ GossipGreetingScrollFrame:Size(304, 402)
+ GossipGreetingScrollFrame:Point("TOPLEFT", GossipFrame, "TOPLEFT", 19, -73)
+
+ GossipGreetingScrollFrameScrollBar:Point("TOPLEFT", GossipGreetingScrollFrame, "TOPRIGHT", 3, -19)
+ GossipGreetingScrollFrameScrollBar:Point("BOTTOMLEFT", GossipGreetingScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ GossipFrameGreetingGoodbyeButton:Point("BOTTOMRIGHT", -40, 8)
+
+ hooksecurefunc("GossipFrameUpdate", function()
+ for i = 1, GossipFrame.buttonIndex do
+ local button = _G["GossipTitleButton"..i]
+
+ if button and button:GetText() and find(button:GetText(), "|cff000000") then
+ button:SetText(gsub(button:GetText(), "|cff000000", "|cffFFFF00"))
+ end
+ end
+ end)
+
+ -- ItemText
+ ItemTextScrollFrame:StripTextures()
+ ItemTextFrame:StripTextures(true)
+ ItemTextFrame:CreateBackdrop("Transparent")
+ ItemTextFrame.backdrop:Point("TOPLEFT", 11, -12)
+ ItemTextFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(ItemTextFrame, "width")
+ S:SetBackdropHitRect(ItemTextFrame)
+
+ ItemTextPageText:SetTextColor(1, 1, 1)
+ ItemTextPageText.SetTextColor = E.noop
+
+ S:HandleCloseButton(ItemTextCloseButton, ItemTextFrame.backdrop)
+
+ S:HandleNextPrevButton(ItemTextPrevPageButton)
+ S:HandleNextPrevButton(ItemTextNextPageButton)
+
+ S:HandleScrollBar(ItemTextScrollFrameScrollBar)
+
+ ItemTextTitleText:Point("CENTER", -15, 230)
+
+ ItemTextCurrentPage:Point("TOP", -15, -52)
+
+ ItemTextPrevPageButton:Point("CENTER", ItemTextFrame, "TOPLEFT", 100, -58)
+ ItemTextNextPageButton:Point("CENTER", ItemTextFrame, "TOPRIGHT", -130, -58)
+
+ ItemTextPrevPageButton:GetRegions():Point("LEFT", ItemTextPrevPageButton, "RIGHT", 3, 0)
+ ItemTextNextPageButton:GetRegions():Point("RIGHT", ItemTextNextPageButton, "LEFT", -3, 0)
+
+ ItemTextScrollFrame:Width(283)
+ ItemTextScrollFrame:Point("TOPRIGHT", -61, -73)
+
+ ItemTextScrollFrameScrollBar:Point("TOPLEFT", ItemTextScrollFrame, "TOPRIGHT", 3, -19)
+ ItemTextScrollFrameScrollBar:Point("BOTTOMLEFT", ItemTextScrollFrame, "BOTTOMRIGHT", 3, 19)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/GuildBank.lua b/ElvUI/Modules/Skins/Blizzard/GuildBank.lua
new file mode 100644
index 0000000..7e0eee6
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/GuildBank.lua
@@ -0,0 +1,214 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+--WoW API / Variables
+local GetCurrentGuildBankTab = GetCurrentGuildBankTab
+local GetGuildBankItemLink = GetGuildBankItemLink
+local GetItemQualityColor = GetItemQualityColor
+
+S:AddCallbackForAddon("Blizzard_GuildBankUI", "Skin_Blizzard_GuildBankUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.gbank then return end
+
+ GuildBankFrame:Width(639)
+ GuildBankFrame:StripTextures()
+ GuildBankFrame:CreateBackdrop("Transparent")
+ GuildBankFrame.backdrop:Point("TOPLEFT", 11, -12)
+ GuildBankFrame.backdrop:Point("BOTTOMRIGHT", 0, 8)
+
+ S:HookScript(GuildBankFrame, "OnShow", function(self)
+ S:SetUIPanelWindowInfo(self, "width", nil, 35)
+ S:SetBackdropHitRect(self)
+ S:Unhook(self, "OnShow")
+ end)
+
+ GuildBankFrame.inset = CreateFrame("Frame", nil, GuildBankFrame)
+ GuildBankFrame.inset:SetTemplate("Default")
+ GuildBankFrame.inset:Point("TOPLEFT", 19, -64)
+ GuildBankFrame.inset:Point("BOTTOMRIGHT", -8, 62)
+
+ GuildBankEmblemFrame:StripTextures(true)
+
+ S:HandleCloseButton((select(13, GuildBankFrame:GetChildren())), GuildBankFrame.backdrop)
+
+ S:HandleButton(GuildBankFrameDepositButton)
+ S:HandleButton(GuildBankFrameWithdrawButton)
+ S:HandleButton(GuildBankInfoSaveButton)
+ S:HandleButton(GuildBankFramePurchaseButton)
+
+ GuildBankInfoScrollFrame:StripTextures()
+
+ S:HandleScrollBar(GuildBankInfoScrollFrameScrollBar)
+
+ GuildBankTransactionsScrollFrame:StripTextures()
+
+ S:HandleScrollBar(GuildBankTransactionsScrollFrameScrollBar)
+
+ S:HandleTab(GuildBankFrameTab1)
+ S:HandleTab(GuildBankFrameTab2)
+ S:HandleTab(GuildBankFrameTab3)
+ S:HandleTab(GuildBankFrameTab4)
+
+ for i = 1, 6 do
+ local tab = _G["GuildBankTab"..i]
+ local button = _G["GuildBankTab"..i.."Button"]
+ local texture = _G["GuildBankTab"..i.."ButtonIconTexture"]
+
+ tab:StripTextures(true)
+
+ button:StripTextures()
+ button:SetTemplate()
+ button:StyleButton()
+
+ button:GetCheckedTexture():SetTexture(1, 1, 1, 0.3)
+ button:GetCheckedTexture():SetInside()
+
+ texture:SetInside()
+ texture:SetTexCoord(unpack(E.TexCoords))
+ texture:SetDrawLayer("ARTWORK")
+ end
+
+ local buttonMap = {}
+
+ for column = 1, NUM_GUILDBANK_COLUMNS do
+ _G["GuildBankColumn"..column]:StripTextures()
+
+ for index = 1, NUM_SLOTS_PER_GUILDBANK_GROUP do
+ local button = _G["GuildBankColumn"..column.."Button"..index]
+ local icon = _G["GuildBankColumn"..column.."Button"..index.."IconTexture"]
+ local texture = _G["GuildBankColumn"..column.."Button"..index.."NormalTexture"]
+ local count = _G["GuildBankColumn"..column.."Button"..index.."Count"]
+
+ if texture then
+ texture:SetTexture(nil)
+ end
+
+ button:StyleButton()
+ button:SetTemplate("Default", true)
+
+ icon:SetInside()
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetDrawLayer("OVERLAY")
+
+ count:SetDrawLayer("OVERLAY")
+
+ buttonMap[#buttonMap + 1] = button
+ end
+ end
+
+ hooksecurefunc("GuildBankFrame_Update", function()
+ if GuildBankFrame.mode ~= "bank" then
+ GuildBankFrame.inset:Point("BOTTOMRIGHT", -29, 62)
+ return
+ else
+ GuildBankFrame.inset:Point("BOTTOMRIGHT", -8, 62)
+
+ GuildBankColumn1:Point("TOPLEFT", 20, -70)
+ end
+
+ local tab = GetCurrentGuildBankTab()
+ local _, link, quality
+
+ for i = 1, MAX_GUILDBANK_SLOTS_PER_TAB do
+ link = GetGuildBankItemLink(tab, i)
+
+ if link then
+ _, _, quality = GetItemInfo(link)
+
+ if quality and quality > 1 then
+ buttonMap[i]:SetBackdropBorderColor(GetItemQualityColor(quality))
+ else
+ buttonMap[i]:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ else
+ buttonMap[i]:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end
+ end)
+
+ GuildBankLimitLabel:ClearAllPoints()
+ GuildBankLimitLabel:Point("BOTTOMLEFT", GuildBankMoneyLimitLabel, "TOPLEFT", -1, 11)
+
+ GuildBankFrameDepositButton:Point("BOTTOMRIGHT", -8, 36)
+ GuildBankFrameWithdrawButton:Point("RIGHT", GuildBankFrameDepositButton, "LEFT", -3, 0)
+
+ GuildBankFrameTab1:Point("BOTTOMLEFT", 11, -22)
+ GuildBankFrameTab2:Point("LEFT", GuildBankFrameTab1, "RIGHT", -15, 0)
+ GuildBankFrameTab3:Point("LEFT", GuildBankFrameTab2, "RIGHT", -15, 0)
+ GuildBankFrameTab4:Point("LEFT", GuildBankFrameTab3, "RIGHT", -15, 0)
+
+ -- Log + Money Log tabs
+ GuildBankMessageFrame:Size(575, 302)
+ GuildBankMessageFrame:Point("TOPLEFT", 27, -72)
+
+ GuildBankTransactionsScrollFrame:Size(591, 318)
+ GuildBankTransactionsScrollFrame:Point("TOPRIGHT", GuildBankFrame, "TOPRIGHT", -29, -64)
+
+ GuildBankTransactionsScrollFrameScrollBar:Point("TOPLEFT", GuildBankTransactionsScrollFrame, "TOPRIGHT", 3, -19)
+ GuildBankTransactionsScrollFrameScrollBar:Point("BOTTOMLEFT", GuildBankTransactionsScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ -- Info tab
+ GuildBankInfo:Point("TOPLEFT", 26, -72)
+
+ GuildBankInfoScrollFrame:Size(575, 302)
+
+ GuildBankInfoScrollFrameScrollBar:Point("TOPLEFT", GuildBankInfoScrollFrame, "TOPRIGHT", 12, -11)
+ GuildBankInfoScrollFrameScrollBar:Point("BOTTOMLEFT", GuildBankInfoScrollFrame, "BOTTOMRIGHT", 12, 11)
+
+ GuildBankTabInfoEditBox:Width(575)
+
+ GuildBankInfoSaveButton:Point("BOTTOMLEFT", GuildBankFrame, "BOTTOMLEFT", 19, 35)
+
+ -- Popup
+ S:HandleIconSelectionFrame(GuildBankPopupFrame, NUM_GUILDBANK_ICONS_SHOWN, "GuildBankPopupButton", "GuildBankPopup")
+ S:SetBackdropHitRect(GuildBankPopupFrame)
+
+ S:HandleScrollBar(GuildBankPopupScrollFrameScrollBar)
+
+ GuildBankPopupFrame:Point("TOPLEFT", GuildBankFrame, "TOPRIGHT", 24, 0)
+
+ local nameLable, iconLable = select(5, GuildBankPopupFrame:GetRegions())
+ nameLable:Point("TOPLEFT", 24, -18)
+ iconLable:Point("TOPLEFT", 24, -60)
+
+ GuildBankPopupEditBox:Point("TOPLEFT", 32, -35)
+
+ GuildBankPopupScrollFrame:CreateBackdrop("Transparent")
+ GuildBankPopupScrollFrame.backdrop:Point("TOPLEFT", 91, -10)
+ GuildBankPopupScrollFrame.backdrop:Point("BOTTOMRIGHT", -19, 5)
+ GuildBankPopupScrollFrame:Point("TOPRIGHT", -30, -66)
+
+ GuildBankPopupScrollFrameScrollBar:Point("TOPLEFT", GuildBankPopupScrollFrame, "TOPRIGHT", -16, -29)
+ GuildBankPopupScrollFrameScrollBar:Point("BOTTOMLEFT", GuildBankPopupScrollFrame, "BOTTOMRIGHT", -16, 24)
+
+ GuildBankPopupButton1:Point("TOPLEFT", 24, -82)
+
+ GuildBankPopupCancelButton:Point("BOTTOMRIGHT", -28, 35)
+ GuildBankPopupOkayButton:Point("RIGHT", GuildBankPopupCancelButton, "LEFT", -3, 0)
+
+ -- Reposition
+ GuildBankTab1:Point("TOPLEFT", GuildBankFrame, "TOPRIGHT", E.PixelMode and -3 or -1, -36)
+ GuildBankTab2:Point("TOPLEFT", GuildBankTab1, "BOTTOMLEFT", 0, 7)
+ GuildBankTab3:Point("TOPLEFT", GuildBankTab2, "BOTTOMLEFT", 0, 7)
+ GuildBankTab4:Point("TOPLEFT", GuildBankTab3, "BOTTOMLEFT", 0, 7)
+ GuildBankTab5:Point("TOPLEFT", GuildBankTab4, "BOTTOMLEFT", 0, 7)
+ GuildBankTab6:Point("TOPLEFT", GuildBankTab5, "BOTTOMLEFT", 0, 7)
+
+ GuildBankColumn1:Point("TOPLEFT", 25, -70)
+ GuildBankColumn2:Point("TOPLEFT", GuildBankColumn1, "TOPRIGHT", -14, 0)
+ GuildBankColumn3:Point("TOPLEFT", GuildBankColumn2, "TOPRIGHT", -14, 0)
+ GuildBankColumn4:Point("TOPLEFT", GuildBankColumn3, "TOPRIGHT", -14, 0)
+ GuildBankColumn5:Point("TOPLEFT", GuildBankColumn4, "TOPRIGHT", -14, 0)
+ GuildBankColumn6:Point("TOPLEFT", GuildBankColumn5, "TOPRIGHT", -14, 0)
+ GuildBankColumn7:Point("TOPLEFT", GuildBankColumn6, "TOPRIGHT", -14, 0)
+
+ GuildBankColumn1Button8:Point("TOPLEFT", GuildBankColumn1Button1, "TOPRIGHT", 6, 0)
+ GuildBankColumn2Button8:Point("TOPLEFT", GuildBankColumn2Button1, "TOPRIGHT", 6, 0)
+ GuildBankColumn3Button8:Point("TOPLEFT", GuildBankColumn3Button1, "TOPRIGHT", 6, 0)
+ GuildBankColumn4Button8:Point("TOPLEFT", GuildBankColumn4Button1, "TOPRIGHT", 6, 0)
+ GuildBankColumn5Button8:Point("TOPLEFT", GuildBankColumn5Button1, "TOPRIGHT", 6, 0)
+ GuildBankColumn6Button8:Point("TOPLEFT", GuildBankColumn6Button1, "TOPRIGHT", 6, 0)
+ GuildBankColumn7Button8:Point("TOPLEFT", GuildBankColumn7Button1, "TOPRIGHT", 6, 0)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/GuildRegistrar.lua b/ElvUI/Modules/Skins/Blizzard/GuildRegistrar.lua
new file mode 100644
index 0000000..1a5f311
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/GuildRegistrar.lua
@@ -0,0 +1,46 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallback("Skin_GuildRegistrar", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.guildregistrar then return end
+
+ GuildRegistrarFrame:StripTextures(true)
+ GuildRegistrarFrame:CreateBackdrop("Transparent")
+ GuildRegistrarFrame.backdrop:Point("TOPLEFT", 11, -12)
+ GuildRegistrarFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(GuildRegistrarFrame, "width")
+ S:SetBackdropHitRect(GuildRegistrarFrame)
+
+ S:HandleCloseButton(GuildRegistrarFrameCloseButton, GuildRegistrarFrame.backdrop)
+
+ GuildRegistrarGreetingFrame:StripTextures()
+
+ for i = 1, 2 do
+ S:HandleButtonHighlight(_G["GuildRegistrarButton"..i])
+ end
+
+ S:HandleButton(GuildRegistrarFrameGoodbyeButton)
+ S:HandleButton(GuildRegistrarFrameCancelButton)
+ S:HandleButton(GuildRegistrarFramePurchaseButton)
+
+ S:HandleEditBox(GuildRegistrarFrameEditBox)
+
+ local leftBG, rightBG = select(6, GuildRegistrarFrameEditBox:GetRegions())
+ leftBG:Kill()
+ rightBG:Kill()
+
+ AvailableServicesText:SetTextColor(1, 1, 0)
+ GuildRegistrarPurchaseText:SetTextColor(1, 1, 1)
+ GuildRegistrarButton1:GetFontString():SetTextColor(1, 1, 1)
+ GuildRegistrarButton2:GetFontString():SetTextColor(1, 1, 1)
+
+ GuildRegistrarFrameEditBox:Height(20)
+
+ GuildRegistrarFrameGoodbyeButton:Point("BOTTOMRIGHT", -40, 84)
+ GuildRegistrarFrameCancelButton:Point("BOTTOMRIGHT", -40, 84)
+ GuildRegistrarFramePurchaseButton:Point("BOTTOMLEFT", 19, 84)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Help.lua b/ElvUI/Modules/Skins/Blizzard/Help.lua
new file mode 100644
index 0000000..c970d8c
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Help.lua
@@ -0,0 +1,144 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local select = select
+--WoW API / Variables
+
+S:AddCallback("Skin_Help", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.help then return end
+
+ HelpFrame:StripTextures()
+ HelpFrame:CreateBackdrop("Transparent")
+ HelpFrame.backdrop:Point("TOPLEFT", 6, 0)
+ HelpFrame.backdrop:Point("BOTTOMRIGHT", -45, 14)
+
+ S:SetBackdropHitRect(HelpFrame)
+
+ S:HandleCloseButton(HelpFrameCloseButton, HelpFrame.backdrop)
+
+ local helpFrameButtons = {
+ "GMTalkOpenTicket",
+ "GMTalkCancel",
+ "ReportIssueOpenTicket",
+ "ReportIssueCancel",
+ "LagLoot",
+ "LagAuctionHouse",
+ "LagMail",
+ "LagChat",
+ "LagMovement",
+ "LagSpell",
+ "LagCancel",
+ "StuckStuck",
+ "StuckOpenTicket",
+ "StuckCancel",
+ "OpenTicketCancel",
+ "OpenTicketSubmit",
+ "ViewResponseCancel",
+ "ViewResponseMoreHelp",
+ "ViewResponseIssueResolved",
+ "WelcomeGMTalk",
+ "WelcomeReportIssue",
+ "WelcomeStuck",
+ "WelcomeCancel"
+ }
+
+ for i = 1, #helpFrameButtons do
+ S:HandleButton(_G["HelpFrame"..helpFrameButtons[i]])
+ end
+
+ KnowledgeBaseFrameDivider:StripTextures()
+ KnowledgeBaseFrameDivider2:StripTextures()
+ HelpFrameOpenTicketDivider:StripTextures()
+ HelpFrameViewResponseDivider:StripTextures()
+
+ local scrollBars = {
+ "HelpFrameOpenTicketScrollFrameScrollBar",
+ "HelpFrameViewResponseIssueScrollFrameScrollBar",
+ "HelpFrameViewResponseMessageScrollFrameScrollBar",
+ }
+
+ for _, scrollBar in ipairs(scrollBars) do
+ S:HandleScrollBar(_G[scrollBar])
+ _G[scrollBar.."Top"]:Hide()
+ _G[scrollBar.."Middle"]:Hide()
+ _G[scrollBar.."Bottom"]:Hide()
+ end
+
+ HelpFrameViewResponseIssueScrollFrame:CreateBackdrop("Transparent")
+ HelpFrameViewResponseIssueScrollFrame.backdrop:Point("TOPLEFT", -2, 2)
+ HelpFrameViewResponseIssueScrollFrame.backdrop:Point("BOTTOMRIGHT", 2, -2)
+
+ HelpFrameViewResponseMessageScrollFrame:CreateBackdrop("Transparent")
+ HelpFrameViewResponseMessageScrollFrame.backdrop:Point("TOPLEFT", -2, 2)
+ HelpFrameViewResponseMessageScrollFrame.backdrop:Point("BOTTOMRIGHT", 2, -2)
+
+ KnowledgeBaseFrame:StripTextures()
+
+ KnowledgeBaseFrame:HookScript("OnShow", function()
+ select(11, HelpFrame:GetRegions()):Hide()
+ end)
+
+ KnowledgeBaseFrame:SetScript("OnHide", function()
+ select(11, HelpFrame:GetRegions()):Show()
+ end)
+
+ S:HandleButton(GMChatOpenLog)
+ S:HandleButton(KnowledgeBaseFrameTopIssuesButton)
+
+ S:HandleEditBox(KnowledgeBaseFrameEditBox)
+ S:HandleDropDownBox(KnowledgeBaseFrameCategoryDropDown)
+ S:HandleDropDownBox(KnowledgeBaseFrameSubCategoryDropDown)
+ S:HandleButton(KnowledgeBaseFrameSearchButton)
+
+ S:HandleNextPrevButton(KnowledgeBaseArticleListFrameNextButton)
+ S:HandleNextPrevButton(KnowledgeBaseArticleListFramePreviousButton)
+
+ S:HandleScrollBar(KnowledgeBaseArticleScrollFrameScrollBar)
+ S:HandleButton(KnowledgeBaseArticleScrollChildFrameBackButton)
+
+ S:HandleButton(KnowledgeBaseFrameReportIssue)
+ S:HandleButton(KnowledgeBaseFrameGMTalk)
+ S:HandleButton(KnowledgeBaseFrameStuck)
+ S:HandleButton(KnowledgeBaseFrameLag)
+ S:HandleButton(KnowledgeBaseFrameCancel)
+ S:HandleButton(KnowledgeBaseFrameAbandonTicket)
+ S:HandleButton(KnowledgeBaseFrameEditTicket)
+
+ GMChatOpenLog:Point("TOPLEFT", 23, -22)
+ KnowledgeBaseFrameTopIssuesButton:Point("TOPRIGHT", -62, -118)
+ KnowledgeBaseFrameTopIssuesButton.Enable = E.noop
+ KnowledgeBaseFrameTopIssuesButton:Disable()
+
+ KnowledgeBaseFrameEditBox:Height(18)
+ KnowledgeBaseFrameEditBox:Point("TOPLEFT", KnowledgeBaseFrameDivider, "BOTTOMLEFT", 12, 10)
+ KnowledgeBaseFrameCategoryDropDown:Point("LEFT", KnowledgeBaseFrameEditBox, "RIGHT", -14, -3)
+ KnowledgeBaseFrameSubCategoryDropDown:Point("LEFT", KnowledgeBaseFrameCategoryDropDown, "RIGHT", -23, 0)
+
+ KnowledgeBaseFrameSearchButton:Height(20)
+ KnowledgeBaseFrameSearchButton:Point("LEFT", KnowledgeBaseFrameSubCategoryDropDown, "RIGHT", -2, 3)
+
+ KnowledgeBaseFrameReportIssue:Point("BOTTOMLEFT", 14, 22)
+ KnowledgeBaseFrameGMTalk:Point("BOTTOM", KnowledgeBaseFrameReportIssue, "TOP", 0, 3)
+ KnowledgeBaseFrameStuck:Point("LEFT", KnowledgeBaseFrameReportIssue, "RIGHT", 3, 0)
+ KnowledgeBaseFrameLag:Point("LEFT", KnowledgeBaseFrameGMTalk, "RIGHT", 3, 0)
+
+ KnowledgeBaseFrameAbandonTicket:Point("BOTTOMLEFT", 14, 22)
+ KnowledgeBaseFrameEditTicket:Point("BOTTOM", KnowledgeBaseFrameAbandonTicket, "TOP", 0, 3)
+
+ KnowledgeBaseFrameCancel:Point("BOTTOMRIGHT", -53, 22)
+ HelpFrameGMTalkCancel:Point("BOTTOMRIGHT", -53, 22)
+ HelpFrameLagCancel:Point("BOTTOMRIGHT", -53, 22)
+ HelpFrameReportIssueCancel:Point("BOTTOMRIGHT", -53, 22)
+ HelpFrameStuckCancel:Point("BOTTOMRIGHT", -53, 22)
+
+ HelpFrameOpenTicketCancel:Height(21)
+ HelpFrameOpenTicketCancel:Point("BOTTOMRIGHT", -53, 22)
+ HelpFrameOpenTicketSubmit:Point("RIGHT", HelpFrameOpenTicketCancel, "LEFT", -3, 0)
+
+ HelpFrameViewResponseMoreHelp:Point("BOTTOMLEFT", 14, 22)
+ HelpFrameViewResponseIssueResolved:Point("LEFT", HelpFrameViewResponseMoreHelp, "RIGHT", 3, 0)
+ HelpFrameViewResponseCancel:Height(21)
+ HelpFrameViewResponseCancel:Point("BOTTOMRIGHT", -53, 22)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Inspect.lua b/ElvUI/Modules/Skins/Blizzard/Inspect.lua
new file mode 100644
index 0000000..93edda4
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Inspect.lua
@@ -0,0 +1,190 @@
+local E, L, V, P, G = unpack(select(2, ...)) -- Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+--WoW API / Variables
+local GetInventoryItemID = GetInventoryItemID
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+
+S:AddCallbackForAddon("Blizzard_InspectUI", "Skin_Blizzard_InspectUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.inspect then return end
+
+ InspectFrame:StripTextures(true)
+ InspectFrame:CreateBackdrop("Transparent")
+ InspectFrame.backdrop:Point("TOPLEFT", 11, -12)
+ InspectFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(InspectFrame, "width")
+
+ S:SetBackdropHitRect(InspectFrame)
+ S:SetBackdropHitRect(InspectPVPFrame, InspectFrame.backdrop)
+ S:SetBackdropHitRect(InspectTalentFrame, InspectFrame.backdrop)
+
+ InspectPVPFrameHonor:SetHitRectInsets(0, 120, 0, 0)
+ InspectPVPFrameArena:SetHitRectInsets(0, 120, 0, 0)
+
+ S:HandleCloseButton(InspectFrameCloseButton, InspectFrame.backdrop)
+
+ S:HandleTab(InspectFrameTab1)
+ S:HandleTab(InspectFrameTab2)
+ S:HandleTab(InspectFrameTab3)
+
+ InspectPaperDollFrame:StripTextures()
+
+ local slots = {
+ "HeadSlot",
+ "NeckSlot",
+ "ShoulderSlot",
+ "BackSlot",
+ "ChestSlot",
+ "ShirtSlot",
+ "TabardSlot",
+ "WristSlot",
+ "HandsSlot",
+ "WaistSlot",
+ "LegsSlot",
+ "FeetSlot",
+ "Finger0Slot",
+ "Finger1Slot",
+ "Trinket0Slot",
+ "Trinket1Slot",
+ "MainHandSlot",
+ "SecondaryHandSlot",
+ "RangedSlot"
+ }
+
+ for _, slot in ipairs(slots) do
+ local icon = _G["Inspect"..slot.."IconTexture"]
+ local frame = _G["Inspect"..slot]
+
+ frame:StripTextures()
+ frame:SetFrameLevel(frame:GetFrameLevel() + 2)
+ frame:CreateBackdrop("Default")
+ frame.backdrop:SetAllPoints()
+
+ frame:StyleButton()
+
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetInside()
+ end
+
+ local styleButton
+ do
+ local function awaitCache(button)
+ if InspectFrame.unit then
+ styleButton(button)
+ end
+ end
+
+ styleButton = function(button)
+ if button.hasItem then
+ local itemID = GetInventoryItemID(InspectFrame.unit, button:GetID())
+ if itemID then
+ local _, _, quality = GetItemInfo(itemID)
+
+ if not quality then
+ E:Delay(0.1, awaitCache, button)
+ return
+ elseif quality then
+ button.backdrop:SetBackdropBorderColor(GetItemQualityColor(quality))
+ return
+ end
+ end
+ end
+
+ button.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end
+
+ hooksecurefunc("InspectPaperDollItemSlotButton_Update", styleButton)
+
+ S:HandleRotateButton(InspectModelRotateLeftButton)
+ S:HandleRotateButton(InspectModelRotateRightButton)
+
+ InspectPVPFrame:StripTextures()
+
+ for i = 1, MAX_ARENA_TEAMS do
+ local frame = _G["InspectPVPTeam"..i]
+ frame:StripTextures()
+ frame:CreateBackdrop("Transparent")
+ frame.backdrop:Point("TOPLEFT", 9, -6)
+ frame.backdrop:Point("BOTTOMRIGHT", -24, -5)
+ -- _G["InspectPVPTeam"..i.."StandardBar"]:Kill()
+ S:SetBackdropHitRect(frame)
+ end
+
+ InspectTalentFrame:StripTextures()
+
+ S:HandleCloseButton(InspectTalentFrameCloseButton, InspectFrame.backdrop)
+
+ for i = 1, MAX_TALENT_TABS do
+ local headerTab = _G["InspectTalentFrameTab"..i]
+
+ headerTab:StripTextures()
+ headerTab:CreateBackdrop("Default", true)
+ headerTab.backdrop:Point("TOPLEFT", 2, -7)
+ headerTab.backdrop:Point("BOTTOMRIGHT", 1, -1)
+ S:SetBackdropHitRect(headerTab)
+
+ headerTab:Width(i == 2 and 101 or 102)
+ headerTab.SetWidth = E.noop
+
+ headerTab:HookScript("OnEnter", S.SetModifiedBackdrop)
+ headerTab:HookScript("OnLeave", S.SetOriginalBackdrop)
+ end
+
+ for i = 1, MAX_NUM_TALENTS do
+ local talent = _G["InspectTalentFrameTalent"..i]
+
+ if talent then
+ local icon = _G["InspectTalentFrameTalent"..i.."IconTexture"]
+ local rank = _G["InspectTalentFrameTalent"..i.."Rank"]
+
+ talent:StripTextures()
+ talent:SetTemplate("Default")
+ talent:StyleButton()
+
+ icon:SetInside()
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetDrawLayer("ARTWORK")
+
+ rank:SetFont(E.LSM:Fetch("font", E.db.general.font), 12, "OUTLINE")
+ end
+ end
+
+ InspectHeadSlot:Point("TOPLEFT", 19, -76)
+ InspectHandsSlot:Point("TOPLEFT", 307, -76)
+ InspectMainHandSlot:Point("TOPLEFT", InspectPaperDollFrame, "BOTTOMLEFT", 121, 131)
+
+ InspectModelFrame:Size(237, 324)
+ InspectModelFrame:Point("TOPLEFT", 63, -76)
+
+ InspectModelRotateLeftButton:Point("TOPLEFT", 4, -4)
+
+ InspectTalentFrameScrollFrame:StripTextures()
+ InspectTalentFrameScrollFrame:CreateBackdrop("Transparent")
+ InspectTalentFrameScrollFrame.backdrop:Point("TOPLEFT", -1, 1)
+ InspectTalentFrameScrollFrame.backdrop:Point("BOTTOMRIGHT", 5, -4)
+
+ InspectTalentFramePointsBar:StripTextures()
+
+ InspectModelRotateRightButton:Point("TOPLEFT", InspectModelRotateLeftButton, "TOPRIGHT", 3, 0)
+
+ InspectFrameTab1:Point("CENTER", InspectFrame, "BOTTOMLEFT", 54, 62)
+ InspectFrameTab2:Point("LEFT", InspectFrameTab1, "RIGHT", -15, 0)
+ InspectFrameTab3:Point("LEFT", InspectFrameTab2, "RIGHT", -15, 0)
+
+ InspectTalentFrameBackgroundTopLeft:Point("TOPLEFT", 21, -77)
+
+ InspectTalentFrameTab1:Point("TOPLEFT", 17, -40)
+
+ InspectTalentFrameScrollFrame:Width(298)
+ InspectTalentFrameScrollFrame:Point("TOPRIGHT", -66, -77)
+
+ S:HandleScrollBar(InspectTalentFrameScrollFrameScrollBar)
+ InspectTalentFrameScrollFrameScrollBar:Point("TOPLEFT", InspectTalentFrameScrollFrame, "TOPRIGHT", 8, -18)
+ InspectTalentFrameScrollFrameScrollBar:Point("BOTTOMLEFT", InspectTalentFrameScrollFrame, "BOTTOMRIGHT", 8, 15)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/LFD.lua b/ElvUI/Modules/Skins/Blizzard/LFD.lua
new file mode 100644
index 0000000..ae97186
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/LFD.lua
@@ -0,0 +1,340 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+local find = string.find
+--WoW API / Variables
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local GetLFGDungeonRewardLink = GetLFGDungeonRewardLink
+local GetLFGDungeonRewards = GetLFGDungeonRewards
+local hooksecurefunc = hooksecurefunc
+
+S:AddCallback("Skin_LFD", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.lfd then return end
+
+ AscensionLFGFrame:StripTextures(true)
+ AscensionLFGFrame:CreateBackdrop("Transparent")
+ AscensionLFGFrameContent:StripTextures(true)
+ AscensionLFGFrameMenu:StripTextures(true)
+ AscensionLFGFrameInset:StripTextures(true)
+ AscensionLFGFrameInset:CreateBackdrop("Transparent")
+ AscensionLFGFrameInsetNineSlice:StripTextures(true)
+ AscensionLFGFrameNineSlice:StripTextures(true)
+ AscensionLFGFrameMenuNineSlice:StripTextures(true)
+
+ AscensionPVEFrameLFDFrame:StripTextures(true)
+ AscensionPVEFrameLFDFrame:CreateBackdrop("Transparent")
+ AscensionPVEFrameLFDFrameRandom:StripTextures(true)
+ AscensionPVEFrameLFDFrameRandomScrollFrame:StripTextures(true)
+
+ S:HookScript(LFDParentFrame, "OnShow", function(self)
+ S:SetUIPanelWindowInfo(self, "width", 341)
+ S:SetBackdropHitRect(self, AscensionLFGFrame.backdrop)
+ S:Unhook(self, "OnShow")
+ end)
+
+ S:HandleCloseButton(AscensionLFGFrameCloseButton)
+
+ LFDParentFramePortrait:Kill()
+
+ -- Role Checkboxes
+ S:HandleCheckBox(AscensionPVEFrameLFDFrameRoleButtonTank.checkButton)
+ AscensionPVEFrameLFDFrameRoleButtonTank.checkButton:SetFrameLevel(AscensionPVEFrameLFDFrameRoleButtonTank.checkButton:GetFrameLevel() + 2)
+ S:HandleCheckBox(AscensionPVEFrameLFDFrameRoleButtonHealer.checkButton)
+ AscensionPVEFrameLFDFrameRoleButtonHealer.checkButton:SetFrameLevel(AscensionPVEFrameLFDFrameRoleButtonHealer.checkButton:GetFrameLevel() + 2)
+ S:HandleCheckBox(AscensionPVEFrameLFDFrameRoleButtonDPS.checkButton)
+ AscensionPVEFrameLFDFrameRoleButtonDPS.checkButton:SetFrameLevel(AscensionPVEFrameLFDFrameRoleButtonDPS.checkButton:GetFrameLevel() + 2)
+ S:HandleCheckBox(AscensionPVEFrameLFDFrameRoleButtonLeader.checkButton)
+ AscensionPVEFrameLFDFrameRoleButtonLeader.checkButton:SetFrameLevel(AscensionPVEFrameLFDFrameRoleButtonLeader.checkButton:GetFrameLevel() + 2)
+
+ -- Dropdown
+ S:HandleDropDownBox(AscensionPVEFrameLFDFrameTypeDropDown)
+ AscensionPVEFrameLFDFrameTypeDropDown:HookScript("OnShow", function(self) self:Width(200) end)
+
+ -- Specific Dungeons
+ for i = 1, NUM_LFD_CHOICE_BUTTONS do
+ local button = _G["AscensionPVEFrameLFDFrameSpecificListButton"..i]
+ button.enableButton:StripTextures()
+ button.enableButton:CreateBackdrop("Default")
+ button.enableButton.backdrop:SetInside(nil, 4, 4)
+
+ button.expandOrCollapseButton:SetNormalTexture(E.Media.Textures.Plus)
+ button.expandOrCollapseButton.SetNormalTexture = E.noop
+ button.expandOrCollapseButton:GetNormalTexture():Size(16)
+
+ button.expandOrCollapseButton:SetHighlightTexture(nil)
+
+ hooksecurefunc(button.expandOrCollapseButton, "SetNormalTexture", function(self, texture)
+ if find(texture, "MinusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Minus)
+ elseif find(texture, "PlusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Plus)
+ end
+ end)
+ end
+
+ AscensionPVEFrameLFDFrameSpecificListScrollFrame:StripTextures()
+ S:HandleScrollBar(AscensionPVEFrameLFDFrameRandomScrollFrameScrollBar)
+ S:HandleScrollBar(AscensionPVEFrameLFDFrameSpecificListScrollFrameScrollBar)
+
+ --Side menu buttons
+ for i = 1, 3 do
+ local sidebutton = _G["AscensionLFGFrameButton"..i]
+ S:HandleButton(sidebutton)
+ end
+
+ --Tabs
+ for i = 1, 3 do
+ local tab = _G["AscensionLFGFrameTab"..i]
+ tab:Size(122, 32)
+ tab:GetRegions():SetPoint("CENTER", 0, 2)
+ S:HandleTab(tab)
+ end
+
+ S:HandleButton(AscensionPVEFrameLFDFrameFindGroupButton)
+ --S:HandleButton(AscensionPVEFrameLFDFrameCancelButton)
+
+ --S:HandleButton(AscensionPVEFrameLFDFramePartyBackfillBackfillButton)
+ --S:HandleButton(AscensionPVEFrameLFDFramePartyBackfillNoBackfillButton)
+
+ S:HandleButton(AscensionPVEFrameLFDFrameNoLFDWhileLFRLeaveQueueButton)
+
+ AscensionPVEFrameLFDFrameRandomScrollFrameScrollBar:Point("TOPLEFT", AscensionPVEFrameLFDFrameRandomScrollFrame, "TOPRIGHT", 5, -22)
+ AscensionPVEFrameLFDFrameRandomScrollFrameScrollBar:Point("BOTTOMLEFT", AscensionPVEFrameLFDFrameRandomScrollFrame, "BOTTOMRIGHT", 5, 19)
+
+ AscensionPVEFrameLFDFrameSpecificListScrollFrameScrollBar:Point("TOPLEFT", AscensionPVEFrameLFDFrameSpecificListScrollFrame, "TOPRIGHT", 5, -17)
+ AscensionPVEFrameLFDFrameSpecificListScrollFrameScrollBar:Point("BOTTOMLEFT", AscensionPVEFrameLFDFrameSpecificListScrollFrame, "BOTTOMRIGHT", 5, 17)
+
+ AscensionPVEFrameLFDFrameFindGroupButton:Point("BOTTOMLEFT", 19, 10)
+ --AscensionPVEFrameLFDFrameCancelButton:Point("BOTTOMRIGHT", -11, 12)
+
+ --AscensionPVEFrameLFDFrameTypeDropDown:Point("TOPLEFT", 152, -119)
+
+ --AscensionPVEFrameLFDFrameSpecificListButton1:Point("TOPLEFT", 25, -154)
+ AscensionPVEFrameLFDFrameRandomScrollFrame:Point("BOTTOMRIGHT", -34, 41)
+
+ --AscensionPVEFrameLFDFrameCooldownFrame:Size(325, 259)
+ --AscensionPVEFrameLFDFrameCooldownFrame:Point("BOTTOMRIGHT", AscensionPVEFrameLFDFrame, "BOTTOMRIGHT", -11, 37)
+
+ --[[AscensionPVEFrameLFDFrameCooldownFrame:HookScript("OnShow", function(self)
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() + 5)
+ end)
+ --]]
+
+ -- PvP Tab
+ -- Progress Bar
+ --Honor
+ S:HandleStatusBar(AscensionPVPFrameHonorBar)
+ --Arena
+ S:HandleStatusBar(AscensionPVPFrameArenaBar)
+
+ -- Quick Match
+ AscensionPVPFrame:StripTextures(true)
+ AscensionPVPFrame:CreateBackdrop("Transparent")
+ AscensionPVPFrameCasualFrame:StripTextures(true)
+ AscensionPVPFrameCasualFrame:CreateBackdrop("Transparent")
+ AscensionPVPFrameCasualFrameInset:StripTextures(true)
+ AscensionPVPFrameCasualFrameInset:CreateBackdrop("Transparent")
+ AscensionPVPFrameCasualFrameInsetNineSlice:StripTextures(true)
+ -- Buttons (Queues)
+ S:HandleButton(AscensionPVPFrameCasualFrameRandomBGButton)
+ S:HandleButton(AscensionPVPFrameCasualFrameCallToArmsButton1)
+ S:HandleButton(AscensionPVPFrameCasualFrameSkirmish1v1Button)
+ S:HandleButton(AscensionPVPFrameCasualFrameSkirmish2v2Button)
+ S:HandleButton(AscensionPVPFrameCasualFrameSkirmish3v3Button)
+ -- Honor Section
+ AscensionPVPFrameHonorInset:StripTextures(true)
+ AscensionPVPFrameHonorInset:CreateBackdrop("Transparent")
+ AscensionPVPFrameHonorInsetNineSlice:StripTextures(true)
+
+ -- Buttons
+ S:HandleButton(AscensionPVPFrameCasualFrameQueueButton)
+ S:HandleButton(AscensionPVPFrameCasualFrameSoloQueueButton)
+
+ --Rated Tab
+ AscensionPVPFrameRatedFrame:StripTextures(true)
+ AscensionPVPFrameRatedFrame:CreateBackdrop("Transparent")
+ AscensionPVPFrameRatedFrameInset:StripTextures(true)
+ AscensionPVPFrameRatedFrameInset:CreateBackdrop("Transparent")
+ AscensionPVPFrameRatedFrameInsetNineSlice:StripTextures(true)
+ -- Buttons (Rated)
+ S:HandleButton(AscensionPVPFrameRatedFrameArena1v1)
+ S:HandleButton(AscensionPVPFrameRatedFrameArena2v2)
+ S:HandleButton(AscensionPVPFrameRatedFrameArena3v3)
+ S:HandleButton(AscensionPVPFrameRatedFrameSoloQueueButton)
+ S:HandleButton(AscensionPVPFrameRatedFrameQueueButton)
+
+ -- PvP Ruleset
+ AscensionRulesetFrame:StripTextures(true)
+
+ --[[for i = 1, 3 do
+ local pvpruleset = _G["AscensionRulesetFrameRuleset"..i]
+ --pvpruleset:StripTextures(true)
+ S:HandleButton(pvpruleset.Select)
+ end
+ ]]--
+
+ local function skinLFDRandomDungeonLoot(frame)
+ if frame.isSkinned then return end
+
+ local icon = _G[frame:GetName().."IconTexture"]
+ local nameFrame = _G[frame:GetName().."NameFrame"]
+ local count = _G[frame:GetName().."Count"]
+
+ frame:StripTextures()
+ frame:CreateBackdrop("Transparent")
+ frame.backdrop:SetOutside(icon)
+
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetDrawLayer("BORDER")
+ icon:SetParent(frame.backdrop)
+
+ nameFrame:SetSize(118, 39)
+
+ count:SetParent(frame.backdrop)
+
+ frame.isSkinned = true
+ end
+
+ local function getLFGDungeonRewardLinkFix(dungeonID, rewardIndex)
+ local _, link = GetLFGDungeonRewardLink(dungeonID, rewardIndex)
+
+ if not link then
+ E.ScanTooltip:SetOwner(UIParent, "ANCHOR_NONE")
+ E.ScanTooltip:SetLFGDungeonReward(dungeonID, rewardIndex)
+ _, link = E.ScanTooltip:GetItem()
+ E.ScanTooltip:Hide()
+ end
+
+ return link
+ end
+
+ --[[hooksecurefunc("AscensionPVEFrameLFDFrameRandom_UpdateFrame", function()
+ local dungeonID = AscensionPVEFrameLFDFrame.type
+ if not dungeonID then return end
+
+ local _, _, _, _, _, numRewards = GetLFGDungeonRewards(dungeonID)
+ for i = 1, numRewards do
+ local frame = _G["AscensionPVEFrameLFDFrameRandomScrollFrameChildFrameItem"..i]
+ local name = _G["AscensionPVEFrameLFDFrameRandomScrollFrameChildFrameItem"..i.."Name"]
+
+ skinLFDRandomDungeonLoot(frame)
+
+ local link = getLFGDungeonRewardLinkFix(dungeonID, i)
+ if link then
+ local _, _, quality = GetItemInfo(link)
+ if quality then
+ local r, g, b = GetItemQualityColor(quality)
+ frame.backdrop:SetBackdropBorderColor(r, g, b)
+ name:SetTextColor(r, g, b)
+ end
+ else
+ frame.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ name:SetTextColor(1, 1, 1)
+ end
+ end
+ end)
+ --]]
+
+ -- LFDDungeonReadyStatus
+ LFDDungeonReadyStatus:SetTemplate("Transparent")
+ S:HandleCloseButton(LFDDungeonReadyStatusCloseButton, nil, "-")
+
+ LFDSearchStatus:SetTemplate("Transparent")
+
+ -- LFDRoleCheckPopup
+ LFDRoleCheckPopup:SetTemplate("Transparent")
+
+ S:HandleCheckBox(LFDRoleCheckPopupRoleButtonTank.checkButton)
+ S:HandleCheckBox(LFDRoleCheckPopupRoleButtonHealer.checkButton)
+ S:HandleCheckBox(LFDRoleCheckPopupRoleButtonDPS.checkButton)
+
+ S:HandleButton(LFDRoleCheckPopupAcceptButton)
+ S:HandleButton(LFDRoleCheckPopupDeclineButton)
+
+ -- LFDDungeonReadyDialog
+ LFDDungeonReadyDialog:SetTemplate("Transparent")
+
+ LFDDungeonReadyDialog.label:Size(280, 0)
+ LFDDungeonReadyDialog.label:Point("TOP", 0, -10)
+
+ LFDDungeonReadyDialog:CreateBackdrop("Default")
+ LFDDungeonReadyDialog.backdrop:Point("TOPLEFT", 10, -35)
+ LFDDungeonReadyDialog.backdrop:Point("BOTTOMRIGHT", -10, 40)
+
+ LFDDungeonReadyDialog.backdrop:SetFrameLevel(LFDDungeonReadyDialog:GetFrameLevel())
+ LFDDungeonReadyDialog.background:SetInside(LFDDungeonReadyDialog.backdrop)
+
+ LFDDungeonReadyDialogFiligree:SetTexture("")
+ LFDDungeonReadyDialogBottomArt:SetTexture("")
+
+ S:HandleCloseButton(LFDDungeonReadyDialogCloseButton, nil, "-")
+
+ LFDDungeonReadyDialogEnterDungeonButton:Point("BOTTOMRIGHT", LFDDungeonReadyDialog, "BOTTOM", -7, 10)
+ S:HandleButton(LFDDungeonReadyDialogEnterDungeonButton)
+ LFDDungeonReadyDialogLeaveQueueButton:Point("BOTTOMLEFT", LFDDungeonReadyDialog, "BOTTOM", 7, 10)
+ S:HandleButton(LFDDungeonReadyDialogLeaveQueueButton)
+
+--[[
+ LFDDungeonReadyDialogRoleIcon:Size(57)
+ LFDDungeonReadyDialogRoleIcon:Point("BOTTOM", 1, 54)
+ LFDDungeonReadyDialogRoleIcon:SetTemplate("Default")
+ LFDDungeonReadyDialogRoleIconTexture:SetInside()
+
+ function GetTexCoordsForRole(role)
+ if role == "GUIDE" then
+ return 0.0625, 0.1953125, 0.05859375, 0.19140625
+ elseif role == "TANK" then
+ return 0.0625, 0.1953125, 0.3203125, 0.453125
+ elseif role == "HEALER" ) then
+ return 0.32421875, 0.45703125, 0.0546875, 0.1875
+ elseif role == "DAMAGER" then
+ return 0.32421875, 0.453125, 0.31640625, 0.4453125
+ end
+ end
+ GameTooltip:SetLFGDungeonReward(287, 1)
+--]]
+
+ local function skinLFDDungeonReadyDialogReward(button)
+ if button.isSkinned then return end
+
+ button:Size(28)
+ button:SetTemplate("Default")
+ if button.texture ~= nil then
+ button.texture:SetInside()
+ button.texture:SetTexCoord(unpack(E.TexCoords))
+ end
+ button:DisableDrawLayer("OVERLAY")
+
+ button.isSkinned = true
+ end
+
+ hooksecurefunc("LFDDungeonReadyDialogReward_SetMisc", function(button)
+ skinLFDDungeonReadyDialogReward(button)
+
+ SetPortraitToTexture(button.texture, "")
+ button.texture:SetTexture("Interface\\Icons\\inv_misc_coin_02")
+ end)
+
+ hooksecurefunc("LFDDungeonReadyDialogReward_SetReward", function(button, dungeonID, rewardIndex)
+ skinLFDDungeonReadyDialogReward(button)
+
+ local link = getLFGDungeonRewardLinkFix(dungeonID, rewardIndex)
+ if link then
+ local _, _, quality = GetItemInfo(link)
+ button:SetBackdropBorderColor(GetItemQualityColor(quality))
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ if button.texture ~= nil then
+ local texturePath = button.texture:GetTexture()
+ if texturePath then
+ SetPortraitToTexture(button.texture, "")
+ button.texture:SetTexture(texturePath)
+ end
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/LFR.lua b/ElvUI/Modules/Skins/Blizzard/LFR.lua
new file mode 100644
index 0000000..4455009
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/LFR.lua
@@ -0,0 +1,104 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local find = string.find
+--WoW API / Variables
+local hooksecurefunc = hooksecurefunc
+
+S:AddCallback("Skin_LFR", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.lfr then return end
+
+ LFRParentFrame:StripTextures()
+ LFRParentFrame:CreateBackdrop("Transparent")
+ LFRParentFrame.backdrop:Point("TOPLEFT", 11, -12)
+ LFRParentFrame.backdrop:Point("BOTTOMRIGHT", -3, 4)
+
+ S:HookScript(LFRParentFrame, "OnShow", function(self)
+ S:SetUIPanelWindowInfo(self, "width")
+ S:SetBackdropHitRect(self)
+ S:Unhook(self, "OnShow")
+ end)
+
+ S:HandleCloseButton((LFRParentFrame:GetChildren()), LFRParentFrame.backdrop)
+
+ LFRQueueFrame:StripTextures()
+ LFRBrowseFrame:StripTextures()
+
+ local buttons = {
+ LFRQueueFrameFindGroupButton,
+ LFRQueueFrameAcceptCommentButton,
+ LFRBrowseFrameSendMessageButton,
+ LFRBrowseFrameInviteButton,
+ LFRBrowseFrameRefreshButton,
+ LFRQueueFrameNoLFRWhileLFDLeaveQueueButton
+ }
+ for i = 1, #buttons do
+ S:HandleButton(buttons[i], true)
+ end
+
+ S:HandleTab(LFRParentFrameTab1)
+ S:HandleTab(LFRParentFrameTab2)
+
+ S:HandleDropDownBox(LFRBrowseFrameRaidDropDown)
+ S:HandleScrollBar(LFRQueueFrameSpecificListScrollFrameScrollBar)
+
+ LFRQueueFrameCommentTextButton:CreateBackdrop("Default")
+
+ --DPS, Healer, Tank check button's don't have a name, use it's parent as a referance.
+ S:HandleCheckBox((LFRQueueFrameRoleButtonTank:GetChildren()))
+ S:HandleCheckBox((LFRQueueFrameRoleButtonHealer:GetChildren()))
+ S:HandleCheckBox((LFRQueueFrameRoleButtonDPS:GetChildren()))
+ LFRQueueFrameRoleButtonTank:GetChildren():SetFrameLevel(LFRQueueFrameRoleButtonTank:GetChildren():GetFrameLevel() + 2)
+ LFRQueueFrameRoleButtonHealer:GetChildren():SetFrameLevel(LFRQueueFrameRoleButtonHealer:GetChildren():GetFrameLevel() + 2)
+ LFRQueueFrameRoleButtonDPS:GetChildren():SetFrameLevel(LFRQueueFrameRoleButtonDPS:GetChildren():GetFrameLevel() + 2)
+
+ LFRQueueFrameSpecificListScrollFrame:StripTextures()
+
+ for i = 1, 7 do
+ local button = "LFRBrowseFrameColumnHeader"..i
+ _G[button.."Left"]:Kill()
+ _G[button.."Middle"]:Kill()
+ _G[button.."Right"]:Kill()
+ _G[button]:StyleButton()
+ end
+
+ for i = 1, NUM_LFR_CHOICE_BUTTONS do
+ local button = _G["LFRQueueFrameSpecificListButton"..i]
+ S:HandleCheckBox(button.enableButton)
+
+ button.expandOrCollapseButton:SetNormalTexture(E.Media.Textures.Plus)
+ button.expandOrCollapseButton.SetNormalTexture = E.noop
+ button.expandOrCollapseButton:GetNormalTexture():Size(16)
+
+ button.expandOrCollapseButton:SetHighlightTexture(nil)
+
+ hooksecurefunc(button.expandOrCollapseButton, "SetNormalTexture", function(self, texture)
+ if find(texture, "MinusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Minus)
+ elseif find(texture, "PlusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Plus)
+ end
+ end)
+ end
+
+ LFRQueueFrameSpecificListScrollFrameScrollBar:Point("TOPLEFT", LFRQueueFrameSpecificListScrollFrame, "TOPRIGHT", 5, -17)
+ LFRQueueFrameSpecificListScrollFrameScrollBar:Point("BOTTOMLEFT", LFRQueueFrameSpecificListScrollFrame, "BOTTOMRIGHT", 5, 17)
+
+ LFRQueueFrameNoLFRWhileLFD:Size(325, 271)
+ LFRQueueFrameNoLFRWhileLFD:Point("BOTTOMRIGHT", -11, 41)
+
+ LFRQueueFrameComment:Width(323)
+ LFRQueueFrameComment:Point("TOPLEFT", LFRQueueFrame, "BOTTOMLEFT", 20, 74)
+
+ LFRQueueFrameCommentTextButton:Size(323, 32)
+
+ LFRQueueFrameFindGroupButton:Point("BOTTOMLEFT", 19, 12)
+ LFRQueueFrameAcceptCommentButton:Point("BOTTOMRIGHT", -11, 12)
+ LFRBrowseFrameSendMessageButton:Point("BOTTOMLEFT", 19, 12)
+ LFRBrowseFrameInviteButton:Point("LEFT", LFRBrowseFrameSendMessageButton, "RIGHT", 4, 0)
+ LFRBrowseFrameRefreshButton:Point("LEFT", LFRBrowseFrameInviteButton, "RIGHT", 4, 0)
+
+ LFRParentFrameTab1:Point("BOTTOMLEFT", 11, -26)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Load_Blizzard.xml b/ElvUI/Modules/Skins/Blizzard/Load_Blizzard.xml
new file mode 100644
index 0000000..8cfb2ac
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Load_Blizzard.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Loot.lua b/ElvUI/Modules/Skins/Blizzard/Loot.lua
new file mode 100644
index 0000000..58faa2e
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Loot.lua
@@ -0,0 +1,198 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack, select = unpack, select
+--WoW API / Variables
+local GetItemQualityColor = GetItemQualityColor
+local GetLootRollItemInfo = GetLootRollItemInfo
+local GetLootSlotInfo = GetLootSlotInfo
+local IsFishingLoot = IsFishingLoot
+local LootSlotIsCoin = LootSlotIsCoin
+local LootSlotIsItem = LootSlotIsItem
+local UnitIsDead = UnitIsDead
+local UnitIsFriend = UnitIsFriend
+local UnitName = UnitName
+
+local ITEMS = ITEMS
+local LOOT = LOOT
+local LOOTFRAME_NUMBUTTONS = LOOTFRAME_NUMBUTTONS
+
+S:AddCallback("Skin_Loot", function()
+ if E.private.general.loot then return end
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.loot then return end
+
+ local LootFrame = _G.LootFrame
+ LootFrame:StripTextures()
+
+ LootFrame:CreateBackdrop("Transparent")
+ LootFrame.backdrop:Point("TOPLEFT", 16, -54)
+ LootFrame.backdrop:Point("BOTTOMRIGHT", -77, 8)
+
+ S:SetBackdropHitRect(LootFrame, nil, true)
+
+ LootFramePortraitOverlay:SetParent(E.HiddenFrame)
+
+ S:HandleNextPrevButton(LootFrameUpButton)
+ LootFrameUpButton:Point("BOTTOMLEFT", 25, 20)
+ LootFrameUpButton:Size(24)
+
+ S:HandleNextPrevButton(LootFrameDownButton)
+ LootFrameDownButton:Point("BOTTOMLEFT", 147, 21)
+ LootFrameDownButton:Size(24)
+
+ LootFrame:EnableMouseWheel(true)
+ LootFrame:SetScript("OnMouseWheel", function(_, value)
+ if value > 0 then
+ if LootFrameUpButton:IsShown() and LootFrameUpButton:IsEnabled() == 1 then
+ LootFrame_PageUp()
+ end
+ else
+ if LootFrameDownButton:IsShown() and LootFrameDownButton:IsEnabled() == 1 then
+ LootFrame_PageDown()
+ end
+ end
+ end)
+
+ S:HandleCloseButton(LootCloseButton)
+ LootCloseButton:Point("CENTER", LootFrame, "TOPRIGHT", -88, -65)
+
+ for i = 1, LootFrame:GetNumRegions() do
+ local region = select(i, LootFrame:GetRegions())
+ if region:GetObjectType() == "FontString" then
+ if region:GetText() == ITEMS then
+ LootFrame.Title = region
+ end
+ end
+ end
+
+ LootFrame.Title:ClearAllPoints()
+ LootFrame.Title:Point("TOPLEFT", LootFrame.backdrop, "TOPLEFT", 4, -4)
+ LootFrame.Title:SetJustifyH("LEFT")
+ LootFrame.Title:SetWordWrap(false)
+ LootFrame.Title:SetWidth(142)
+
+ LootFrame:HookScript("OnShow", function(self)
+ if IsFishingLoot() then
+ self.Title:SetText(L["Fishy Loot"])
+ elseif not UnitIsFriend("player", "target") and UnitIsDead("target") then
+ self.Title:SetText(UnitName("target"))
+ else
+ self.Title:SetText(LOOT)
+ end
+ end)
+
+ for i = 1, LOOTFRAME_NUMBUTTONS do
+ local button = _G["LootButton"..i]
+ local nameFrame = _G["LootButton"..i.."NameFrame"]
+
+ S:HandleItemButton(button, true)
+
+ button.bg = CreateFrame("Frame", nil, button)
+ button.bg:SetTemplate("Default")
+ button.bg:Point("TOPLEFT", 40, 0)
+ button.bg:Point("BOTTOMRIGHT", 110, 0)
+ button.bg:SetFrameLevel(button.bg:GetFrameLevel() - 1)
+
+ local questTexture = button:CreateTexture(nil, "OVERLAY")
+ questTexture:SetInside()
+ questTexture:SetTexture(E.Media.Textures.BagQuestIcon)
+ button.questTexture = questTexture
+
+ nameFrame:Hide()
+ end
+
+ hooksecurefunc("LootFrame_UpdateButton", function(index)
+ local numLootItems = LootFrame.numLootItems
+ local numLootToShow = LOOTFRAME_NUMBUTTONS
+
+ if numLootItems > LOOTFRAME_NUMBUTTONS then
+ numLootToShow = numLootToShow - 1
+ end
+
+ local slot = (numLootToShow * (LootFrame.page - 1)) + index
+
+ if slot <= numLootItems then
+ if index <= numLootToShow and (LootSlotIsItem(slot) or LootSlotIsCoin(slot)) then
+ local texture, _, _, quality, _, isQuestItem, questId, isActive = GetLootSlotInfo(slot)
+
+ if texture then
+ local button = _G["LootButton"..index]
+
+ if questId and not isActive then
+ button.backdrop:SetBackdropBorderColor(1.0, 1.0, 0.0)
+ button.questTexture:Show()
+ return
+ elseif questId or isQuestItem then
+ button.backdrop:SetBackdropBorderColor(1.0, 0.3, 0.3)
+ elseif quality then
+ button.backdrop:SetBackdropBorderColor(GetItemQualityColor(quality))
+ else
+ button.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+
+ button.questTexture:Hide()
+ end
+ end
+ end
+ end)
+end)
+
+S:AddCallback("Skin_LootRoll", function()
+ if E.private.general.lootRoll then return end
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.lootRoll then return end
+
+ local function OnShow(self)
+ local frameName = self:GetName()
+ local iconFrame = _G[frameName.."IconFrame"]
+ local statusBar = _G[frameName.."Timer"]
+ local _, _, _, quality = GetLootRollItemInfo(self.rollID)
+ local r, g, b = GetItemQualityColor(quality)
+
+ self:SetTemplate("Transparent")
+
+ iconFrame:SetBackdropBorderColor(r, g, b)
+ statusBar:SetStatusBarColor(r, g, b)
+ end
+
+ for i = 1, NUM_GROUP_LOOT_FRAMES do
+ local frameName = "GroupLootFrame"..i
+ local frame = _G[frameName]
+ local iconFrame = _G[frameName.."IconFrame"]
+ local icon = _G[frameName.."IconFrameIcon"]
+ local statusBar = _G[frameName.."Timer"]
+ local decoration = _G[frameName.."Decoration"]
+
+ frame:EnableMouse(true)
+ frame:StripTextures()
+ frame:ClearAllPoints()
+
+ if i == 1 then
+ frame:Point("TOP", AlertFrameHolder, "BOTTOM", 0, -4)
+ else
+ frame:Point("TOP", _G["GroupLootFrame"..i - 1], "BOTTOM", 0, -4)
+ end
+
+ iconFrame:SetTemplate("Default")
+ iconFrame:StyleButton()
+
+ icon:SetInside()
+ icon:SetTexCoord(unpack(E.TexCoords))
+
+ statusBar:StripTextures()
+ statusBar:CreateBackdrop("Default")
+ statusBar:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(statusBar)
+
+ decoration:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Gold-Dragon")
+ decoration:Size(130)
+ decoration:Point("TOPLEFT", -37, 20)
+
+ S:HandleCloseButton(_G[frameName.."PassButton"], frame)
+
+ _G[frameName.."Corner"]:Hide()
+
+ frame:HookScript("OnShow", OnShow)
+ end
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Macro.lua b/ElvUI/Modules/Skins/Blizzard/Macro.lua
new file mode 100644
index 0000000..09bd343
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Macro.lua
@@ -0,0 +1,131 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+--WoW API / Variables
+
+S:AddCallbackForAddon("Blizzard_MacroUI", "Skin_Blizzard_MacroUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.macro then return end
+
+ MacroFrame:StripTextures()
+ MacroFrame:CreateBackdrop("Transparent")
+ MacroFrame.backdrop:Point("TOPLEFT", 11, -12)
+ MacroFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(MacroFrame, "width")
+ S:SetBackdropHitRect(MacroFrame)
+
+ S:HandleCloseButton(MacroFrameCloseButton, MacroFrame.backdrop)
+
+ MacroButtonScrollFrame:StripTextures()
+ MacroButtonScrollFrame:CreateBackdrop("Transparent")
+
+ S:HandleScrollBar(MacroButtonScrollFrameScrollBar)
+ S:HandleScrollBar(MacroFrameScrollFrameScrollBar)
+
+ MacroFrameSelectedMacroButton:StripTextures()
+ MacroFrameSelectedMacroButton:StyleButton(nil, true)
+ MacroFrameSelectedMacroButton:GetNormalTexture():SetTexture(nil)
+ MacroFrameSelectedMacroButton:SetTemplate()
+
+ MacroFrameSelectedMacroButtonIcon:SetTexCoord(unpack(E.TexCoords))
+ MacroFrameSelectedMacroButtonIcon:SetInside()
+
+ MacroFrameTextBackground:StripTextures()
+ MacroFrameTextBackground:CreateBackdrop()
+ MacroFrameTextBackground.backdrop:Point("TOPLEFT", 1, -3)
+ MacroFrameTextBackground.backdrop:Point("BOTTOMRIGHT", -17, 3)
+
+ S:HandleButton(MacroEditButton)
+ S:HandleButton(MacroDeleteButton)
+ S:HandleButton(MacroExitButton)
+ S:HandleButton(MacroNewButton)
+
+ for i = 1, 2 do
+ local tab = _G["MacroFrameTab"..i]
+ tab:StripTextures()
+ S:HandleButton(tab)
+
+ tab:Height(22)
+
+ if i == 1 then
+ tab:Point("TOPLEFT", 19, -50)
+ tab:Width(125)
+ elseif i == 2 then
+ tab:Point("LEFT", MacroFrameTab1, "RIGHT", 3, 0)
+ tab:Width(176)
+ end
+
+ tab.SetWidth = E.noop
+ end
+
+ for i = 1, MAX_ACCOUNT_MACROS do
+ local button = _G["MacroButton"..i]
+ local buttonIcon = _G["MacroButton"..i.."Icon"]
+
+ if button then
+ button:StripTextures()
+ button:SetTemplate(nil, true)
+ button:StyleButton(nil, true)
+
+ buttonIcon:SetTexCoord(unpack(E.TexCoords))
+ buttonIcon:SetInside()
+ end
+ end
+
+ MacroButtonScrollFrame:Size(302, 142)
+ MacroButtonScrollFrame:Point("TOPLEFT", 20, -76)
+
+ MacroButtonScrollFrameScrollBar:Point("TOPLEFT", MacroButtonScrollFrame, "TOPRIGHT", 4, -18)
+ MacroButtonScrollFrameScrollBar:Point("BOTTOMLEFT", MacroButtonScrollFrame, "BOTTOMRIGHT", 4, 18)
+
+ MacroButton1:Point("TOPLEFT", 10, -7)
+
+ MacroEditButton:Point("TOPLEFT", MacroFrameSelectedMacroBackground, "TOPLEFT", 60, -28)
+
+ MacroFrameTextBackground:Point("TOPLEFT", 18, -290)
+
+ MacroFrameText:Width(297)
+
+ MacroFrameSelectedMacroBackground:Point("TOPLEFT", 16, -213)
+
+ MacroFrameScrollFrame:Size(300, 81)
+ MacroFrameScrollFrame:Point("TOPLEFT", MacroFrameSelectedMacroBackground, "BOTTOMLEFT", 5, -20)
+
+ MacroFrameScrollFrameScrollBar:Point("TOPLEFT", MacroFrameScrollFrame, "TOPRIGHT", 5, -15)
+ MacroFrameScrollFrameScrollBar:Point("BOTTOMLEFT", MacroFrameScrollFrame, "BOTTOMRIGHT", 5, 15)
+
+ MacroFrameCharLimitText:Point("BOTTOM", -15, 113)
+
+ MacroDeleteButton:Point("BOTTOMLEFT", 19, 84)
+ MacroExitButton:Point("CENTER", MacroFrame, "TOPLEFT", 304, -417)
+ MacroNewButton:Point("CENTER", MacroFrame, "TOPLEFT", 221, -417)
+
+ -- Popup frame
+ S:HandleIconSelectionFrame(MacroPopupFrame, NUM_MACRO_ICONS_SHOWN, "MacroPopupButton", "MacroPopup")
+
+ S:SetBackdropHitRect(MacroPopupFrame)
+ MacroPopupFrame:Point("TOPLEFT", MacroFrame, "TOPRIGHT", -43, 0)
+
+ MacroPopupScrollFrame:SetTemplate("Transparent")
+
+ S:HandleScrollBar(MacroPopupScrollFrameScrollBar)
+
+ local text1, text2 = select(5, MacroPopupFrame:GetRegions())
+ text1:Point("TOPLEFT", 24, -18)
+ text2:Point("TOPLEFT", 24, -60)
+
+ MacroPopupEditBox:Point("TOPLEFT", 61, -35)
+
+ MacroPopupButton1:Point("TOPLEFT", 31, -82)
+
+ MacroPopupScrollFrame:Size(247, 180)
+ MacroPopupScrollFrame:Point("TOPRIGHT", -32, -76)
+
+ MacroPopupScrollFrameScrollBar:Point("TOPLEFT", MacroPopupScrollFrame, "TOPRIGHT", 3, -19)
+ MacroPopupScrollFrameScrollBar:Point("BOTTOMLEFT", MacroPopupScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ MacroPopupOkayButton:Point("RIGHT", MacroPopupCancelButton, "LEFT", -3, 0)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Mail.lua b/ElvUI/Modules/Skins/Blizzard/Mail.lua
new file mode 100644
index 0000000..78f5511
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Mail.lua
@@ -0,0 +1,301 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack, select = unpack, select
+--WoW API / Variables
+local GetInboxHeaderInfo = GetInboxHeaderInfo
+local GetInboxItemLink = GetInboxItemLink
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local GetSendMailItem = GetSendMailItem
+
+local INBOXITEMS_TO_DISPLAY = INBOXITEMS_TO_DISPLAY
+local ATTACHMENTS_MAX_SEND = ATTACHMENTS_MAX_SEND
+local ATTACHMENTS_MAX_RECEIVE = ATTACHMENTS_MAX_RECEIVE
+
+S:AddCallback("Skin_Mail", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.mail then return end
+
+ -- Inbox Frame
+ MailFrame:StripTextures(true)
+ MailFrame:CreateBackdrop("Transparent")
+ MailFrame.backdrop:Point("TOPLEFT", 11, -12)
+ MailFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(MailFrame, "width")
+ S:SetBackdropHitRect(MailFrame)
+ S:SetBackdropHitRect(SendMailFrame, MailFrame.backdrop)
+
+ MailFrame:EnableMouseWheel(true)
+
+ MailFrame:SetScript("OnMouseWheel", function(_, value)
+ if value > 0 then
+ if InboxPrevPageButton:IsEnabled() == 1 then
+ InboxPrevPage()
+ end
+ else
+ if InboxNextPageButton:IsEnabled() == 1 then
+ InboxNextPage()
+ end
+ end
+ end)
+
+ for i = 1, INBOXITEMS_TO_DISPLAY do
+ local mail = _G["MailItem"..i]
+ local button = _G["MailItem"..i.."Button"]
+ local icon = _G["MailItem"..i.."ButtonIcon"]
+
+ mail:StripTextures()
+ mail:CreateBackdrop("Transparent")
+ mail.backdrop:SetParent(button)
+ mail.backdrop:ClearAllPoints()
+ mail.backdrop:Point("TOPLEFT", mail, 45, -2)
+ mail.backdrop:Point("BOTTOMRIGHT", mail, 4, 9)
+ mail.backdrop:SetFrameLevel(mail:GetFrameLevel() - 1)
+
+ button:StripTextures()
+ button:CreateBackdrop()
+ button:Point("TOPLEFT", 8, -3)
+ button:Size(32)
+ button:StyleButton()
+ button.hover:SetAllPoints()
+
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetInside(button.backdrop)
+ end
+
+ hooksecurefunc("InboxFrame_Update", function()
+ local numItems = GetInboxNumItems()
+ local index = (InboxFrame.pageNum - 1) * INBOXITEMS_TO_DISPLAY
+
+ for i = 1, INBOXITEMS_TO_DISPLAY do
+ index = index + 1
+
+ if index <= numItems then
+ local button = _G["MailItem"..i.."Button"]
+ local packageIcon, _, _, _, _, _, _, _, _, _, _, _, isGM = GetInboxHeaderInfo(index)
+
+ if packageIcon and not isGM then
+ local itemLink = GetInboxItemLink(index, 1)
+
+ if itemLink then
+ local quality = select(3, GetItemInfo(itemLink))
+
+ if quality then
+ button.backdrop:SetBackdropBorderColor(GetItemQualityColor(quality))
+ else
+ button.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end
+ elseif isGM then
+ button.backdrop:SetBackdropBorderColor(0, 0.56, 0.94)
+ else
+ button.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end
+ end
+ end)
+
+ InboxTitleText:Point("CENTER", 0, 231)
+ SendMailTitleText:Point("CENTER", 0, 231)
+
+ S:HandleNextPrevButton(InboxPrevPageButton, nil, nil, true)
+ InboxPrevPageButton:Size(32)
+
+ S:HandleNextPrevButton(InboxNextPageButton, nil, nil, true)
+ InboxNextPageButton:Size(32)
+
+ S:HandleCloseButton(InboxCloseButton, MailFrame.backdrop)
+
+ for i = 1, 2 do
+ local tab = _G["MailFrameTab"..i]
+ tab:StripTextures()
+ S:HandleTab(tab)
+ end
+
+ MailFrameTab1:Point("BOTTOMLEFT", MailFrame, 11, 46)
+ MailFrameTab2:Point("LEFT", MailFrameTab1, "RIGHT", -15, 0)
+
+ -- Send Mail Frame
+ SendMailFrame:StripTextures()
+
+ SendMailScrollFrame:StripTextures(true)
+
+ hooksecurefunc("SendMailFrame_Update", function()
+ for i = 1, ATTACHMENTS_MAX_SEND do
+ local button = _G["SendMailAttachment"..i]
+ local name = GetSendMailItem(i)
+
+ if not button.skinned then
+ button:StripTextures()
+ button:SetTemplate("Default", true)
+ button:StyleButton(nil, true)
+
+ button.skinned = true
+ end
+
+ if name then
+ local icon = button:GetNormalTexture()
+ local quality = select(3, GetItemInfo(name))
+
+ if quality then
+ button:SetBackdropBorderColor(GetItemQualityColor(quality))
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetInside()
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end
+ end)
+
+ S:HandleScrollBar(SendMailScrollFrameScrollBar)
+
+ S:HandleEditBox(SendMailNameEditBox)
+ S:HandleEditBox(SendMailSubjectEditBox)
+ S:HandleEditBox(SendMailMoneyGold)
+ S:HandleEditBox(SendMailMoneySilver)
+ S:HandleEditBox(SendMailMoneyCopper)
+
+ S:HandleButton(SendMailMailButton)
+ S:HandleButton(SendMailCancelButton)
+
+ for i = 1, 5 do
+ _G["AutoCompleteButton"..i]:StyleButton()
+ end
+
+ SendMailScrollFrame:CreateBackdrop()
+ SendMailScrollFrame.backdrop:Point("TOPLEFT", 0, 5)
+ SendMailScrollFrame.backdrop:Point("BOTTOMRIGHT", 0, -5)
+
+ SendMailScrollFrameScrollBar:Point("TOPLEFT", SendMailScrollFrame, "TOPRIGHT", 3, -14)
+ SendMailScrollFrameScrollBar:Point("BOTTOMLEFT", SendMailScrollFrame, "BOTTOMRIGHT", 3, 14)
+
+ SendMailBodyEditBox:SetTextColor(1, 1, 1)
+ SendMailBodyEditBox:Width(291)
+ SendMailBodyEditBox:Point("TOPLEFT", 5, -5)
+
+ SendMailScrollFrame:Width(304)
+ SendMailScrollFrame:Point("TOPLEFT", 19, -97)
+
+ SendMailNameEditBox:Height(18)
+ SendMailNameEditBox:Point("TOPLEFT", 75, -43)
+
+ SendMailSubjectEditBox:Size(247, 18)
+ SendMailSubjectEditBox:Point("TOPLEFT", SendMailNameEditBox, "BOTTOMLEFT", 0, -5)
+
+ SendMailCostMoneyFrame:Point("TOPRIGHT", -27, -45)
+
+ SendMailMoneyText:Point("TOPLEFT", 0, 3)
+ SendMailMoney:Point("TOPLEFT", SendMailMoneyText, "BOTTOMLEFT", 2, -3)
+
+ SendMailMoneyFrame:Point("BOTTOMRIGHT", SendMailFrame, "BOTTOMLEFT", 164, 88)
+ SendMailMailButton:Point("RIGHT", SendMailCancelButton, "LEFT", -3, 0)
+
+ SendMailCancelButton:Point("BOTTOMRIGHT", -40, 84)
+
+ -- Open Mail Frame
+ OpenMailFrame:StripTextures(true)
+ OpenMailFrame:CreateBackdrop("Transparent")
+ OpenMailFrame.backdrop:Point("TOPLEFT", 11, -12)
+ OpenMailFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+ OpenMailFrame:Point("TOPLEFT", InboxFrame, "TOPRIGHT", -44, 0)
+
+ for i = 1, ATTACHMENTS_MAX_SEND do
+ local button = _G["OpenMailAttachmentButton"..i]
+ local icon = _G["OpenMailAttachmentButton"..i.."IconTexture"]
+ local count = _G["OpenMailAttachmentButton"..i.."Count"]
+
+ button:StripTextures()
+ button:SetTemplate("Default", true)
+ button:StyleButton()
+
+ if icon then
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetDrawLayer("ARTWORK")
+ icon:SetInside()
+
+ count:SetDrawLayer("OVERLAY")
+ end
+ end
+
+ hooksecurefunc("OpenMailFrame_UpdateButtonPositions", function()
+ for i = 1, ATTACHMENTS_MAX_RECEIVE do
+ local itemLink = GetInboxItemLink(InboxFrame.openMailID, i)
+ local button = _G["OpenMailAttachmentButton"..i]
+
+ if itemLink then
+ local quality = select(3, GetItemInfo(itemLink))
+
+ if quality then
+ button:SetBackdropBorderColor(GetItemQualityColor(quality))
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end
+ end)
+
+ S:HandleCloseButton(OpenMailCloseButton, OpenMailFrame.backdrop)
+
+ S:HandleButton(OpenMailReportSpamButton)
+
+ S:HandleButton(OpenMailReplyButton)
+ S:HandleButton(OpenMailDeleteButton)
+ S:HandleButton(OpenMailCancelButton)
+
+ OpenMailScrollFrame:StripTextures(true)
+ OpenMailScrollFrame:SetTemplate("Default")
+
+ S:HandleScrollBar(OpenMailScrollFrameScrollBar)
+
+ OpenMailBodyText:SetTextColor(1, 1, 1)
+ InvoiceTextFontNormal:SetFont(E.media.normFont, 13)
+ InvoiceTextFontNormal:SetTextColor(1, 1, 1)
+ OpenMailInvoiceBuyMode:SetTextColor(1, 0.80, 0.10)
+
+ OpenMailArithmeticLine:Kill()
+
+ OpenMailLetterButton:StripTextures()
+ OpenMailLetterButton:SetTemplate("Default", true)
+ OpenMailLetterButton:StyleButton()
+
+ OpenMailLetterButtonIconTexture:SetTexCoord(unpack(E.TexCoords))
+ OpenMailLetterButtonIconTexture:SetDrawLayer("ARTWORK")
+ OpenMailLetterButtonIconTexture:SetInside()
+
+ OpenMailLetterButtonCount:SetDrawLayer("OVERLAY")
+
+ OpenMailMoneyButton:StripTextures()
+ OpenMailMoneyButton:SetTemplate("Default", true)
+ OpenMailMoneyButton:StyleButton()
+
+ OpenMailMoneyButtonIconTexture:SetTexCoord(unpack(E.TexCoords))
+ OpenMailMoneyButtonIconTexture:SetDrawLayer("ARTWORK")
+ OpenMailMoneyButtonIconTexture:SetInside()
+
+ OpenMailMoneyButtonCount:SetDrawLayer("OVERLAY")
+
+ OpenMailScrollFrame:Width(304)
+ OpenMailScrollFrame:Point("TOPLEFT", 19, -92)
+
+ OpenMailScrollFrameScrollBar:Point("TOPLEFT", OpenMailScrollFrame, "TOPRIGHT", 3, -19)
+ OpenMailScrollFrameScrollBar:Point("BOTTOMLEFT", OpenMailScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ OpenMailSenderLabel:Point("TOPRIGHT", OpenMailFrame, "TOPLEFT", 85, -45)
+ OpenMailSubjectLabel:Point("TOPRIGHT", OpenMailFrame, "TOPLEFT", 85, -65)
+ OpenMailSender:Point("LEFT", OpenMailSenderLabel, "RIGHT", 5, -1)
+ OpenMailSubject:Point("TOPLEFT", OpenMailSubjectLabel, "TOPRIGHT", 5, -1)
+
+ OpenMailReportSpamButton:Point("TOPRIGHT", -40, -43)
+ OpenMailCancelButton:Point("BOTTOMRIGHT", -40, 84)
+ OpenMailDeleteButton:Point("RIGHT", OpenMailCancelButton, "LEFT", -3, 0)
+ OpenMailReplyButton:Point("RIGHT", OpenMailDeleteButton, "LEFT", -3, 0)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Merchant.lua b/ElvUI/Modules/Skins/Blizzard/Merchant.lua
new file mode 100644
index 0000000..78cb8e8
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Merchant.lua
@@ -0,0 +1,237 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+--WoW API / Variables
+local GetBuybackItemInfo = GetBuybackItemInfo
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local GetMerchantNumItems = GetMerchantNumItems
+
+S:AddCallback("Skin_Merchant", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.merchant then return end
+
+ local MerchantFrame = _G.MerchantFrame
+ MerchantFrame:StripTextures(true)
+ MerchantFrame:CreateBackdrop("Transparent")
+ MerchantFrame.backdrop:Point("TOPLEFT", 11, -12)
+ MerchantFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(MerchantFrame, "width")
+ S:SetBackdropHitRect(MerchantFrame)
+
+ MerchantFrame:EnableMouseWheel(true)
+ MerchantFrame:SetScript("OnMouseWheel", function(_, value)
+ if value > 0 then
+ if MerchantPrevPageButton:IsShown() and MerchantPrevPageButton:IsEnabled() == 1 then
+ MerchantPrevPageButton_OnClick()
+ end
+ else
+ if MerchantNextPageButton:IsShown() and MerchantNextPageButton:IsEnabled() == 1 then
+ MerchantNextPageButton_OnClick()
+ end
+ end
+ end)
+
+ S:HandleCloseButton(MerchantFrameCloseButton, MerchantFrame.backdrop)
+
+ local function skinMerchantButton(buttonName, buyback)
+ local button = _G[buttonName]
+ local itemButton = _G[buttonName.."ItemButton"]
+ local icon = _G[buttonName.."ItemButtonIconTexture"]
+ local name = _G[buttonName.."Name"]
+ local nameFrame = _G[buttonName.."NameFrame"]
+ local money = _G[buttonName.."MoneyFrame"]
+ local slot = _G[buttonName.."SlotTexture"]
+
+ button:StripTextures(true)
+ button:CreateBackdrop("Default")
+ button.backdrop:Point("TOPLEFT", -2, 2)
+
+ if buyback then
+ button.backdrop:Point("BOTTOMRIGHT", 4, -13)
+ else
+ button.backdrop:Point("BOTTOMRIGHT", 4, -6)
+ end
+
+ itemButton:StripTextures()
+ itemButton:StyleButton()
+ itemButton:SetTemplate("Default", true)
+ itemButton:Size(40)
+ itemButton:Point("TOPLEFT", 4, -4)
+
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetInside()
+
+ name:Point("LEFT", slot, "RIGHT", -4, 5)
+ nameFrame:Point("LEFT", slot, "RIGHT", -6, -17)
+
+ money:ClearAllPoints()
+ money:Point("BOTTOMLEFT", itemButton, "BOTTOMRIGHT", 3, 0)
+
+ if not buyback then
+ for j = 1, 2 do
+ local currencyItem = _G[buttonName.."AltCurrencyFrameItem"..j]
+ local currencyIcon = _G[buttonName.."AltCurrencyFrameItem"..j.."Texture"]
+
+ currencyIcon.backdrop = CreateFrame("Frame", nil, currencyItem)
+ currencyIcon.backdrop:SetTemplate("Default")
+ currencyIcon.backdrop:SetFrameLevel(currencyItem:GetFrameLevel())
+ currencyIcon.backdrop:SetOutside(currencyIcon)
+
+ currencyIcon:SetTexCoord(unpack(E.TexCoords))
+ currencyIcon:SetParent(currencyIcon.backdrop)
+ end
+ end
+ end
+
+ for i = 1, 12 do
+ skinMerchantButton("MerchantItem"..i)
+
+ if i % 2 == 0 then
+ _G["MerchantItem"..i]:Point("TOPLEFT", _G["MerchantItem"..i-1], "TOPRIGHT", 13, 0)
+ end
+ end
+
+ skinMerchantButton("MerchantBuyBackItem", true)
+
+ S:HandleNextPrevButton(MerchantNextPageButton, nil, nil, true)
+ S:HandleNextPrevButton(MerchantPrevPageButton, nil, nil, true)
+
+ S:HandleButton(MerchantRepairItemButton)
+ MerchantRepairItemButton:StyleButton(false)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 128, 64, 26, 26, 5, 6
+ MerchantRepairItemButton:GetRegions():SetTexCoord(0.0390625, 0.2421875, 0.09375, 0.5)
+ MerchantRepairItemButton:GetRegions():SetInside()
+
+ S:HandleButton(MerchantRepairAllButton)
+ MerchantRepairAllIcon:StyleButton(false)
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 128, 64, 26, 26, 41, 6
+ MerchantRepairAllIcon:SetTexCoord(0.3203125, 0.5234375, 0.09375, 0.5)
+ MerchantRepairAllIcon:SetInside()
+
+ S:HandleButton(MerchantGuildBankRepairButton)
+ MerchantGuildBankRepairButton:StyleButton()
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 128, 64, 26, 26, 77, 6
+ MerchantGuildBankRepairButtonIcon:SetTexCoord(0.6015625, 0.8046875, 0.09375, 0.5)
+ MerchantGuildBankRepairButtonIcon:SetInside()
+
+ S:HandleTab(MerchantFrameTab1)
+ S:HandleTab(MerchantFrameTab2)
+
+ MerchantNameText:Point("TOP", -6, -22)
+
+ MerchantItem1:SetPoint("TOPLEFT", 21, -54)
+
+ MerchantPrevPageButton:Point("CENTER", MerchantFrame, "BOTTOMLEFT", 37, 172)
+ MerchantNextPageButton:Point("CENTER", MerchantFrame, "BOTTOMLEFT", 324, 172)
+
+ MerchantPageText:Point("BOTTOM", -14, 166)
+
+ MerchantBuyBackItem:Point("TOPLEFT", MerchantItem10, "BOTTOMLEFT", 0, -39)
+
+ MerchantGuildBankRepairButton:Point("LEFT", MerchantRepairAllButton, "RIGHT", 5, 0)
+ MerchantRepairItemButton:Point("RIGHT", MerchantRepairAllButton, "LEFT", -5, 0)
+ MerchantRepairItemButton.SetPoint = E.noop
+
+ MerchantMoneyFrame:Point("BOTTOMRIGHT", -30, 86)
+
+ MerchantFrameTab1:Point("CENTER", MerchantFrame, "BOTTOMLEFT", 54, 62)
+ MerchantFrameTab2:Point("LEFT", MerchantFrameTab1, "RIGHT", -15, 0)
+
+ hooksecurefunc(MerchantRepairAllButton, "Show", function(self)
+ -- CanMerchantRepair && CanGuildBankRepair
+ if self:GetWidth() == 32 then
+ MerchantRepairText:SetPoint("CENTER", MerchantFrame, "BOTTOMLEFT", 94, 151)
+ MerchantRepairAllButton:Point("BOTTOMRIGHT", MerchantFrame, "BOTTOMLEFT", 111, 105)
+ else
+ MerchantRepairText:SetPoint("BOTTOMLEFT", MerchantFrame, "BOTTOMLEFT", 26, 125)
+ MerchantRepairAllButton:Point("BOTTOMRIGHT", MerchantFrame, "BOTTOMLEFT", 172, 113)
+ end
+ end)
+
+ hooksecurefunc("MerchantFrame_UpdateMerchantInfo", function()
+ local numMerchantItems = GetMerchantNumItems()
+ local index = (MerchantFrame.page - 1) * MERCHANT_ITEMS_PER_PAGE
+ local _, button, name, quality
+
+ for i = 1, BUYBACK_ITEMS_PER_PAGE do
+ index = index + 1
+
+ if index <= numMerchantItems then
+ button = _G["MerchantItem"..i.."ItemButton"]
+ name = _G["MerchantItem"..i.."Name"]
+
+ if button.link then
+ _, _, quality = GetItemInfo(button.link)
+
+ if quality then
+ local r, g, b = GetItemQualityColor(quality)
+ button:SetBackdropBorderColor(r, g, b)
+ name:SetTextColor(r, g, b)
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ name:SetTextColor(1, 1, 1)
+ end
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ name:SetTextColor(1, 1, 1)
+ end
+ end
+
+ local itemName = GetBuybackItemInfo(GetNumBuybackItems())
+ if itemName then
+ _, _, quality = GetItemInfo(itemName)
+
+ if quality then
+ local r, g, b = GetItemQualityColor(quality)
+ MerchantBuyBackItemItemButton:SetBackdropBorderColor(r, g, b)
+ MerchantBuyBackItemName:SetTextColor(r, g, b)
+ else
+ MerchantBuyBackItemItemButton:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ MerchantBuyBackItemName:SetTextColor(1, 1, 1)
+ end
+ else
+ MerchantBuyBackItemItemButton:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end
+
+ MerchantItem3:SetPoint("TOPLEFT", "MerchantItem1", "BOTTOMLEFT", 0, -11)
+ MerchantItem5:SetPoint("TOPLEFT", "MerchantItem3", "BOTTOMLEFT", 0, -11)
+ MerchantItem7:SetPoint("TOPLEFT", "MerchantItem5", "BOTTOMLEFT", 0, -11)
+ MerchantItem9:SetPoint("TOPLEFT", "MerchantItem7", "BOTTOMLEFT", 0, -11)
+ end)
+
+ hooksecurefunc("MerchantFrame_UpdateBuybackInfo", function()
+ local numBuybackItems = GetNumBuybackItems()
+ local _, button, name, quality
+
+ for i = 1, BUYBACK_ITEMS_PER_PAGE do
+ if i <= numBuybackItems then
+ local itemName = GetBuybackItemInfo(i)
+
+ if itemName then
+ button = _G["MerchantItem"..i.."ItemButton"]
+ name = _G["MerchantItem"..i.."Name"]
+ _, _, quality = GetItemInfo(itemName)
+
+ if quality then
+ local r, g, b = GetItemQualityColor(quality)
+ button:SetBackdropBorderColor(r, g, b)
+ name:SetTextColor(r, g, b)
+ else
+ button:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ name:SetTextColor(1, 1, 1)
+ end
+ end
+ end
+ end
+
+ MerchantItem3:SetPoint("TOPLEFT", "MerchantItem1", "BOTTOMLEFT", 0, -15)
+ MerchantItem5:SetPoint("TOPLEFT", "MerchantItem3", "BOTTOMLEFT", 0, -15)
+ MerchantItem7:SetPoint("TOPLEFT", "MerchantItem5", "BOTTOMLEFT", 0, -15)
+ MerchantItem9:SetPoint("TOPLEFT", "MerchantItem7", "BOTTOMLEFT", 0, -15)
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/MirrorTimers.lua b/ElvUI/Modules/Skins/Blizzard/MirrorTimers.lua
new file mode 100644
index 0000000..91f76ed
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/MirrorTimers.lua
@@ -0,0 +1,54 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallback("Skin_MirrorTimers", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.mirrorTimers then return end
+
+ local function MirrorTimer_OnUpdate(frame, elapsed)
+ if frame.paused then return end
+
+ if frame.timeSinceUpdate <= 0 then
+ local text = frame.label:GetText()
+
+ if frame.value > 0 then
+ frame.TimerText:SetFormattedText("%s (%d:%02d)", text, frame.value / 60, frame.value % 60)
+ else
+ frame.TimerText:SetFormattedText("%s (0:00)", text)
+ end
+
+ frame.timeSinceUpdate = 0.033
+ else
+ frame.timeSinceUpdate = frame.timeSinceUpdate - elapsed
+ end
+ end
+
+ for i = 1, MIRRORTIMER_NUMTIMERS do
+ local mirrorTimer = _G["MirrorTimer"..i]
+ local statusBar = _G["MirrorTimer"..i.."StatusBar"]
+ local text = _G["MirrorTimer"..i.."Text"]
+
+ mirrorTimer:StripTextures()
+ mirrorTimer:Size(222, 18)
+ mirrorTimer.label = text
+
+ statusBar:CreateBackdrop()
+ statusBar:Size(222, 18)
+ statusBar:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(statusBar)
+
+ text:Hide()
+
+ local timerText = mirrorTimer:CreateFontString(nil, "OVERLAY")
+ timerText:FontTemplate()
+ timerText:Point("CENTER", statusBar)
+ mirrorTimer.TimerText = timerText
+
+ mirrorTimer.timeSinceUpdate = 0
+ mirrorTimer:HookScript("OnUpdate", MirrorTimer_OnUpdate)
+
+ E:CreateMover(mirrorTimer, "MirrorTimer"..i.."Mover", L["MirrorTimer"]..i, nil, nil, nil, "ALL,SOLO")
+ end
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Misc.lua b/ElvUI/Modules/Skins/Blizzard/Misc.lua
new file mode 100644
index 0000000..9f94490
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Misc.lua
@@ -0,0 +1,302 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local type = type
+local unpack = unpack
+--WoW API / Variables
+
+S:AddCallback("Skin_Misc", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.misc then return end
+
+ -- ESC/Menu Buttons
+ GameMenuFrame:StripTextures()
+ GameMenuFrame:CreateBackdrop("Transparent")
+
+ GameMenuFrameHeader:Point("TOP", 0, 7)
+
+ local menuButtons = {
+ GameMenuButtonOptions,
+ GameMenuButtonSoundOptions,
+ GameMenuButtonUIOptions,
+ -- GameMenuButtonMacOptions,
+ GameMenuButtonKeybindings,
+ GameMenuButtonMacros,
+ -- GameMenuButtonRatings,
+ GameMenuButtonLogout,
+ GameMenuButtonQuit,
+ GameMenuButtonContinue,
+
+ ElvUI_MenuButton
+ }
+
+ for i = 1, #menuButtons do
+ local button = menuButtons[i]
+ if button then
+ S:HandleButton(menuButtons[i])
+ end
+ end
+
+ -- Static Popups
+ for i = 1, 4 do
+ local staticPopup = _G["StaticPopup"..i]
+ local itemFrame = _G["StaticPopup"..i.."ItemFrame"]
+ local itemFrameBox = _G["StaticPopup"..i.."EditBox"]
+ local itemFrameTexture = _G["StaticPopup"..i.."ItemFrameIconTexture"]
+ local itemFrameNormal = _G["StaticPopup"..i.."ItemFrameNormalTexture"]
+ local itemFrameName = _G["StaticPopup"..i.."ItemFrameNameFrame"]
+ local closeButton = _G["StaticPopup"..i.."CloseButton"]
+ local wideBox = _G["StaticPopup"..i.."WideEditBox"]
+
+ staticPopup:SetTemplate("Transparent")
+
+ S:HandleEditBox(itemFrameBox)
+ itemFrameBox.backdrop:Point("TOPLEFT", -2, -4)
+ itemFrameBox.backdrop:Point("BOTTOMRIGHT", 2, 4)
+
+ S:HandleEditBox(_G["StaticPopup"..i.."MoneyInputFrameGold"])
+ S:HandleEditBox(_G["StaticPopup"..i.."MoneyInputFrameSilver"])
+ S:HandleEditBox(_G["StaticPopup"..i.."MoneyInputFrameCopper"])
+
+ for j = 1, itemFrameBox:GetNumRegions() do
+ local region = select(j, itemFrameBox:GetRegions())
+ if region and region:GetObjectType() == "Texture" then
+ if region:GetTexture() == "Interface\\ChatFrame\\UI-ChatInputBorder-Left" or region:GetTexture() == "Interface\\ChatFrame\\UI-ChatInputBorder-Right" then
+ region:Kill()
+ end
+ end
+ end
+
+ closeButton:StripTextures()
+ S:HandleCloseButton(closeButton, staticPopup)
+
+ itemFrame:GetNormalTexture():Kill()
+ itemFrame:SetTemplate()
+ itemFrame:StyleButton()
+
+ hooksecurefunc("StaticPopup_Show", function(which, _, _, data)
+ local info = StaticPopupDialogs[which]
+ if not info then return nil end
+
+ if info.hasItemFrame then
+ if data and type(data) == "table" then
+ if data.color then
+ itemFrame:SetBackdropBorderColor(unpack(data.color))
+ else
+ itemFrame:SetBackdropBorderColor(1, 1, 1, 1)
+ end
+ end
+ end
+ end)
+
+ itemFrameTexture:SetTexCoord(unpack(E.TexCoords))
+ itemFrameTexture:SetInside()
+
+ itemFrameNormal:SetAlpha(0)
+ itemFrameName:Kill()
+
+ select(8, wideBox:GetRegions()):Hide()
+ S:HandleEditBox(wideBox)
+ wideBox:Height(22)
+
+ for j = 1, 3 do
+ S:HandleButton(_G["StaticPopup"..i.."Button"..j])
+ end
+ end
+
+ -- Other Frames
+ TicketStatusFrameButton:SetTemplate("Transparent")
+ AutoCompleteBox:SetTemplate("Transparent")
+ ConsolidatedBuffsTooltip:SetTemplate("Transparent")
+ --ResInSafeZoneButton
+
+ -- BNToast Frame
+ BNToastFrame:SetTemplate("Transparent")
+
+ BNToastFrameCloseButton:Size(32)
+ BNToastFrameCloseButton:Point("TOPRIGHT", "BNToastFrame", 4, 4)
+
+ S:HandleCloseButton(BNToastFrameCloseButton, BNToastFrame)
+
+ -- Ready Check Frame
+ ReadyCheckFrame:EnableMouse(true)
+ ReadyCheckFrame:SetTemplate("Transparent")
+
+ S:HandleButton(ReadyCheckFrameYesButton)
+ ReadyCheckFrameYesButton:SetParent(ReadyCheckFrame)
+ ReadyCheckFrameYesButton:ClearAllPoints()
+ ReadyCheckFrameYesButton:Point("TOPRIGHT", ReadyCheckFrame, "CENTER", -3, -5)
+
+ S:HandleButton(ReadyCheckFrameNoButton)
+ ReadyCheckFrameNoButton:SetParent(ReadyCheckFrame)
+ ReadyCheckFrameNoButton:ClearAllPoints()
+ ReadyCheckFrameNoButton:Point("TOPLEFT", ReadyCheckFrame, "CENTER", 4, -5)
+
+ ReadyCheckFrameText:SetParent(ReadyCheckFrame)
+ ReadyCheckFrameText:Point("TOP", 0, -15)
+ ReadyCheckFrameText:SetTextColor(1, 1, 1)
+
+ ReadyCheckListenerFrame:SetAlpha(0)
+
+ -- Coin PickUp Frame
+ CoinPickupFrame:StripTextures()
+ CoinPickupFrame:SetTemplate("Transparent")
+
+ S:HandleButton(CoinPickupOkayButton)
+ S:HandleButton(CoinPickupCancelButton)
+
+ -- Zone Text Frame
+ ZoneTextFrame:ClearAllPoints()
+ ZoneTextFrame:Point("TOP", UIParent, 0, -128)
+
+ -- Stack Split Frame
+ StackSplitFrame:SetTemplate("Transparent")
+ StackSplitFrame:GetRegions():Hide()
+ StackSplitFrame:SetFrameStrata("DIALOG")
+
+ StackSplitFrame.bg1 = CreateFrame("Frame", nil, StackSplitFrame)
+ StackSplitFrame.bg1:SetFrameLevel(StackSplitFrame.bg1:GetFrameLevel() - 1)
+ StackSplitFrame.bg1:SetTemplate("Transparent")
+ StackSplitFrame.bg1:Point("TOPLEFT", 10, -15)
+ StackSplitFrame.bg1:Point("BOTTOMRIGHT", -10, 55)
+
+ S:HandleButton(StackSplitOkayButton)
+ S:HandleButton(StackSplitCancelButton)
+
+ -- Opacity Frame
+ OpacityFrame:StripTextures()
+ OpacityFrame:SetTemplate("Transparent")
+
+ S:HandleSliderFrame(OpacityFrameSlider)
+
+ -- Channel Pullout Frame
+ ChannelPullout:SetTemplate("Transparent")
+
+ ChannelPulloutBackground:Kill()
+
+ S:HandleTab(ChannelPulloutTab)
+ ChannelPulloutTab:Size(107, 26)
+ ChannelPulloutTabText:Point("LEFT", ChannelPulloutTabLeft, "RIGHT", 0, 4)
+
+ S:HandleCloseButton(ChannelPulloutCloseButton, ChannelPullout)
+ ChannelPulloutCloseButton:Size(32)
+
+ -- Dropdown Menu
+ local checkBoxSkin = E.private.skins.dropdownCheckBoxSkin
+ local menuLevel = 0
+ local maxButtons = 0
+
+ local function dropDownButtonShow(self)
+ if self.notCheckable then
+ self.check.backdrop:Hide()
+ else
+ self.check.backdrop:Show()
+ end
+ end
+
+ local function skinDropdownMenu()
+ local updateButtons = maxButtons < UIDROPDOWNMENU_MAXBUTTONS
+
+ if updateButtons or menuLevel < UIDROPDOWNMENU_MAXLEVELS then
+ for i = 1, UIDROPDOWNMENU_MAXLEVELS do
+ local frame = _G["DropDownList"..i]
+
+ if not frame.isSkinned then
+ _G["DropDownList"..i.."Backdrop"]:SetTemplate("Transparent")
+ _G["DropDownList"..i.."MenuBackdrop"]:SetTemplate("Transparent")
+
+ frame.isSkinned = true
+ end
+
+ if updateButtons then
+ for j = 1, UIDROPDOWNMENU_MAXBUTTONS do
+ local button = _G["DropDownList"..i.."Button"..j]
+
+ if not button.isSkinned then
+ S:HandleButtonHighlight(_G["DropDownList"..i.."Button"..j.."Highlight"])
+
+ if checkBoxSkin then
+ local check = _G["DropDownList"..i.."Button"..j.."Check"]
+ check:Size(12)
+ check:Point("LEFT", 1, 0)
+ check:CreateBackdrop()
+ check:SetTexture(E.media.normTex)
+ check:SetVertexColor(1, 0.82, 0, 0.8)
+
+ button.check = check
+ hooksecurefunc(button, "Show", dropDownButtonShow)
+ end
+
+ S:HandleColorSwatch(_G["DropDownList"..i.."Button"..j.."ColorSwatch"], 14)
+
+ button.isSkinned = true
+ end
+ end
+ end
+ end
+
+ menuLevel = UIDROPDOWNMENU_MAXLEVELS
+ maxButtons = UIDROPDOWNMENU_MAXBUTTONS
+ end
+ end
+
+ skinDropdownMenu()
+ hooksecurefunc("UIDropDownMenu_InitializeHelper", skinDropdownMenu)
+
+ -- Chat Menu
+ local chatMenus = {
+ "ChatMenu",
+ "EmoteMenu",
+ "LanguageMenu",
+ "VoiceMacroMenu",
+ }
+
+ for i = 1, #chatMenus do
+ if chatMenus[i] == "ChatMenu" then
+ _G[chatMenus[i]]:HookScript("OnShow", function(self)
+ self:SetTemplate("Transparent")
+ self:SetBackdropColor(unpack(E.media.backdropfadecolor))
+ self:ClearAllPoints()
+ self:Point("BOTTOMLEFT", ChatFrame1, "TOPLEFT", 0, 30)
+ end)
+ else
+ _G[chatMenus[i]]:HookScript("OnShow", function(self)
+ self:SetTemplate("Transparent")
+ self:SetBackdropColor(unpack(E.media.backdropfadecolor))
+ end)
+ end
+ end
+
+ for i = 1, 32 do
+ _G["ChatMenuButton"..i]:StyleButton()
+ _G["EmoteMenuButton"..i]:StyleButton()
+ _G["LanguageMenuButton"..i]:StyleButton()
+ _G["VoiceMacroMenuButton"..i]:StyleButton()
+ end
+
+ local locale = GetLocale()
+ if locale == "koKR" then
+ S:HandleButton(GameMenuButtonRatings)
+
+ RatingMenuFrame:SetTemplate("Transparent")
+ RatingMenuFrameHeader:Kill()
+ S:HandleButton(RatingMenuButtonOkay)
+ elseif locale == "ruRU" then
+ -- Declension Frame
+ DeclensionFrame:SetTemplate("Transparent")
+
+ S:HandleNextPrevButton(DeclensionFrameSetPrev)
+ S:HandleNextPrevButton(DeclensionFrameSetNext)
+ S:HandleButton(DeclensionFrameOkayButton)
+ S:HandleButton(DeclensionFrameCancelButton)
+
+ for i = 1, RUSSIAN_DECLENSION_PATTERNS do
+ local editBox = _G["DeclensionFrameDeclension"..i.."Edit"]
+ if editBox then
+ editBox:StripTextures()
+ S:HandleEditBox(editBox)
+ end
+ end
+ end
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Petition.lua b/ElvUI/Modules/Skins/Blizzard/Petition.lua
new file mode 100644
index 0000000..87df59f
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Petition.lua
@@ -0,0 +1,40 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallback("Skin_Petition", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.petition then return end
+
+ PetitionFrame:StripTextures(true)
+ PetitionFrame:CreateBackdrop("Transparent")
+ PetitionFrame.backdrop:Point("TOPLEFT", 11, -12)
+ PetitionFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(PetitionFrame, "width")
+ S:SetBackdropHitRect(PetitionFrame)
+
+ S:HandleButton(PetitionFrameSignButton)
+ S:HandleButton(PetitionFrameRequestButton)
+ S:HandleButton(PetitionFrameRenameButton)
+ S:HandleButton(PetitionFrameCancelButton)
+ S:HandleCloseButton(PetitionFrameCloseButton, PetitionFrame.backdrop)
+
+ PetitionFrameCharterTitle:SetTextColor(1, 1, 0)
+ PetitionFrameCharterName:SetTextColor(1, 1, 1)
+ PetitionFrameMasterTitle:SetTextColor(1, 1, 0)
+ PetitionFrameMasterName:SetTextColor(1, 1, 1)
+ PetitionFrameMemberTitle:SetTextColor(1, 1, 0)
+
+ for i = 1, 9 do
+ _G["PetitionFrameMemberName"..i]:SetTextColor(1, 1, 1)
+ end
+
+ PetitionFrameInstructions:SetTextColor(1, 1, 1)
+
+ PetitionFrameRequestButton:Point("BOTTOMLEFT", 19, 84)
+ PetitionFrameCancelButton:Point("BOTTOMRIGHT", -40, 84)
+ PetitionFrameRenameButton:Point("LEFT", PetitionFrameRequestButton, "RIGHT", 3, 0)
+ PetitionFrameRenameButton:Point("RIGHT", PetitionFrameCancelButton, "LEFT", -3, 0)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/PvP.lua b/ElvUI/Modules/Skins/Blizzard/PvP.lua
new file mode 100644
index 0000000..331d98e
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/PvP.lua
@@ -0,0 +1,155 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+--WoW API / Variables
+local CanQueueForWintergrasp = CanQueueForWintergrasp
+
+S:AddCallback("Skin_PvP", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.pvp then return end
+
+ PVPParentFrame:CreateBackdrop("Transparent")
+ PVPParentFrame.backdrop:Point("TOPLEFT", 11, -12)
+ PVPParentFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(PVPParentFrame, "width")
+ S:SetBackdropHitRect(PVPParentFrame)
+ S:SetBackdropHitRect(PVPFrame, PVPParentFrame.backdrop)
+ S:SetBackdropHitRect(PVPBattlegroundFrame, PVPParentFrame.backdrop)
+
+ S:HandleCloseButton(PVPParentFrameCloseButton, PVPParentFrame.backdrop)
+
+ S:HandleTab(PVPParentFrameTab1)
+ S:HandleTab(PVPParentFrameTab2)
+
+ PVPFrame:StripTextures(true)
+
+ for i = 1, MAX_ARENA_TEAMS do
+ local pvpTeam = _G["PVPTeam"..i]
+ pvpTeam:StripTextures()
+ pvpTeam:CreateBackdrop("Default")
+ pvpTeam.backdrop:Point("TOPLEFT", 9, -4)
+ pvpTeam.backdrop:Point("BOTTOMRIGHT", -24, 3)
+ S:SetBackdropHitRect(pvpTeam)
+
+ pvpTeam:HookScript("OnEnter", S.SetModifiedBackdrop)
+ pvpTeam:HookScript("OnLeave", S.SetOriginalBackdrop)
+
+ _G["PVPTeam"..i.."Highlight"]:Kill()
+ end
+
+ -- PVP Team Details
+ PVPTeamDetails:StripTextures()
+ PVPTeamDetails:SetTemplate("Transparent")
+ PVPTeamDetails:Point("TOPLEFT", PVPFrame, "TOPRIGHT", -33, -81)
+
+ S:HandleCloseButton(PVPTeamDetailsCloseButton, PVPTeamDetails)
+
+ for i = 1, 5 do
+ _G["PVPTeamDetailsFrameColumnHeader"..i]:StripTextures()
+ end
+
+ for i = 1, MAX_ARENA_TEAM_MEMBERS do
+ S:HandleButtonHighlight(_G["PVPTeamDetailsButton"..i])
+ end
+
+ S:HandleButton(PVPTeamDetailsAddTeamMember)
+ S:HandleNextPrevButton(PVPTeamDetailsToggleButton)
+
+ PVPTeamDetailsAddTeamMember:Point("TOPLEFT", PVPTeamDetailsButton10, "BOTTOMLEFT", 5, -8)
+ PVPTeamDetailsToggleButton:Point("BOTTOMRIGHT", -20, 25)
+
+ -- PVP Battleground Frame
+ PVPBattlegroundFrame:StripTextures(true)
+
+ PVPBattlegroundFrameTypeScrollFrame:StripTextures()
+ S:HandleScrollBar(PVPBattlegroundFrameTypeScrollFrameScrollBar)
+
+ PVPBattlegroundFrameInfoScrollFrame:StripTextures()
+ S:HandleScrollBar(PVPBattlegroundFrameInfoScrollFrameScrollBar)
+
+ S:HandleButton(PVPBattlegroundFrameGroupJoinButton)
+ S:HandleButton(PVPBattlegroundFrameJoinButton)
+ S:HandleButton(PVPBattlegroundFrameCancelButton)
+
+ for i = 1, 5 do
+ S:HandleButtonHighlight(_G["BattlegroundType"..i])
+ end
+
+ PVPBattlegroundFrameInfoScrollFrameChildFrameDescription:SetTextColor(1, 1, 1)
+ PVPBattlegroundFrameInfoScrollFrameChildFrameRewardsInfo.description:SetTextColor(1, 1, 1)
+
+ PVPBattlegroundFrameTypeScrollFrameScrollBar:Point("TOPLEFT", PVPBattlegroundFrameTypeScrollFrame, "TOPRIGHT", 6, -19)
+ PVPBattlegroundFrameTypeScrollFrameScrollBar:Point("BOTTOMLEFT", PVPBattlegroundFrameTypeScrollFrame, "BOTTOMRIGHT", 6, 19)
+
+ PVPBattlegroundFrameInfoScrollFrame:Point("BOTTOMLEFT", 19, 114)
+
+ PVPBattlegroundFrameInfoScrollFrameScrollBar:Point("TOPLEFT", PVPBattlegroundFrameInfoScrollFrame, "TOPRIGHT", 7, -24)
+ PVPBattlegroundFrameInfoScrollFrameScrollBar:Point("BOTTOMLEFT", PVPBattlegroundFrameInfoScrollFrame, "BOTTOMRIGHT", 7, 19)
+
+ PVPBattlegroundFrameGroupJoinButton:Width(127)
+ PVPBattlegroundFrameCancelButton:Point("CENTER", PVPBattlegroundFrame, "TOPLEFT", 300, -416)
+ PVPBattlegroundFrameJoinButton:Point("RIGHT", PVPBattlegroundFrameCancelButton, "LEFT", -3, 0)
+ PVPBattlegroundFrameGroupJoinButton:Point("RIGHT", PVPBattlegroundFrameJoinButton, "LEFT", -3, 0)
+
+ WintergraspTimer:Size(24)
+ WintergraspTimer:SetTemplate("Default")
+ WintergraspTimer:Point("RIGHT", PVPBattlegroundFrame, "TOPRIGHT", -42, -58)
+
+ WintergraspTimer.texture:SetDrawLayer("ARTWORK")
+ WintergraspTimer.texture:SetInside()
+
+ WintergraspTimer:HookScript("OnUpdate", function(self)
+ if CanQueueForWintergrasp() then
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 32, 64, 20, 20, 6, 38
+ self.texture:SetTexCoord(0.1875, 0.8125, 0.59375, 0.90625)
+ else
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 32, 64, 20, 20, 6, 6
+ self.texture:SetTexCoord(0.1875, 0.8125, 0.09375, 0.40625)
+ end
+ end)
+
+ -- Battlefield Frame
+ BattlefieldFrame:StripTextures(true)
+ BattlefieldFrame:CreateBackdrop("Transparent")
+ BattlefieldFrame.backdrop:Point("TOPLEFT", 11, -12)
+ BattlefieldFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(BattlefieldFrame, "width")
+ S:SetBackdropHitRect(BattlefieldFrame)
+
+ S:HandleCloseButton(BattlefieldFrameCloseButton, BattlefieldFrame.backdrop)
+
+ BattlefieldListScrollFrame:StripTextures()
+ S:HandleScrollBar(BattlefieldListScrollFrameScrollBar)
+ S:HandleScrollBar(BattlefieldFrameInfoScrollFrameScrollBar)
+
+ BattlefieldFrameInfoScrollFrameChildFrameDescription:SetTextColor(1, 1, 1)
+ BattlefieldFrameInfoScrollFrameChildFrameRewardsInfoDescription:SetTextColor(1, 1, 1)
+
+ S:HandleButton(BattlefieldFrameGroupJoinButton)
+ S:HandleButton(BattlefieldFrameJoinButton)
+ S:HandleButton(BattlefieldFrameCancelButton)
+
+ for i = 1, BATTLEFIELD_ZONES_DISPLAYED do
+ S:HandleButtonHighlight(_G["BattlefieldZone"..i])
+ end
+
+ BattlefieldFrameNameHeader:Point("TOPLEFT", 73, -57)
+
+ BattlefieldZone1:Point("TOPLEFT", 25, -80)
+
+ BattlefieldListScrollFrameScrollBar:Point("TOPLEFT", BattlefieldListScrollFrame, "TOPRIGHT", 9, -23)
+ BattlefieldListScrollFrameScrollBar:Point("BOTTOMLEFT", BattlefieldListScrollFrame, "BOTTOMRIGHT", 9, 23)
+
+ BattlefieldFrameInfoScrollFrame:Point("BOTTOMLEFT", 21, 113)
+
+ BattlefieldFrameInfoScrollFrameScrollBar:Point("TOPLEFT", BattlefieldFrameInfoScrollFrame, "TOPRIGHT", 7, -20)
+ BattlefieldFrameInfoScrollFrameScrollBar:Point("BOTTOMLEFT", BattlefieldFrameInfoScrollFrame, "BOTTOMRIGHT", 7, 19)
+
+ BattlefieldFrameGroupJoinButton:Width(127)
+ BattlefieldFrameGroupJoinButton:Point("RIGHT", BattlefieldFrameJoinButton, "LEFT", -3, 0)
+ BattlefieldFrameJoinButton:Point("RIGHT", BattlefieldFrameCancelButton, "LEFT", -3, 0)
+ BattlefieldFrameCancelButton:Point("CENTER", BattlefieldFrame, "TOPLEFT", 302, -417)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Quest.lua b/ElvUI/Modules/Skins/Blizzard/Quest.lua
new file mode 100644
index 0000000..8aeb6ea
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Quest.lua
@@ -0,0 +1,437 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local select = select
+local unpack = unpack
+local find, gsub = string.find, string.gsub
+--WoW API / Variables
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local GetMoney = GetMoney
+local GetNumQuestLeaderBoards = GetNumQuestLeaderBoards
+local GetQuestItemLink = GetQuestItemLink
+local GetQuestLogItemLink = GetQuestLogItemLink
+local GetQuestLogLeaderBoard = GetQuestLogLeaderBoard
+local GetQuestLogRequiredMoney = GetQuestLogRequiredMoney
+local hooksecurefunc = hooksecurefunc
+local GetQuestMoneyToGet = GetQuestMoneyToGet
+
+local MAX_NUM_ITEMS = MAX_NUM_ITEMS
+local MAX_REPUTATIONS = MAX_REPUTATIONS
+
+S:AddCallback("Skin_Quest", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.quest then return end
+
+ QuestLogFrame:StripTextures()
+ QuestLogFrame:CreateBackdrop("Transparent")
+ QuestLogFrame.backdrop:Point("TOPLEFT", 11, -12)
+ QuestLogFrame.backdrop:Point("BOTTOMRIGHT", -1, 11)
+
+ S:SetUIPanelWindowInfo(QuestLogFrame, "width")
+ S:SetBackdropHitRect(QuestLogFrame)
+
+ S:HandleCloseButton(QuestLogFrameCloseButton, QuestLogFrame.backdrop)
+
+ QuestLogCount:StripTextures()
+ QuestLogCount:CreateBackdrop("Transparent")
+ QuestLogCount.backdrop:Point("TOPLEFT", -1, 0)
+ QuestLogCount.backdrop:Point("BOTTOMRIGHT", 1, -4)
+
+ QuestLogFrameShowMapButton:StripTextures()
+ S:HandleButton(QuestLogFrameShowMapButton)
+
+ QuestLogScrollFrame:CreateBackdrop("Transparent")
+ QuestLogScrollFrame.backdrop:Point("TOPLEFT", 0, 2)
+ QuestLogScrollFrame.backdrop:Point("BOTTOMRIGHT", 0, -2)
+
+ QuestLogDetailScrollFrame:StripTextures()
+ QuestLogDetailScrollFrame:CreateBackdrop("Transparent")
+ QuestLogDetailScrollFrame.backdrop:Point("TOPLEFT", 0, 1)
+ QuestLogDetailScrollFrame.backdrop:Point("BOTTOMRIGHT", 0, -2)
+
+ EmptyQuestLogFrame:StripTextures()
+
+ S:HandleButton(QuestLogFrameAbandonButton)
+ S:HandleButton(QuestLogFramePushQuestButton)
+ S:HandleButton(QuestLogFrameTrackButton)
+ S:HandleButton(QuestLogFrameCancelButton)
+
+ QuestLogSkillHighlight:SetTexture(E.Media.Textures.Highlight)
+ QuestLogSkillHighlight:SetAlpha(0.35)
+
+ S:HandleScrollBar(QuestLogScrollFrameScrollBar)
+ S:HandleScrollBar(QuestLogDetailScrollFrameScrollBar)
+ S:HandleScrollBar(QuestDetailScrollFrameScrollBar)
+ S:HandleScrollBar(QuestProgressScrollFrameScrollBar)
+ S:HandleScrollBar(QuestRewardScrollFrameScrollBar)
+
+ QuestLogCount:ClearAllPoints()
+ QuestLogCount:Point("BOTTOMLEFT", QuestLogScrollFrame, "TOPLEFT", 1, 13)
+ QuestLogCount.SetPoint = E.noop
+
+ QuestLogFrameShowMapButton.text:ClearAllPoints()
+ QuestLogFrameShowMapButton.text:Point("CENTER")
+ QuestLogFrameShowMapButton:Size(QuestLogFrameShowMapButton.text:GetWidth() + 32, 32)
+
+ QuestLogScrollFrame:Point("TOPLEFT", 19, -62)
+
+ QuestLogScrollFrameScrollBar:Point("TOPLEFT", QuestLogScrollFrame, "TOPRIGHT", 3, -17)
+ QuestLogScrollFrameScrollBar:Point("BOTTOMLEFT", QuestLogScrollFrame, "BOTTOMRIGHT", 3, 17)
+
+ QuestLogDetailScrollFrame:Width(304)
+ QuestLogDetailScrollFrame.Hide = E.noop
+ QuestLogDetailScrollFrame:Show()
+
+ QuestLogFrameTrackButton:Height(22)
+ QuestLogFrameAbandonButton:Height(22)
+ QuestLogFramePushQuestButton:Height(22)
+
+ QuestLogFrameTrackButton:Point("RIGHT", -1, 2)
+ QuestLogFrameAbandonButton:Point("LEFT", 1, 2)
+
+ QuestLogFramePushQuestButton:Point("LEFT", QuestLogFrameAbandonButton, "RIGHT", 3, 0)
+ QuestLogFramePushQuestButton:Point("RIGHT", QuestLogFrameTrackButton, "LEFT", -3, 0)
+
+ QuestLogFrameCancelButton:Point("BOTTOMRIGHT", -9, 19)
+
+ QuestLogFrame:HookScript("OnShow", function()
+ QuestLogDetailScrollFrame.backdrop:Show()
+
+ QuestLogFrameShowMapButton:Point("TOPRIGHT", -30, -24)
+
+ QuestLogDetailScrollFrame:Height(336)
+ QuestLogDetailScrollFrame:Point("TOPRIGHT", -30, -61)
+
+ QuestLogDetailScrollFrameScrollBar:Point("TOPLEFT", QuestLogDetailScrollFrame, "TOPRIGHT", 3, -18)
+ QuestLogDetailScrollFrameScrollBar:Point("BOTTOMLEFT", QuestLogDetailScrollFrame, "BOTTOMRIGHT", 3, 17)
+
+ QuestLogControlPanel:SetPoint("BOTTOMLEFT", 18, 15)
+ end)
+
+ for _, questLogTitle in ipairs(QuestLogScrollFrame.buttons) do
+ questLogTitle:SetNormalTexture(E.Media.Textures.Plus)
+ questLogTitle.SetNormalTexture = E.noop
+ questLogTitle:GetNormalTexture():Size(16)
+ questLogTitle:GetNormalTexture():Point("LEFT", 5, 0)
+ questLogTitle:SetHighlightTexture("")
+ questLogTitle.SetHighlightTexture = E.noop
+
+ hooksecurefunc(questLogTitle, "SetNormalTexture", function(self, texture)
+ if find(texture, "MinusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Minus)
+ elseif find(texture, "PlusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Plus)
+ else
+ self:GetNormalTexture():SetTexture(0, 0, 0, 0)
+ end
+ end)
+ end
+
+ -- QuestLog Detail Frame
+ QuestLogDetailFrame:StripTextures()
+ QuestLogDetailFrame:Height(513)
+ QuestLogDetailFrame:CreateBackdrop("Transparent")
+ QuestLogDetailFrame.backdrop:Point("TOPLEFT", 11, -12)
+ QuestLogDetailFrame.backdrop:Point("BOTTOMRIGHT", 2, 1)
+
+ S:SetUIPanelWindowInfo(QuestLogDetailFrame, "height", nil, nil, true)
+ S:SetUIPanelWindowInfo(QuestLogDetailFrame, "width")
+ S:SetBackdropHitRect(QuestLogDetailFrame)
+
+ S:HandleCloseButton(QuestLogDetailFrameCloseButton, QuestLogDetailFrame.backdrop)
+
+ QuestLogDetailTitleText:Point("TOP", QuestLogDetailFrame, "TOP", 0, -18)
+
+ QuestLogDetailFrame:HookScript("OnShow", function()
+ QuestLogDetailScrollFrame.backdrop:Hide()
+
+ QuestLogDetailScrollFrame:Height(402)
+ QuestLogDetailScrollFrame:Point("TOPLEFT", 19, -73)
+
+ QuestLogDetailScrollFrameScrollBar:Point("TOPLEFT", QuestLogDetailScrollFrame, "TOPRIGHT", 3, -19)
+ QuestLogDetailScrollFrameScrollBar:Point("BOTTOMLEFT", QuestLogDetailScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ QuestLogFrameShowMapButton:Point("TOPRIGHT", -27, -34)
+ end)
+
+ -- Quest Frame
+ QuestFrame:StripTextures(true)
+ QuestFrame:CreateBackdrop("Transparent")
+ QuestFrame.backdrop:Point("TOPLEFT", 11, -12)
+ QuestFrame.backdrop:Point("BOTTOMRIGHT", -32, 0)
+
+ S:SetUIPanelWindowInfo(QuestFrame, "width")
+ S:SetBackdropHitRect(QuestFrame)
+
+ S:HandleCloseButton(QuestFrameCloseButton, QuestFrame.backdrop)
+
+ QuestFrameDetailPanel:StripTextures(true)
+ QuestDetailScrollFrame:StripTextures(true)
+ QuestDetailScrollChildFrame:StripTextures(true)
+ QuestRewardScrollFrame:StripTextures(true)
+ QuestRewardScrollChildFrame:StripTextures(true)
+ QuestFrameProgressPanel:StripTextures(true)
+ QuestFrameRewardPanel:StripTextures(true)
+
+ S:HandleButton(QuestFrameAcceptButton)
+ S:HandleButton(QuestFrameCompleteButton)
+ S:HandleButton(QuestFrameCompleteQuestButton)
+ S:HandleButton(QuestFrameDeclineButton)
+ S:HandleButton(QuestFrameGoodbyeButton)
+ S:HandleButton(QuestFrameCancelButton)
+
+ QuestFrameNpcNameText:ClearAllPoints()
+ QuestFrameNpcNameText:Point("TOP", QuestFrame, "TOP", -6, -15)
+
+ QuestDetailScrollFrame:Size(304, 402)
+ QuestRewardScrollFrame:Size(304, 402)
+ QuestProgressScrollFrame:Size(304, 402)
+
+ QuestDetailScrollFrame:Point("TOPLEFT", QuestFrame, "TOPLEFT", 19, -73)
+ QuestRewardScrollFrame:Point("TOPLEFT", QuestFrame, "TOPLEFT", 19, -73)
+ QuestProgressScrollFrame:Point("TOPLEFT", QuestFrame, "TOPLEFT", 19, -73)
+
+ QuestDetailScrollFrameScrollBar:Point("TOPLEFT", QuestDetailScrollFrame, "TOPRIGHT", 3, -19)
+ QuestDetailScrollFrameScrollBar:Point("BOTTOMLEFT", QuestDetailScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ QuestRewardScrollFrameScrollBar:Point("TOPLEFT", QuestRewardScrollFrame, "TOPRIGHT", 3, -19)
+ QuestRewardScrollFrameScrollBar:Point("BOTTOMLEFT", QuestRewardScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ QuestProgressScrollFrameScrollBar:Point("TOPLEFT", QuestProgressScrollFrame, "TOPRIGHT", 3, -19)
+ QuestProgressScrollFrameScrollBar:Point("BOTTOMLEFT", QuestProgressScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ QuestFrameAcceptButton:Point("BOTTOMLEFT", 19, 8)
+ QuestFrameCompleteButton:Point("BOTTOMLEFT", 19, 8)
+ QuestFrameCompleteQuestButton:Point("BOTTOMLEFT", 19, 8)
+ QuestFrameDeclineButton:Point("BOTTOMRIGHT", -40, 8)
+ QuestFrameGoodbyeButton:Point("BOTTOMRIGHT", -40, 8)
+ QuestFrameCancelButton:Point("BOTTOMRIGHT", -40, 8)
+
+ -- Quest Greeting Frame
+ QuestFrameGreetingPanel:StripTextures(true)
+ QuestGreetingFrameHorizontalBreak:Kill()
+
+ S:HandleButton(QuestFrameGreetingGoodbyeButton, true)
+ S:HandleScrollBar(QuestGreetingScrollFrameScrollBar)
+
+ GreetingText:SetTextColor(1, 1, 1)
+ CurrentQuestsText:SetTextColor(1, 0.80, 0.10)
+ AvailableQuestsText:SetTextColor(1, 0.80, 0.10)
+
+ GreetingText.SetTextColor = E.noop
+ CurrentQuestsText.SetTextColor = E.noop
+ AvailableQuestsText.SetTextColor = E.noop
+
+ QuestGreetingScrollFrame:Size(304, 402)
+ QuestGreetingScrollFrame:Point("TOPLEFT", GossipFrame, "TOPLEFT", 19, -73)
+
+ QuestGreetingScrollFrameScrollBar:Point("TOPLEFT", QuestGreetingScrollFrame, "TOPRIGHT", 3, -19)
+ QuestGreetingScrollFrameScrollBar:Point("BOTTOMLEFT", QuestGreetingScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ QuestFrameGreetingGoodbyeButton:Point("BOTTOMRIGHT", -40, 8)
+
+ QuestFrameGreetingPanel:HookScript("OnShow", function()
+ for i = 1, MAX_NUM_QUESTS do
+ local button = _G["QuestTitleButton"..i]
+
+ if button:GetFontString() then
+ if button:GetText() and find(button:GetText(), "|cff000000") then
+ button:SetText(gsub(button:GetText(), "|cff000000", "|cffFFFF00"))
+ end
+ end
+ end
+ end)
+
+ -- Quest Progress + Reward
+ QuestInfoItemHighlight:StripTextures()
+
+ QuestInfoTimerText:SetTextColor(1, 1, 1)
+ QuestInfoAnchor:SetTextColor(1, 1, 1)
+
+ local items = {
+ ["QuestInfoItem"] = MAX_NUM_ITEMS,
+ ["QuestProgressItem"] = MAX_REQUIRED_ITEMS
+ }
+ for frame, numItems in pairs(items) do
+ for i = 1, numItems do
+ local item = _G[frame..i]
+ local icon = _G[frame..i.."IconTexture"]
+ local count = _G[frame..i.."Count"]
+
+ item:StripTextures()
+ item:SetTemplate("Default")
+ item:StyleButton()
+ item:Size(143, 40)
+ item:SetFrameLevel(item:GetFrameLevel() + 2)
+
+ icon:Size(E.PixelMode and 38 or 32)
+ icon:SetDrawLayer("OVERLAY")
+ icon:Point("TOPLEFT", E.PixelMode and 1 or 4, -(E.PixelMode and 1 or 4))
+ S:HandleIcon(icon)
+
+ count:SetParent(item.backdrop)
+ count:SetDrawLayer("OVERLAY")
+ end
+ end
+
+ local function questQualityColors(frame, text, link, quality)
+ if link and not quality then
+ quality = select(3, GetItemInfo(link))
+ end
+
+ if quality then
+ local r, g, b = GetItemQualityColor(quality)
+
+ frame:SetBackdropBorderColor(r, g, b)
+ frame.backdrop:SetBackdropBorderColor(r, g, b)
+
+ text:SetTextColor(r, g, b)
+ else
+ frame:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ frame.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
+
+ text:SetTextColor(1, 1, 1)
+ end
+ end
+
+ hooksecurefunc("QuestFrameProgressItems_Update", function()
+ QuestProgressTitleText:SetTextColor(1, 0.80, 0.10)
+ QuestProgressText:SetTextColor(1, 1, 1)
+ QuestProgressRequiredItemsText:SetTextColor(1, 0.80, 0.10)
+
+ local moneyToGet = GetQuestMoneyToGet()
+
+ if moneyToGet > 0 then
+ if moneyToGet > GetMoney() then
+ QuestProgressRequiredMoneyText:SetTextColor(0.6, 0.6, 0.6)
+ else
+ QuestProgressRequiredMoneyText:SetTextColor(1, 0.80, 0.10)
+ end
+ end
+
+ local item, name, link
+
+ for i = 1, MAX_REQUIRED_ITEMS do
+ item = _G["QuestProgressItem"..i]
+ name = _G["QuestProgressItem"..i.."Name"]
+ link = item.type and GetQuestItemLink(item.type, item:GetID())
+
+ questQualityColors(item, name, link)
+ end
+ end)
+
+ hooksecurefunc("QuestInfoItem_OnClick", function(self)
+ if self.type == "choice" then
+ self:SetBackdropBorderColor(1, 0.80, 0.10)
+ self.backdrop:SetBackdropBorderColor(1, 0.80, 0.10)
+ _G[self:GetName().."Name"]:SetTextColor(1, 0.80, 0.10)
+
+ local item, name, link
+
+ for i = 1, MAX_NUM_ITEMS do
+ item = _G["QuestInfoItem"..i]
+
+ if item ~= self then
+ name = _G["QuestInfoItem"..i.."Name"]
+ link = item.type and (QuestInfoFrame.questLog and GetQuestLogItemLink or GetQuestItemLink)(item.type, item:GetID())
+
+ questQualityColors(item, name, link)
+ end
+ end
+ end
+ end)
+
+ local function questObjectiveText()
+ local numObjectives = GetNumQuestLeaderBoards()
+ local _, objType, finished, objective
+ local numVisibleObjectives = 0
+
+ for i = 1, numObjectives do
+ _, objType, finished = GetQuestLogLeaderBoard(i)
+
+ if objType ~= "spell" then
+ numVisibleObjectives = numVisibleObjectives + 1
+ objective = _G["QuestInfoObjective"..numVisibleObjectives]
+
+ if finished then
+ objective:SetTextColor(1, 0.80, 0.10)
+ else
+ objective:SetTextColor(0.6, 0.6, 0.6)
+ end
+ end
+ end
+ end
+
+ hooksecurefunc("QuestInfo_Display", function()
+ QuestInfoTitleHeader:SetTextColor(1, 0.80, 0.10)
+ QuestInfoDescriptionHeader:SetTextColor(1, 0.80, 0.10)
+ QuestInfoObjectivesHeader:SetTextColor(1, 0.80, 0.10)
+ QuestInfoRewardsHeader:SetTextColor(1, 0.80, 0.10)
+
+ QuestInfoDescriptionText:SetTextColor(1, 1, 1)
+ QuestInfoObjectivesText:SetTextColor(1, 1, 1)
+ QuestInfoGroupSize:SetTextColor(1, 1, 1)
+ QuestInfoRewardText:SetTextColor(1, 1, 1)
+
+ QuestInfoItemChooseText:SetTextColor(1, 1, 1)
+ QuestInfoItemReceiveText:SetTextColor(1, 1, 1)
+ QuestInfoSpellLearnText:SetTextColor(1, 1, 1)
+ QuestInfoHonorFrameReceiveText:SetTextColor(1, 1, 1)
+ QuestInfoArenaPointsFrameReceiveText:SetTextColor(1, 1, 1)
+ QuestInfoTalentFrameReceiveText:SetTextColor(1, 1, 1)
+ QuestInfoXPFrameReceiveText:SetTextColor(1, 1, 1)
+ QuestInfoReputationText:SetTextColor(1, 1, 1)
+
+ for i = 1, MAX_REPUTATIONS do
+ _G["QuestInfoReputation"..i.."Faction"]:SetTextColor(1, 1, 1)
+ end
+
+ local requiredMoney = GetQuestLogRequiredMoney()
+
+ if requiredMoney > 0 then
+ if requiredMoney > GetMoney() then
+ QuestInfoRequiredMoneyText:SetTextColor(0.6, 0.6, 0.6)
+ else
+ QuestInfoRequiredMoneyText:SetTextColor(1, 0.80, 0.10)
+ end
+ end
+
+ questObjectiveText()
+
+ local item, name, link
+
+ for i = 1, MAX_NUM_ITEMS do
+ item = _G["QuestInfoItem"..i]
+ name = _G["QuestInfoItem"..i.."Name"]
+ link = item.type and (QuestInfoFrame.questLog and GetQuestLogItemLink or GetQuestItemLink)(item.type, item:GetID())
+
+ questQualityColors(item, name, link)
+ end
+ end)
+
+ hooksecurefunc("QuestInfo_ShowRewards", function()
+ local item, name, link
+
+ for i = 1, MAX_NUM_ITEMS do
+ item = _G["QuestInfoItem"..i]
+ name = _G["QuestInfoItem"..i.."Name"]
+ link = item.type and (QuestInfoFrame.questLog and GetQuestLogItemLink or GetQuestItemLink)(item.type, item:GetID())
+
+ questQualityColors(item, name, link)
+ end
+ end)
+
+ hooksecurefunc("QuestInfo_ShowRequiredMoney", function()
+ local requiredMoney = GetQuestLogRequiredMoney()
+
+ if requiredMoney > 0 then
+ if requiredMoney > GetMoney() then
+ QuestInfoRequiredMoneyText:SetTextColor(0.6, 0.6, 0.6)
+ else
+ QuestInfoRequiredMoneyText:SetTextColor(1, 0.80, 0.10)
+ end
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Raid.lua b/ElvUI/Modules/Skins/Blizzard/Raid.lua
new file mode 100644
index 0000000..87485f1
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Raid.lua
@@ -0,0 +1,152 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local ipairs = ipairs
+local unpack = unpack
+--WoW API / Variables
+
+S:AddCallbackForAddon("Blizzard_RaidUI", "Skin_Blizzard_RaidUI", function()
+ if E.private.skins.blizzard.enable and E.private.skins.blizzard.friends then
+ RaidClassButton1:HookScript("OnShow", function()
+ S:SetUIPanelWindowInfo(FriendsFrame, "width", nil, 21)
+ end)
+ RaidClassButton1:HookScript("OnHide", function()
+ S:SetUIPanelWindowInfo(FriendsFrame, "width")
+ end)
+ end
+
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.raid then return end
+
+ local StripAllTextures = {
+ RaidGroup1,
+ RaidGroup2,
+ RaidGroup3,
+ RaidGroup4,
+ RaidGroup5,
+ RaidGroup6,
+ RaidGroup7,
+ RaidGroup8
+ }
+
+ for _, object in ipairs(StripAllTextures) do
+ object:StripTextures()
+ end
+
+ RaidFrameRaidBrowserButton:Point("TOPLEFT", RaidFrame, 45, -33)
+
+ S:HandleButton(RaidFrameRaidBrowserButton)
+ S:HandleButton(RaidFrameReadyCheckButton)
+-- S:HandleButton(RaidFrameRaidInfoButton) -- skinned in Friends.lua
+
+ for i = 1, MAX_RAID_GROUPS * 5 do
+ S:HandleButton(_G["RaidGroupButton"..i], true)
+ end
+
+ for i = 1, 8 do
+ for j = 1, 5 do
+ local slot = _G["RaidGroup"..i.."Slot"..j]
+ slot:StripTextures()
+ slot:SetTemplate("Transparent")
+ end
+ end
+
+ do
+ local prevButton
+ local button, icon, count, coords
+
+ for index = 1, 13 do
+ button = _G["RaidClassButton"..index]
+ icon = _G["RaidClassButton"..index.."IconTexture"]
+ count = _G["RaidClassButton"..index.."Count"]
+
+ button:StripTextures()
+ button:SetTemplate("Default")
+ button:Size(22)
+
+ button:ClearAllPoints()
+ if index == 1 then
+ button:Point("TOPLEFT", RaidFrame, "TOPRIGHT", -33, -44)
+ elseif index == 11 then
+ button:Point("TOP", prevButton, "BOTTOM", 0, -25)
+ else
+ button:Point("TOP", prevButton, "BOTTOM", 0, -5)
+ end
+ prevButton = button
+
+ icon:SetInside()
+
+ if index == 11 then
+ icon:SetTexture("Interface\\RaidFrame\\UI-RaidFrame-Pets")
+ icon:SetTexCoord(unpack(E.TexCoords))
+ elseif index == 12 then
+ icon:SetTexture("Interface\\RaidFrame\\UI-RaidFrame-MainTank")
+ icon:SetTexCoord(unpack(E.TexCoords))
+ elseif index == 13 then
+ icon:SetTexture("Interface\\RaidFrame\\UI-RaidFrame-MainAssist")
+ icon:SetTexCoord(unpack(E.TexCoords))
+ else
+ coords = CLASS_ICON_TCOORDS[CLASS_SORT_ORDER[index]]
+ icon:SetTexture("Interface\\WorldStateFrame\\Icons-Classes")
+ icon:SetTexCoord(coords[1] + 0.02, coords[2] - 0.02, coords[3] + 0.02, coords[4] - 0.02)
+ end
+
+ count:FontTemplate(nil, 12, "OUTLINE")
+ end
+ end
+
+ hooksecurefunc("RaidPulloutButton_OnDragStart", function(frame)
+ if InCombatLockdown() then return end
+
+ local scale = GetScreenHeightScale()
+ local cursorX, cursorY = GetCursorPosition()
+ frame:SetPoint("TOP", nil, "BOTTOMLEFT", cursorX * scale, cursorY * scale)
+ end)
+
+ local nSkinned = 0
+ hooksecurefunc("RaidPullout_GetFrame", function()
+ if nSkinned < NUM_RAID_PULLOUT_FRAMES then
+ nSkinned = NUM_RAID_PULLOUT_FRAMES
+
+ local pfButton = _G["RaidPullout"..nSkinned]
+ pfButton:CreateBackdrop("Transparent")
+ pfButton.backdrop:Point("TOPLEFT", 9, -17)
+ pfButton.backdrop:Point("BOTTOMRIGHT", -7, 7)
+
+ _G["RaidPullout"..nSkinned.."MenuBackdrop"]:SetBackdrop(nil)
+ end
+ end)
+
+ local MAX_RAID_AURAS = MAX_RAID_AURAS
+ local pfButtonSubFrames = {"HealthBar", "ManaBar", "Target", "TargetTarget"}
+
+ hooksecurefunc("RaidPullout_Update", function(pullOutFrame)
+ for _, pfButton in ipairs(pullOutFrame.buttons) do
+ if not pfButton.backdrop then
+ local pfBName = pfButton:GetName()
+ local pfTot = _G[pfBName.."TargetTargetFrame"]
+
+ for _, sName in ipairs(pfButtonSubFrames) do
+ local sBar = _G[pfBName..sName]
+ sBar:StripTextures()
+ sBar:SetStatusBarTexture(E.media.normTex)
+ end
+
+ pfButton:CreateBackdrop("Default")
+ pfButton.backdrop:Point("TOPLEFT", E.PixelMode and 0 or -1, -(E.PixelMode and 10 or 9))
+ pfButton.backdrop:Point("BOTTOMRIGHT", E.PixelMode and 0 or 1, E.PixelMode and -2 or 0)
+
+ pfTot:StripTextures()
+ pfTot:CreateBackdrop("Default")
+ pfTot.backdrop:Point("TOPLEFT", E.PixelMode and 10 or 9, -(E.PixelMode and 15 or 14))
+ pfTot.backdrop:Point("BOTTOMRIGHT", -(E.PixelMode and 10 or 9), E.PixelMode and 8 or 7)
+
+ for i = 1, MAX_RAID_AURAS do
+ S:HandleIcon(_G[pfBName.."Aura"..i.."Icon"])
+ _G[pfBName.."Aura"..i.."Border"]:Hide()
+ end
+ end
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Socket.lua b/ElvUI/Modules/Skins/Blizzard/Socket.lua
new file mode 100644
index 0000000..3b36321
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Socket.lua
@@ -0,0 +1,90 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+--WoW API / Variables
+local GetNumSockets = GetNumSockets
+local GetSocketTypes = GetSocketTypes
+
+S:AddCallbackForAddon("Blizzard_ItemSocketingUI", "Skin_Blizzard_ItemSocketingUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.socket then return end
+
+ ITEM_SOCKETING_DESCRIPTION_MIN_WIDTH = 278
+
+ ItemSocketingFrame:StripTextures()
+ ItemSocketingFrame:CreateBackdrop("Transparent")
+ ItemSocketingFrame.backdrop:Point("TOPLEFT", 11, -12)
+ ItemSocketingFrame.backdrop:Point("BOTTOMRIGHT", -2, 31)
+
+ S:SetUIPanelWindowInfo(ItemSocketingFrame, "width")
+ S:SetBackdropHitRect(ItemSocketingFrame)
+
+ ItemSocketingFramePortrait:Kill()
+
+ S:HandleCloseButton(ItemSocketingCloseButton, ItemSocketingFrame.backdrop)
+
+ ItemSocketingScrollFrame:Height(269)
+ ItemSocketingScrollFrame:Point("TOPLEFT", 20, -77)
+ ItemSocketingScrollFrame:StripTextures()
+ ItemSocketingScrollFrame:CreateBackdrop("Transparent")
+ ItemSocketingScrollFrame.backdrop:Point("BOTTOMRIGHT", 3, -2)
+
+ S:HandleScrollBar(ItemSocketingScrollFrameScrollBar)
+
+ ItemSocketingScrollFrameScrollBar:Point("TOPLEFT", ItemSocketingScrollFrame, "TOPRIGHT", 6, -18)
+ ItemSocketingScrollFrameScrollBar:Point("BOTTOMLEFT", ItemSocketingScrollFrame, "BOTTOMRIGHT", 6, 17)
+
+ S:HandleButton(ItemSocketingSocketButton)
+ ItemSocketingSocketButton:Point("BOTTOMRIGHT", -10, 39)
+
+ for i = 1, MAX_NUM_SOCKETS do
+ local button = _G["ItemSocketingSocket"..i]
+ local bracket = _G["ItemSocketingSocket"..i.."BracketFrame"]
+ local bg = _G["ItemSocketingSocket"..i.."Background"]
+ local icon = _G["ItemSocketingSocket"..i.."IconTexture"]
+ local shine = _G["ItemSocketingSocket"..i.."Shine"]
+
+ button:StripTextures()
+ button:StyleButton(false)
+ button:SetTemplate("Default", true)
+
+ bracket:Kill()
+ bg:Kill()
+
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetInside()
+
+ shine:Point("CENTER")
+ shine:Size(40)
+ end
+
+ local GEM_TYPE_INFO = GEM_TYPE_INFO
+
+ hooksecurefunc("ItemSocketingFrame_Update", function()
+ local numSockets = GetNumSockets()
+
+ for i = 1, numSockets do
+ local button = _G["ItemSocketingSocket"..i]
+ local color = GEM_TYPE_INFO[GetSocketTypes(i)]
+ button:SetBackdropColor(color.r, color.g, color.b, 0.15)
+ button:SetBackdropBorderColor(color.r, color.g, color.b)
+ end
+
+ if numSockets == 3 then
+ ItemSocketingSocket1:SetPoint("BOTTOM", -80, 70)
+ elseif numSockets == 2 then
+ ItemSocketingSocket1:SetPoint("BOTTOM", -36, 70)
+ else
+ ItemSocketingSocket1:SetPoint("BOTTOM", 0, 70)
+ end
+ end)
+
+ hooksecurefunc(ItemSocketingScrollFrame, "SetWidth", function(self, width)
+ if width == 269 then
+ self:Width(300)
+ elseif width == 297 then
+ self:Width(321)
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Spellbook.lua b/ElvUI/Modules/Skins/Blizzard/Spellbook.lua
new file mode 100644
index 0000000..3641070
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Spellbook.lua
@@ -0,0 +1,209 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+--WoW API / Variables
+--local SpellBook_GetCurrentPage = SpellBook_GetCurrentPage
+--local BOOKTYPE_SPELL = BOOKTYPE_SPELL
+local MAX_SKILLLINE_TABS = MAX_SKILLLINE_TABS
+
+S:AddCallback("Skin_Spellbook", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.spellbook then return end
+
+ -- AscensionSpellbook
+
+ AscensionSpellbookFrame:StripTextures(true)
+ AscensionSpellbookFrame:CreateBackdrop("Transparent")
+ --AscensionSpellbookFrame:Size -- for later on, the spells will need to be moved as well
+ AscensionSpellbookFrameNineSlice:StripTextures(true)
+ --AscensionSpellbookFrameNineSlice:CreateBackdrop("Transparent")
+ AscensionSpellbookFrameInset:StripTextures(true)
+ AscensionSpellbookFrameInset:CreateBackdrop("Transparent")
+
+ AscensionSpellbookFrame:RegisterForDrag("LeftButton")
+ AscensionSpellbookFrame:SetMovable(true)
+ AscensionSpellbookFrame:SetScript("OnDragStart", function(self) self:StartMoving() end)
+ AscensionSpellbookFrame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
+
+ -- AscensionSpellbookFrame:SetScale(0.9)
+
+ for i = 1, 3 do
+ local tab = _G["AscensionSpellbookFrameTab"..i]
+ tab:Size(122, 32)
+ tab:GetRegions():SetPoint("CENTER", 0, 2)
+ S:HandleTab(tab)
+ end
+
+ AscensionSpellbookFrameTab1:Point("CENTER", AscensionSpellbookFrame, "BOTTOMLEFT", 72, 62)
+ AscensionSpellbookFrameTab2:Point("LEFT", AscensionSpellbookFrameTab1, "RIGHT", -15, 0)
+ AscensionSpellbookFrameTab3:Point("LEFT", AscensionSpellbookFrameTab2, "RIGHT", -15, 0)
+
+ S:HandleNextPrevButton(AscensionSpellbookFramePreviousPageButton, nil, nil, true)
+ S:HandleNextPrevButton(AscensionSpellbookFrameNextPageButton, nil, nil, true)
+
+ S:HandleCloseButton(AscensionSpellbookFrameCloseButton)
+
+ S:HandleCheckBox(AscensionSpellbookFrameContentSpellsShowAllSpellRanks)
+
+ for i = 1, SPELLS_PER_PAGE do
+ local button = _G["AscensionSpellbookFrameContentSpellsSpellButton"..i]
+ local autoCast = _G["AscensionSpellbookFrameContentSpellsSpellButton"..i.."AutoCastable"]
+ button:StripTextures()
+ button:CreateBackdrop("Default", true)
+
+ autoCast:SetTexture("Interface\\Buttons\\UI-AutoCastableOverlay")
+ autoCast:SetOutside(button, 16, 16)
+
+ _G["AscensionSpellbookFrameContentSpellsSpellButton"..i.."IconTexture"]:SetTexCoord(unpack(E.TexCoords))
+
+ E:RegisterCooldown(_G["AscensionSpellbookFrameContentSpellsSpellButton"..i.."Cooldown"])
+ end
+
+ hooksecurefunc("SpellButton_UpdateButton", function(self)
+ local name = self:GetName()
+ _G[name.."SpellName"]:SetTextColor(1, 0.80, 0.10)
+ _G[name.."SubSpellName"]:SetTextColor(1, 1, 1)
+ _G[name.."Highlight"]:SetTexture(1, 1, 1, 0.3)
+ end)
+
+ for i = 1, MAX_SKILLLINE_TABS do
+ local tab = _G["AscensionSpellbookFrameSideBarTab"..i]
+
+ tab:StripTextures()
+ tab:StyleButton(nil, true)
+ tab:SetTemplate("Default", true)
+
+ tab:GetNormalTexture():SetInside()
+ tab:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+ end
+
+ AscensionSpellbookFrameSideBarTab1:Point("TOPLEFT", AscensionSpellbookFrame, "TOPRIGHT", 0, -40)
+
+ for i = 2, MAX_SKILLLINE_TABS do
+ local tab = _G["AscensionSpellbookFrameSideBarTab"..i]
+ local previous = _G["AscensionSpellbookFrameSideBarTab"..i - 1]
+
+ tab:SetPoint("TOPLEFT", previous, "BOTTOMLEFT", 0, -8)
+ end
+
+ SpellBookPageText:SetTextColor(1, 1, 1)
+
+ --Professions
+ AscensionSpellbookFrameContentProfessions:StripTextures(true)
+
+ for i = 1, 5 do
+ local professions = _G["AscensionSpellbookFrameContentProfessionsProfession"..i]
+ --_G["AscensionSpellbookFrameContentProfessionsProfession"..i.."MainSpellIconTexture"]:SetTexCoord(unpack(E.TexCoords))
+ --_G["AscensionSpellbookFrameContentProfessionsProfession"..i.."ExtraSpellIconTexture"]:SetTexCoord(unpack(E.TexCoords))
+ S:HandleStatusBar(_G["AscensionSpellbookFrameContentProfessionsProfession"..i.."StatusBar"])
+ professions.MissingText:FontTemplate(nil,12)
+ professions.MissingText:SetTextColor(1, 1, 1)
+
+ end
+
+ -- Pet Tab
+ AscensionSpellbookFrameContentPetSpells:StripTextures(true)
+ AscensionSpellbookFrameContentPetSpells:CreateBackdrop("Transparent")
+
+ for i = 1, 12 do
+ local button = _G["AscensionSpellbookFrameContentPetSpellsSpellButton"..i]
+ button:StripTextures()
+ button:CreateBackdrop("Default", true)
+
+ _G["AscensionSpellbookFrameContentPetSpellsSpellButton"..i.."IconTexture"]:SetTexCoord(unpack(E.TexCoords))
+
+ E:RegisterCooldown(_G["AscensionSpellbookFrameContentPetSpellsSpellButton"..i.."Cooldown"])
+ end
+
+
+
+ -- Blizz Spellbook (Leaving here for now)
+ SpellBookFrame:StripTextures(true)
+ SpellBookFrame:CreateBackdrop("Transparent")
+ SpellBookFrame.backdrop:Point("TOPLEFT", 11, -12)
+ SpellBookFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(SpellBookFrame, "width", nil, 32)
+ S:SetBackdropHitRect(SpellBookFrame)
+
+--[[
+ SpellBookFrame:EnableMouseWheel(true)
+ SpellBookFrame:SetScript("OnMouseWheel", function(_, value)
+ --do nothing if not on an appropriate book type
+ if SpellBookFrame.bookType ~= BOOKTYPE_SPELL then
+ return
+ end
+
+ local currentPage, maxPages = SpellBook_GetCurrentPage()
+
+ if value > 0 then
+ if currentPage > 1 then
+ SpellBookPrevPageButton_OnClick()
+ end
+ else
+ if currentPage < maxPages then
+ SpellBookNextPageButton_OnClick()
+ end
+ end
+ end)
+]]
+
+ for i = 1, 3 do
+ local tab = _G["SpellBookFrameTabButton"..i]
+ tab:Size(122, 32)
+ tab:GetNormalTexture():SetTexture(nil)
+ tab:GetDisabledTexture():SetTexture(nil)
+ tab:GetRegions():SetPoint("CENTER", 0, 2)
+ S:HandleTab(tab)
+ end
+
+ SpellBookFrameTabButton1:Point("CENTER", SpellBookFrame, "BOTTOMLEFT", 72, 62)
+ SpellBookFrameTabButton2:Point("LEFT", SpellBookFrameTabButton1, "RIGHT", -15, 0)
+ SpellBookFrameTabButton3:Point("LEFT", SpellBookFrameTabButton2, "RIGHT", -15, 0)
+
+ S:HandleNextPrevButton(SpellBookPrevPageButton, nil, nil, true)
+ S:HandleNextPrevButton(SpellBookNextPageButton, nil, nil, true)
+
+ S:HandleCloseButton(SpellBookCloseButton, SpellBookFrame.backdrop)
+
+ S:HandleCheckBox(ShowAllSpellRanksCheckBox)
+
+ for i = 1, SPELLS_PER_PAGE do
+ local button = _G["SpellButton"..i]
+ local autoCast = _G["SpellButton"..i.."AutoCastable"]
+ button:StripTextures()
+
+ autoCast:SetTexture("Interface\\Buttons\\UI-AutoCastableOverlay")
+ autoCast:SetOutside(button, 16, 16)
+
+ button:CreateBackdrop("Default", true)
+
+ _G["SpellButton"..i.."IconTexture"]:SetTexCoord(unpack(E.TexCoords))
+
+ E:RegisterCooldown(_G["SpellButton"..i.."Cooldown"])
+ end
+
+ hooksecurefunc("SpellButton_UpdateButton", function(self)
+ local name = self:GetName()
+ _G[name.."SpellName"]:SetTextColor(1, 0.80, 0.10)
+ _G[name.."SubSpellName"]:SetTextColor(1, 1, 1)
+ _G[name.."Highlight"]:SetTexture(1, 1, 1, 0.3)
+ end)
+
+ for i = 1, MAX_SKILLLINE_TABS do
+ local tab = _G["SpellBookSkillLineTab"..i]
+
+ tab:StripTextures()
+ tab:StyleButton(nil, true)
+ tab:SetTemplate("Default", true)
+
+ tab:GetNormalTexture():SetInside()
+ tab:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+ end
+
+ SpellBookSkillLineTab1:Point("TOPLEFT", SpellBookFrame, "TOPRIGHT", -33, -65)
+
+ SpellBookPageText:SetTextColor(1, 1, 1)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Stable.lua b/ElvUI/Modules/Skins/Blizzard/Stable.lua
new file mode 100644
index 0000000..a1f9375
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Stable.lua
@@ -0,0 +1,83 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+--WoW API / Variables
+local GetPetHappiness = GetPetHappiness
+local HasPetUI = HasPetUI
+local UnitExists = UnitExists
+
+S:AddCallback("Skin_Stable", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.stable then return end
+
+ PetStableFrame:StripTextures()
+ PetStableFramePortrait:Kill()
+ PetStableFrame:CreateBackdrop("Transparent")
+ PetStableFrame.backdrop:Point("TOPLEFT", 11, -12)
+ PetStableFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(PetStableFrame, "width")
+ S:SetBackdropHitRect(PetStableFrame)
+
+ S:HandleCloseButton(PetStableFrameCloseButton, PetStableFrame.backdrop)
+
+ S:HandleRotateButton(PetStableModelRotateLeftButton)
+ S:HandleRotateButton(PetStableModelRotateRightButton)
+
+ S:HandleButton(PetStablePurchaseButton)
+
+ S:HandleItemButton(PetStableCurrentPet, true)
+ PetStableCurrentPetIconTexture:SetDrawLayer("OVERLAY")
+
+ PetStableModel:Size(325, 224)
+ PetStableModel:Point("TOPLEFT", 19, -71)
+
+ PetStableModelRotateLeftButton:Point("TOPLEFT", PetStableModel, "TOPLEFT", 4, -4)
+ PetStableModelRotateRightButton:Point("TOPLEFT", PetStableModelRotateLeftButton, "TOPRIGHT", 3, 0)
+
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 128, 64, 16, 16, 52, 4
+ PetStablePetInfo:GetRegions():SetTexCoord(0.03125, 0.15625, 0.0625, 0.3125)
+ PetStablePetInfo:SetFrameLevel(PetModelFrame:GetFrameLevel() + 2)
+ PetStablePetInfo:CreateBackdrop("Default")
+ PetStablePetInfo:Size(25)
+ PetStablePetInfo:Point("TOPLEFT", PetStableModelRotateLeftButton, "BOTTOMLEFT", 10, -4)
+
+ PetStableCurrentPet:Point("BOTTOMLEFT", 40, 150)
+
+ local function UpdateSlot(self, r, g, b)
+ if g ~= 1 then
+ self:SetTexture(.8, .2, .2, .3)
+ else
+ self:SetTexture(0, 0, 0, 0)
+ end
+ end
+
+ for i = 1, NUM_PET_STABLE_SLOTS do
+ S:HandleItemButton(_G["PetStableStabledPet"..i], true)
+ _G["PetStableStabledPet"..i.."IconTexture"]:SetDrawLayer("OVERLAY")
+
+ local bg = _G["PetStableStabledPet"..i.."Background"]
+ bg:SetDrawLayer("BORDER")
+ bg:SetInside()
+ hooksecurefunc(bg, "SetVertexColor", UpdateSlot)
+ end
+
+ hooksecurefunc("PetStable_Update", function()
+ local hasPetUI, isHunterPet = HasPetUI()
+ if hasPetUI and not isHunterPet and UnitExists("pet") then return end
+
+ local happiness = GetPetHappiness()
+
+ if happiness == 1 then
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 128, 64, 16, 16, 52, 4
+ PetStablePetInfo:GetRegions():SetTexCoord(0.40625, 0.53125, 0.0625, 0.3125)
+ elseif happiness == 2 then
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 128, 64, 16, 16, 28, 4
+ PetStablePetInfo:GetRegions():SetTexCoord(0.21875, 0.34375, 0.0625, 0.3125)
+ elseif happiness == 3 then
+ -- texWidth, texHeight, cropWidth, cropHeight, offsetX, offsetY = 128, 64, 16, 16, 52, 4
+ PetStablePetInfo:GetRegions():SetTexCoord(0.03125, 0.15625, 0.0625, 0.3125)
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Tabard.lua b/ElvUI/Modules/Skins/Blizzard/Tabard.lua
new file mode 100644
index 0000000..06ce358
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Tabard.lua
@@ -0,0 +1,59 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallback("Skin_Tabard", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.tabard then return end
+
+ TabardFrame:StripTextures()
+ TabardFrame:CreateBackdrop("Transparent")
+ TabardFrame.backdrop:Point("TOPLEFT", 11, -12)
+ TabardFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(TabardFrame, "width")
+ S:SetBackdropHitRect(TabardFrame)
+
+ S:HandleCloseButton(TabardFrameCloseButton, TabardFrame.backdrop)
+
+ TabardFramePortrait:Kill()
+
+ TabardModel:CreateBackdrop("Transparent")
+ TabardModel.backdrop:Point("TOPLEFT", -2, 5)
+ TabardModel.backdrop:Point("BOTTOMRIGHT", 20, -1)
+
+ S:HandleRotateButton(TabardCharacterModelRotateLeftButton)
+ S:HandleRotateButton(TabardCharacterModelRotateRightButton)
+
+ S:HandleButton(TabardFrameCancelButton)
+ S:HandleButton(TabardFrameAcceptButton)
+
+ TabardFrameCostFrame:StripTextures()
+ TabardFrameCustomizationFrame:StripTextures()
+
+ for i = 1, 5 do
+ _G["TabardFrameCustomization"..i]:StripTextures()
+ S:HandleNextPrevButton(_G["TabardFrameCustomization"..i.."LeftButton"])
+ S:HandleNextPrevButton(_G["TabardFrameCustomization"..i.."RightButton"])
+ end
+
+ TabardModel:Point("BOTTOM", -20, 114)
+
+ TabardCharacterModelRotateLeftButton:Point("BOTTOMLEFT", 2, 3)
+ TabardCharacterModelRotateRightButton:Point("TOPLEFT", TabardCharacterModelRotateLeftButton, "TOPRIGHT", 3, 0)
+
+-- TabardCharacterModelRotateLeftButton.SetPoint = E.noop
+-- TabardCharacterModelRotateRightButton.SetPoint = E.noop
+
+ TabardFrameEmblemTopRight:Point("TOPRIGHT", TabardFrameOuterFrameTopRight, "TOPRIGHT", 24, 6)
+
+ TabardFrameCustomization1:Point("TOPLEFT", TabardFrameCustomizationBorder, "TOPLEFT", 63, -63)
+
+ TabardFrameMoneyFrame:Point("BOTTOMRIGHT", TabardFrame, "BOTTOMLEFT", 183, 88)
+
+ TabardFrameCancelButton:Point("CENTER", TabardFrame, "TOPLEFT", 304, -417)
+ TabardFrameAcceptButton:Point("CENTER", TabardFrame, "TOPLEFT", 221, -417)
+
+ TabardModel:SetModelScale(1.25)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Talent.lua b/ElvUI/Modules/Skins/Blizzard/Talent.lua
new file mode 100644
index 0000000..e4399f9
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Talent.lua
@@ -0,0 +1,115 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+--WoW API / Variables
+
+S:AddCallbackForAddon("Blizzard_TalentUI", "Skin_Blizzard_TalentUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.talent then return end
+
+ PlayerTalentFrame:StripTextures(true)
+ PlayerTalentFrame:CreateBackdrop("Transparent")
+ PlayerTalentFrame.backdrop:Point("TOPLEFT", 11, -12)
+ PlayerTalentFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetBackdropHitRect(PlayerTalentFrame)
+
+ do
+ local offset
+
+ local talentGroups = GetNumTalentGroups(false, false)
+ local petTalentGroups = GetNumTalentGroups(false, true)
+
+ if talentGroups + petTalentGroups > 1 then
+ S:SetUIPanelWindowInfo(PlayerTalentFrame, "width", nil, 32)
+ offset = true
+ else
+ S:SetUIPanelWindowInfo(PlayerTalentFrame, "width")
+ end
+
+ hooksecurefunc("PlayerTalentFrame_UpdateSpecs", function(_, numTalentGroups, _, numPetTalentGroups)
+ if offset and numTalentGroups + numPetTalentGroups <= 1 then
+ S:SetUIPanelWindowInfo(PlayerTalentFrame, "width")
+ offset = nil
+ elseif not offset and numTalentGroups + numPetTalentGroups > 1 then
+ S:SetUIPanelWindowInfo(PlayerTalentFrame, "width", nil, 32)
+ offset = true
+ end
+ end)
+ end
+
+ S:HandleCloseButton(PlayerTalentFrameCloseButton, PlayerTalentFrame.backdrop)
+
+ local function glyphFrameOnShow(self)
+ if GlyphFrame and GlyphFrame:IsShown() then
+ self:Hide()
+ end
+ end
+
+ PlayerTalentFrameStatusFrame:HookScript("OnShow", glyphFrameOnShow)
+ PlayerTalentFrameActivateButton:HookScript("OnShow", glyphFrameOnShow)
+
+ PlayerTalentFrameStatusFrame:StripTextures()
+ PlayerTalentFramePointsBar:StripTextures()
+ PlayerTalentFramePreviewBar:StripTextures()
+
+ S:HandleButton(PlayerTalentFrameActivateButton)
+ S:HandleButton(PlayerTalentFrameResetButton)
+ S:HandleButton(PlayerTalentFrameLearnButton)
+
+ PlayerTalentFramePreviewBarFiller:StripTextures()
+
+ PlayerTalentFrameScrollFrame:StripTextures()
+ PlayerTalentFrameScrollFrame:CreateBackdrop("Default")
+ S:HandleScrollBar(PlayerTalentFrameScrollFrameScrollBar)
+
+ for i = 1, MAX_NUM_TALENTS do
+ local talent = _G["PlayerTalentFrameTalent"..i]
+ local icon = _G["PlayerTalentFrameTalent"..i.."IconTexture"]
+ local rank = _G["PlayerTalentFrameTalent"..i.."Rank"]
+
+ if talent then
+ talent:StripTextures()
+ talent:SetTemplate("Default")
+ talent:StyleButton()
+
+ icon:SetInside()
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetDrawLayer("ARTWORK")
+
+ rank:SetFont(E.LSM:Fetch("font", E.db.general.font), 12, "OUTLINE")
+ end
+ end
+
+ for i = 1, 4 do
+ S:HandleTab(_G["PlayerTalentFrameTab"..i])
+ end
+
+ for i = 1, MAX_TALENT_TABS do
+ local tab = _G["PlayerSpecTab"..i]
+ tab:GetRegions():Hide()
+
+ tab:SetTemplate("Default")
+ tab:StyleButton(nil, true)
+
+ tab:GetNormalTexture():SetInside()
+ tab:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+ end
+
+ PlayerTalentFrameStatusFrame:Point("TOPLEFT", 57, -40)
+ PlayerTalentFrameActivateButton:Point("TOP", 0, -40)
+
+ PlayerTalentFrameScrollFrame:Width(302)
+ PlayerTalentFrameScrollFrame:Point("TOPRIGHT", PlayerTalentFrame, "TOPRIGHT", -62, -77)
+ PlayerTalentFrameScrollFrame:Point("BOTTOM", PlayerTalentFramePointsBar, "TOP", 0, 0)
+
+ PlayerTalentFrameScrollFrameScrollBar:Point("TOPLEFT", PlayerTalentFrameScrollFrame, "TOPRIGHT", 4, -18)
+ PlayerTalentFrameScrollFrameScrollBar:Point("BOTTOMLEFT", PlayerTalentFrameScrollFrame, "BOTTOMRIGHT", 4, 18)
+
+ PlayerTalentFrameResetButton:Point("RIGHT", -4, 1)
+ PlayerTalentFrameLearnButton:Point("RIGHT", PlayerTalentFrameResetButton, "LEFT", -3, 0)
+
+ PlayerTalentFrameTab1:Point("BOTTOMLEFT", 11, 46)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Taxi.lua b/ElvUI/Modules/Skins/Blizzard/Taxi.lua
new file mode 100644
index 0000000..b49d78b
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Taxi.lua
@@ -0,0 +1,36 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallback("Skin_Taxi", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.taxi then return end
+
+ TaxiFrame:StripTextures()
+
+ TaxiFrame:CreateBackdrop("Transparent")
+ TaxiFrame.backdrop:Point("TOPLEFT", 11, -12)
+ TaxiFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(TaxiFrame, "width")
+ S:SetBackdropHitRect(TaxiFrame)
+
+ TaxiPortrait:Kill()
+
+ S:HandleCloseButton(TaxiCloseButton, TaxiFrame.backdrop)
+
+ TaxiRouteMap:CreateBackdrop("Default")
+
+ local TAXI_MAP_WIDTH = 331 -- orig 316
+ local TAXI_MAP_HEIGHT = 369 -- orig 352
+
+ _G.TAXI_MAP_WIDTH = TAXI_MAP_WIDTH
+ _G.TAXI_MAP_HEIGHT = TAXI_MAP_HEIGHT
+
+ TaxiMap:Size(TAXI_MAP_WIDTH, TAXI_MAP_HEIGHT)
+ TaxiRouteMap:Size(TAXI_MAP_WIDTH, TAXI_MAP_HEIGHT)
+
+ TaxiMap:Point("TOP", -11, -48)
+ TaxiRouteMap:Point("TOP", -11, -48)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/TimeManager.lua b/ElvUI/Modules/Skins/Blizzard/TimeManager.lua
new file mode 100644
index 0000000..d6f26d4
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/TimeManager.lua
@@ -0,0 +1,100 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallbackForAddon("Blizzard_TimeManager", "Skin_Blizzard_TimeManager", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.timemanager then return end
+
+ TimeManagerFrame:StripTextures()
+ TimeManagerFrame:SetTemplate("Transparent")
+
+ E:CreateMover(TimeManagerFrame, "TimeManagerFrameMover", TIMEMANAGER_TITLE)
+ TimeManagerFrame.mover:SetFrameLevel(TimeManagerFrame:GetFrameLevel() + 4)
+
+ S:HandleCloseButton(TimeManagerCloseButton, TimeManagerFrame)
+
+ TimeManagerStopwatchFrameBackground:SetTexture(nil)
+
+ TimeManagerStopwatchCheck:SetTemplate("Default")
+ TimeManagerStopwatchCheck:StyleButton(nil, true)
+
+ TimeManagerStopwatchCheck:GetNormalTexture():SetInside()
+ TimeManagerStopwatchCheck:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+
+ S:HandleDropDownBox(TimeManagerAlarmHourDropDown, 80)
+ S:HandleDropDownBox(TimeManagerAlarmMinuteDropDown, 80)
+ S:HandleDropDownBox(TimeManagerAlarmAMPMDropDown, 80)
+
+ S:HandleEditBox(TimeManagerAlarmMessageEditBox)
+
+ TimeManagerAlarmEnabledButton:SetNormalTexture(nil)
+ TimeManagerAlarmEnabledButton.SetNormalTexture = E.noop
+ TimeManagerAlarmEnabledButton:SetPushedTexture(nil)
+ TimeManagerAlarmEnabledButton.SetPushedTexture = E.noop
+ S:HandleButton(TimeManagerAlarmEnabledButton)
+
+ S:HandleCheckBox(TimeManagerMilitaryTimeCheck)
+ S:HandleCheckBox(TimeManagerLocalTimeCheck)
+
+ TimeManagerFrame:Size(186, 221)
+
+ select(7, TimeManagerFrame:GetRegions()):Point("TOP", 0, -5)
+
+ TimeManagerFrameTicker:Point("CENTER", TimeManagerGlobe, -4, 12)
+
+ TimeManagerStopwatchFrame:Point("TOPRIGHT", 9, -13)
+
+ TimeManagerAlarmTimeFrame:Point("TOPLEFT", 8, -56)
+
+ TimeManagerAlarmHourDropDown:Point("TOPLEFT", TimeManagerAlarmTimeLabel, "BOTTOMLEFT", -20, -3)
+ TimeManagerAlarmMinuteDropDown:Point("LEFT", TimeManagerAlarmHourDropDown, "RIGHT", -21, 0)
+ TimeManagerAlarmAMPMDropDown:Point("LEFT", TimeManagerAlarmMinuteDropDown, "RIGHT", -21, 0)
+
+ TimeManagerAlarmMessageEditBox:Width(168)
+ TimeManagerAlarmMessageEditBox:Point("TOPLEFT", TimeManagerAlarmMessageLabel, "BOTTOMLEFT", 1, -7)
+
+ TimeManagerAlarmEnabledButton:Size(170, 22)
+ TimeManagerAlarmEnabledButton:Point("LEFT", 8, -50)
+
+ TimeManagerMilitaryTimeCheck:Point("TOPLEFT", 158, -175)
+
+ -- StopwatchFrame
+ StopwatchFrame:CreateBackdrop("Transparent")
+ StopwatchFrame.backdrop:Point("TOPLEFT", 0, -20)
+ StopwatchFrame.backdrop:Point("BOTTOMRIGHT", 0, 0)
+
+ StopwatchFrame:StripTextures()
+ StopwatchTabFrame:StripTextures()
+
+ S:HandleCloseButton(StopwatchCloseButton)
+
+ S:HandleButton(StopwatchResetButton)
+
+ StopwatchTicker:Point("BOTTOMRIGHT", -49, 0)
+
+ StopwatchResetButton:Size(16)
+ StopwatchResetButton:Point("BOTTOMRIGHT", -4, 4)
+ StopwatchResetButton:SetNormalTexture("Interface\\AddOns\\ElvUI\\media\\textures\\reset")
+
+ StopwatchPlayPauseButton:Size(12)
+ StopwatchPlayPauseButton:Point("RIGHT", StopwatchResetButton, "LEFT", -5, 0)
+ StopwatchPlayPauseButton:CreateBackdrop("Default", true)
+ StopwatchPlayPauseButton.backdrop:SetOutside(StopwatchPlayPauseButton, 2, 2)
+ StopwatchPlayPauseButton:SetNormalTexture("Interface\\AddOns\\ElvUI\\media\\textures\\play")
+ StopwatchPlayPauseButton:SetHighlightTexture("")
+ StopwatchPlayPauseButton:HookScript("OnEnter", S.SetModifiedBackdrop)
+ StopwatchPlayPauseButton:HookScript("OnLeave", S.SetOriginalBackdrop)
+
+ local function SetPlayTexture()
+ StopwatchPlayPauseButton:SetNormalTexture("Interface\\AddOns\\ElvUI\\media\\textures\\play")
+ end
+ local function SetPauseTexture()
+ StopwatchPlayPauseButton:SetNormalTexture("Interface\\AddOns\\ElvUI\\media\\textures\\pause")
+ end
+
+ hooksecurefunc("Stopwatch_Play", SetPauseTexture)
+ hooksecurefunc("Stopwatch_Pause", SetPlayTexture)
+ hooksecurefunc("Stopwatch_Clear", SetPlayTexture)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Tooltip.lua b/ElvUI/Modules/Skins/Blizzard/Tooltip.lua
new file mode 100644
index 0000000..b329560
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Tooltip.lua
@@ -0,0 +1,45 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+local TT = E:GetModule("Tooltip")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallback("Skin_Tooltip", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.tooltip then return end
+
+ S:HandleCloseButton(ItemRefCloseButton, ItemRefTooltip)
+
+ local tooltips = {
+ GameTooltip,
+ ItemRefTooltip,
+ ItemRefShoppingTooltip1,
+ ItemRefShoppingTooltip2,
+ ItemRefShoppingTooltip3,
+ AutoCompleteBox,
+ FriendsTooltip,
+ ConsolidatedBuffsTooltip,
+ ShoppingTooltip1,
+ ShoppingTooltip2,
+ ShoppingTooltip3,
+ WorldMapTooltip,
+ WorldMapCompareTooltip1,
+ WorldMapCompareTooltip2,
+ WorldMapCompareTooltip3
+ }
+ for _, tt in ipairs(tooltips) do
+ TT:SecureHookScript(tt, "OnShow", "SetStyle")
+ end
+
+ GameTooltipStatusBar:SetStatusBarTexture(E.media.normTex)
+ E:RegisterStatusBar(GameTooltipStatusBar)
+ GameTooltipStatusBar:CreateBackdrop("Transparent")
+ GameTooltipStatusBar:ClearAllPoints()
+ GameTooltipStatusBar:Point("TOPLEFT", GameTooltip, "BOTTOMLEFT", E.Border, -(E.Spacing * 3))
+ GameTooltipStatusBar:Point("TOPRIGHT", GameTooltip, "BOTTOMRIGHT", -E.Border, -(E.Spacing * 3))
+
+ TT:SecureHook("GameTooltip_ShowStatusBar", "GameTooltip_ShowStatusBar")
+
+ TT:SecureHookScript(GameTooltip, "OnSizeChanged", "CheckBackdropColor")
+ TT:SecureHookScript(GameTooltip, "OnUpdate", "CheckBackdropColor")
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Trade.lua b/ElvUI/Modules/Skins/Blizzard/Trade.lua
new file mode 100644
index 0000000..d835ee2
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Trade.lua
@@ -0,0 +1,146 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack, select = unpack, select
+--WoW API / Variables
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local GetTradePlayerItemLink = GetTradePlayerItemLink
+local GetTradeTargetItemLink = GetTradeTargetItemLink
+
+S:AddCallback("Skin_Trade", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.trade then return end
+
+ TradeFrame:StripTextures(true)
+ TradeFrame:CreateBackdrop("Transparent")
+ TradeFrame.backdrop:Point("TOPLEFT", 11, -12)
+ TradeFrame.backdrop:Point("BOTTOMRIGHT", -21, 49)
+
+ S:SetUIPanelWindowInfo(TradeFrame, "width")
+ S:SetBackdropHitRect(TradeFrame)
+
+ S:HandleCloseButton(TradeFrameCloseButton, TradeFrame.backdrop)
+
+ S:HandleButton(TradeFrameTradeButton)
+ S:HandleButton(TradeFrameCancelButton)
+
+ S:HandleEditBox(TradePlayerInputMoneyFrameGold)
+ S:HandleEditBox(TradePlayerInputMoneyFrameSilver)
+ S:HandleEditBox(TradePlayerInputMoneyFrameCopper)
+
+ for i = 1, MAX_TRADE_ITEMS do
+ local player = _G["TradePlayerItem"..i]
+ local recipient = _G["TradeRecipientItem"..i]
+ local playerButton = _G["TradePlayerItem"..i.."ItemButton"]
+ local playerButtonIcon = _G["TradePlayerItem"..i.."ItemButtonIconTexture"]
+ local recipientButton = _G["TradeRecipientItem"..i.."ItemButton"]
+ local recipientButtonIcon = _G["TradeRecipientItem"..i.."ItemButtonIconTexture"]
+
+ player:StripTextures()
+ recipient:StripTextures()
+
+ playerButton:StripTextures()
+ playerButton:StyleButton()
+ playerButton:SetTemplate("Default", true)
+
+ playerButtonIcon:SetInside()
+ playerButtonIcon:SetTexCoord(unpack(E.TexCoords))
+
+ recipientButton:StripTextures()
+ recipientButton:StyleButton()
+ recipientButton:SetTemplate("Default", true)
+
+ recipientButtonIcon:SetInside()
+ recipientButtonIcon:SetTexCoord(unpack(E.TexCoords))
+
+ playerButton.bg = CreateFrame("Frame", nil, playerButton)
+ playerButton.bg:SetTemplate("Default")
+ playerButton.bg:Point("TOPLEFT", playerButton, "TOPRIGHT", 4, 0)
+ playerButton.bg:Point("BOTTOMRIGHT", _G["TradePlayerItem"..i.."NameFrame"], "BOTTOMRIGHT", 0, 14)
+ playerButton.bg:SetFrameLevel(playerButton:GetFrameLevel() - 3)
+
+ recipientButton.bg = CreateFrame("Frame", nil, recipientButton)
+ recipientButton.bg:SetTemplate("Default")
+ recipientButton.bg:Point("TOPLEFT", recipientButton, "TOPRIGHT", 4, 0)
+ recipientButton.bg:Point("BOTTOMRIGHT", _G["TradeRecipientItem"..i.."NameFrame"], "BOTTOMRIGHT", 0, 14)
+ recipientButton.bg:SetFrameLevel(recipientButton:GetFrameLevel() - 3)
+ end
+
+ TradeHighlightPlayerTop:SetTexture(0, 1, 0, 0.2)
+ TradeHighlightPlayerBottom:SetTexture(0, 1, 0, 0.2)
+ TradeHighlightPlayerMiddle:SetTexture(0, 1, 0, 0.2)
+
+ TradeHighlightPlayerEnchantTop:SetTexture(0, 1, 0, 0.2)
+ TradeHighlightPlayerEnchantBottom:SetTexture(0, 1, 0, 0.2)
+ TradeHighlightPlayerEnchantMiddle:SetTexture(0, 1, 0, 0.2)
+
+ TradeHighlightRecipientTop:SetTexture(0, 1, 0, 0.2)
+ TradeHighlightRecipientBottom:SetTexture(0, 1, 0, 0.2)
+ TradeHighlightRecipientMiddle:SetTexture(0, 1, 0, 0.2)
+
+ TradeHighlightRecipientEnchantTop:SetTexture(0, 1, 0, 0.2)
+ TradeHighlightRecipientEnchantBottom:SetTexture(0, 1, 0, 0.2)
+ TradeHighlightRecipientEnchantMiddle:SetTexture(0, 1, 0, 0.2)
+
+ TradeHighlightPlayer:SetFrameStrata("HIGH")
+ TradeHighlightRecipient:SetFrameStrata("HIGH")
+ TradeHighlightPlayerEnchant:SetFrameStrata("HIGH")
+ TradeHighlightRecipientEnchant:SetFrameStrata("HIGH")
+
+ hooksecurefunc("TradeFrame_UpdatePlayerItem", function(id)
+ local tradeItemButton = _G["TradePlayerItem"..id.."ItemButton"]
+ local link = GetTradePlayerItemLink(id)
+
+ if link then
+ local tradeItemName = _G["TradePlayerItem"..id.."Name"]
+ local quality = select(3, GetItemInfo(link))
+
+ tradeItemName:SetTextColor(GetItemQualityColor(quality))
+
+ if quality then
+ tradeItemButton:SetBackdropBorderColor(GetItemQualityColor(quality))
+ else
+ tradeItemButton:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ else
+ tradeItemButton:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end)
+
+ hooksecurefunc("TradeFrame_UpdateTargetItem", function(id)
+ local tradeItemButton = _G["TradeRecipientItem"..id.."ItemButton"]
+ local link = GetTradeTargetItemLink(id)
+
+ if link then
+ local tradeItemName = _G["TradeRecipientItem"..id.."Name"]
+ local quality = select(3, GetItemInfo(link))
+
+ tradeItemName:SetTextColor(GetItemQualityColor(quality))
+
+ if quality then
+ tradeItemButton:SetBackdropBorderColor(GetItemQualityColor(quality))
+ else
+ tradeItemButton:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ else
+ tradeItemButton:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end)
+
+ TradePlayerInputMoneyFrame:Point("TOPLEFT", 26, -53)
+ TradeRecipientMoneyFrame:Point("TOPRIGHT", -40, -58)
+
+ TradePlayerItem1:Point("TOPLEFT", 23, -94)
+ TradeRecipientItem1:Point("TOPLEFT", 196, -94)
+
+ TradeHighlightPlayer:Height(263)
+ TradeHighlightRecipient:Height(263)
+ TradeHighlightPlayer:Point("TOPLEFT", 20, -91)
+ TradeHighlightRecipient:Point("TOPLEFT", 193, -91)
+
+ TradeFramePlayerEnchantText:Point("TOPLEFT", 26, -364)
+
+ TradeFrameTradeButton:Point("BOTTOMRIGHT", -113, 61)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Tradeskill.lua b/ElvUI/Modules/Skins/Blizzard/Tradeskill.lua
new file mode 100644
index 0000000..4d5cf56
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Tradeskill.lua
@@ -0,0 +1,264 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack, select = unpack, select
+local find = string.find
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetItemInfo = GetItemInfo
+local GetItemQualityColor = GetItemQualityColor
+local GetTradeSkillItemLink = GetTradeSkillItemLink
+local GetTradeSkillReagentInfo = GetTradeSkillReagentInfo
+local GetTradeSkillReagentItemLink = GetTradeSkillReagentItemLink
+local hooksecurefunc = hooksecurefunc
+
+S:AddCallbackForAddon("Blizzard_TradeSkillUI", "Skin_Blizzard_TradeSkillUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.tradeskill then return end
+
+ local SKILLS_DISPLAYED = 21
+ TRADE_SKILLS_DISPLAYED = SKILLS_DISPLAYED
+
+ for i = 9, SKILLS_DISPLAYED do
+ CreateFrame("Button", "TradeSkillSkill"..i, TradeSkillFrame, "TradeSkillSkillButtonTemplate"):Point("TOPLEFT", _G["TradeSkillSkill"..i - 1], "BOTTOMLEFT")
+ end
+
+ TradeSkillFrame:StripTextures(true)
+ TradeSkillFrame:Width(713)
+
+ TradeSkillFrame:CreateBackdrop("Transparent")
+ TradeSkillFrame.backdrop:Point("TOPLEFT", 11, -12)
+ TradeSkillFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(TradeSkillFrame, "width")
+ S:SetBackdropHitRect(TradeSkillFrame)
+
+ S:HandleCloseButton(TradeSkillFrameCloseButton, TradeSkillFrame.backdrop)
+
+ TradeSkillRankFrame:StripTextures()
+ TradeSkillRankFrame:CreateBackdrop()
+ TradeSkillRankFrame:SetStatusBarTexture(E.media.normTex)
+ TradeSkillRankFrame:SetStatusBarColor(0.22, 0.39, 0.84)
+ TradeSkillRankFrame.SetStatusBarColor = E.noop
+ E:RegisterStatusBar(TradeSkillRankFrame)
+
+ S:HandleCheckBox(TradeSkillFrameAvailableFilterCheckButton)
+
+ S:HandleEditBox(TradeSkillFrameEditBox)
+
+ S:HandleDropDownBox(TradeSkillInvSlotDropDown, 140)
+ S:HandleDropDownBox(TradeSkillSubClassDropDown, 140)
+
+ TradeSkillExpandButtonFrame:StripTextures()
+
+ TradeSkillCollapseAllButton:SetNormalTexture(E.Media.Textures.Plus)
+ TradeSkillCollapseAllButton.SetNormalTexture = E.noop
+ TradeSkillCollapseAllButton:GetNormalTexture():Point("LEFT", 3, 2)
+ TradeSkillCollapseAllButton:GetNormalTexture():Size(16)
+
+ TradeSkillCollapseAllButton:SetHighlightTexture("")
+ TradeSkillCollapseAllButton.SetHighlightTexture = E.noop
+
+ TradeSkillCollapseAllButton:SetDisabledTexture(E.Media.Textures.Plus)
+ TradeSkillCollapseAllButton.SetDisabledTexture = E.noop
+ TradeSkillCollapseAllButton:GetDisabledTexture():Point("LEFT", 3, 2)
+ TradeSkillCollapseAllButton:GetDisabledTexture():Size(16)
+ TradeSkillCollapseAllButton:GetDisabledTexture():SetDesaturated(true)
+
+ for i = 1, SKILLS_DISPLAYED do
+ local skillButton = _G["TradeSkillSkill"..i]
+ local skillButtonHighlight = _G["TradeSkillSkill"..i.."Highlight"]
+
+ skillButton:SetNormalTexture(E.Media.Textures.Plus)
+ skillButton.SetNormalTexture = E.noop
+ skillButton:GetNormalTexture():Size(13)
+ skillButton:GetNormalTexture():Point("LEFT", 2, 1)
+
+ skillButtonHighlight:SetTexture("")
+ skillButtonHighlight.SetTexture = E.noop
+
+ hooksecurefunc(skillButton, "SetNormalTexture", function(self, texture)
+ if find(texture, "MinusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Minus)
+ elseif find(texture, "PlusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Plus)
+ else
+ self:GetNormalTexture():SetTexture("")
+ end
+ end)
+ end
+
+ TradeSkillListScrollFrame:StripTextures()
+ S:HandleScrollBar(TradeSkillListScrollFrameScrollBar)
+
+ TradeSkillDetailScrollFrame:StripTextures()
+ TradeSkillDetailScrollFrame.scrollBarHideable = nil
+ TradeSkillDetailScrollChildFrame:StripTextures()
+ S:HandleScrollBar(TradeSkillDetailScrollFrameScrollBar)
+
+ TradeSkillSkillIcon:StyleButton(nil, true)
+ TradeSkillSkillIcon:SetTemplate("Default")
+
+ TradeSkillRequirementLabel:SetTextColor(1, 0.80, 0.10)
+
+ for i = 1, MAX_TRADE_SKILL_REAGENTS do
+ local reagent = _G["TradeSkillReagent"..i]
+ local icon = _G["TradeSkillReagent"..i.."IconTexture"]
+ local count = _G["TradeSkillReagent"..i.."Count"]
+ local name = _G["TradeSkillReagent"..i.."Name"]
+ local nameFrame = _G["TradeSkillReagent"..i.."NameFrame"]
+
+ reagent:SetTemplate("Default")
+ reagent:StyleButton(nil, true)
+ reagent:Size(143, 40)
+
+ icon.backdrop = CreateFrame("Frame", nil, reagent)
+ icon.backdrop:SetTemplate()
+ icon.backdrop:Point("TOPLEFT", icon, -1, 1)
+ icon.backdrop:Point("BOTTOMRIGHT", icon, 1, -1)
+
+ icon:SetTexCoord(unpack(E.TexCoords))
+ icon:SetDrawLayer("OVERLAY")
+ icon:Size(E.PixelMode and 38 or 32)
+ icon:Point("TOPLEFT", E.PixelMode and 1 or 4, -(E.PixelMode and 1 or 4))
+ icon:SetParent(icon.backdrop)
+
+ count:SetParent(icon.backdrop)
+ count:SetDrawLayer("OVERLAY")
+
+ name:Point("LEFT", nameFrame, "LEFT", 20, 0)
+
+ nameFrame:Kill()
+ end
+
+ TradeSkillHighlight:SetTexture(E.Media.Textures.Highlight)
+ TradeSkillHighlight:SetAlpha(0.35)
+
+ S:HandleNextPrevButton(TradeSkillDecrementButton)
+ S:HandleEditBox(TradeSkillInputBox)
+ S:HandleNextPrevButton(TradeSkillIncrementButton)
+
+ S:HandleButton(TradeSkillCancelButton)
+ S:HandleButton(TradeSkillCreateButton)
+ S:HandleButton(TradeSkillCreateAllButton)
+
+ TradeSkillRankFrame:Size(522, 17)
+ TradeSkillRankFrame:Point("TOPLEFT", 85, -36)
+
+ TradeSkillRankFrameSkillRank:Point("TOP", TradeSkillFrameTitleText, 0, -23)
+
+ TradeSkillFrameAvailableFilterCheckButton:Point("TOPLEFT", 80, -59)
+
+ TradeSkillFrameEditBox:Height(18)
+ TradeSkillFrameEditBox:Point("TOPRIGHT", TradeSkillRankFrame, "BOTTOMRIGHT", -263, -9)
+
+ TradeSkillInvSlotDropDown:Point("TOPRIGHT", -32, -58)
+ TradeSkillSubClassDropDown:Point("RIGHT", TradeSkillInvSlotDropDown, "LEFT", 21, 0)
+
+ TradeSkillExpandButtonFrame:Point("TOPLEFT", 15, -68)
+
+ TradeSkillSkill1:Point("TOPLEFT", 25, -90)
+
+ TradeSkillListScrollFrame:Size(305, 340)
+ TradeSkillListScrollFrame:Point("TOPRIGHT", -389, -88)
+ TradeSkillListScrollFrame.Hide = E.noop
+ TradeSkillListScrollFrame:Show()
+
+ TradeSkillListScrollFrameScrollBar:Point("TOPLEFT", TradeSkillListScrollFrame, "TOPRIGHT", 3, -19)
+ TradeSkillListScrollFrameScrollBar:Point("BOTTOMLEFT", TradeSkillListScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ TradeSkillDetailScrollFrame:Size(304, 311)
+ TradeSkillDetailScrollFrame:Point("TOPLEFT", 348, -88)
+
+ TradeSkillDetailScrollChildFrame:Size(304, 310)
+
+ TradeSkillDetailScrollFrameScrollBar:Point("TOPLEFT", TradeSkillDetailScrollFrame, "TOPRIGHT", 3, -19)
+ TradeSkillDetailScrollFrameScrollBar:Point("BOTTOMLEFT", TradeSkillDetailScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ TradeSkillSkillIcon:Size(47)
+ TradeSkillSkillIcon:Point("TOPLEFT", 10, -9)
+
+ TradeSkillSkillName:Point("TOPLEFT", 65, -9)
+ TradeSkillDescription:Point("TOPLEFT", 8, -64)
+
+ TradeSkillReagent1:Point("TOPLEFT", TradeSkillReagentLabel, "BOTTOMLEFT", 1, -3)
+ TradeSkillReagent2:Point("LEFT", TradeSkillReagent1, "RIGHT", 3, 0)
+ TradeSkillReagent3:Point("TOPLEFT", TradeSkillReagent1, "BOTTOMLEFT", 0, -3)
+ TradeSkillReagent4:Point("LEFT", TradeSkillReagent3, "RIGHT", 3, 0)
+ TradeSkillReagent5:Point("TOPLEFT", TradeSkillReagent3, "BOTTOMLEFT", 0, -3)
+ TradeSkillReagent6:Point("LEFT", TradeSkillReagent5, "RIGHT", 3, 0)
+ TradeSkillReagent7:Point("TOPLEFT", TradeSkillReagent5, "BOTTOMLEFT", 0, -3)
+ TradeSkillReagent8:Point("LEFT", TradeSkillReagent7, "RIGHT", 3, 0)
+
+ TradeSkillInputBox:Height(16)
+
+ TradeSkillCancelButton:Point("CENTER", TradeSkillFrame, "TOPLEFT", 633, -417)
+ TradeSkillCreateButton:Point("CENTER", TradeSkillFrame, "TOPLEFT", 550, -417)
+ TradeSkillCreateAllButton:Point("RIGHT", TradeSkillCreateButton, "LEFT", -82, 0)
+ TradeSkillIncrementButton:Point("RIGHT", TradeSkillCreateButton, "LEFT", -4, 0)
+ TradeSkillDecrementButton:Point("LEFT", TradeSkillCreateAllButton, "RIGHT", 4, 0)
+
+ hooksecurefunc(TradeSkillCollapseAllButton, "SetNormalTexture", function(self, texture)
+ if find(texture, "MinusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Minus)
+ else
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Plus)
+ end
+ end)
+
+ hooksecurefunc("TradeSkillFrame_SetSelection", function(id)
+ if TradeSkillSkillIcon:GetNormalTexture() then
+ TradeSkillSkillIcon:SetAlpha(1)
+ TradeSkillSkillIcon:GetNormalTexture():SetTexCoord(unpack(E.TexCoords))
+ TradeSkillSkillIcon:GetNormalTexture():SetInside()
+ else
+ TradeSkillSkillIcon:SetAlpha(0)
+ end
+
+ local skillLink = GetTradeSkillItemLink(id)
+ local r, g, b
+
+ if skillLink then
+ local quality = select(3, GetItemInfo(skillLink))
+
+ if quality then
+ r, g, b = GetItemQualityColor(quality)
+
+ TradeSkillSkillIcon:SetBackdropBorderColor(r, g, b)
+ TradeSkillSkillName:SetTextColor(r, g, b)
+ else
+ TradeSkillSkillIcon:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ TradeSkillSkillName:SetTextColor(1, 1, 1)
+ end
+ end
+
+ for i = 1, GetTradeSkillNumReagents(id) do
+ local _, _, reagentCount, playerReagentCount = GetTradeSkillReagentInfo(id, i)
+ local reagentLink = GetTradeSkillReagentItemLink(id, i)
+
+ if reagentLink then
+ local reagent = _G["TradeSkillReagent"..i]
+ local icon = _G["TradeSkillReagent"..i.."IconTexture"]
+ local quality = select(3, GetItemInfo(reagentLink))
+
+ if quality then
+ local name = _G["TradeSkillReagent"..i.."Name"]
+ r, g, b = GetItemQualityColor(quality)
+
+ icon.backdrop:SetBackdropBorderColor(r, g, b)
+ reagent:SetBackdropBorderColor(r, g, b)
+
+ if playerReagentCount < reagentCount then
+ name:SetTextColor(0.5, 0.5, 0.5)
+ else
+ name:SetTextColor(r, g, b)
+ end
+ else
+ reagent:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ icon.backdrop:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+ end
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Trainer.lua b/ElvUI/Modules/Skins/Blizzard/Trainer.lua
new file mode 100644
index 0000000..2af1740
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Trainer.lua
@@ -0,0 +1,136 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+local find = string.find
+--WoW API / Variables
+local hooksecurefunc = hooksecurefunc
+
+S:AddCallbackForAddon("Blizzard_TrainerUI", "Skin_Blizzard_TrainerUI", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.trainer then return end
+
+ ClassTrainerFrame:StripTextures(true)
+ ClassTrainerFrame:CreateBackdrop("Transparent")
+ ClassTrainerFrame.backdrop:Point("TOPLEFT", 11, -12)
+ ClassTrainerFrame.backdrop:Point("BOTTOMRIGHT", -32, 76)
+
+ S:SetUIPanelWindowInfo(ClassTrainerFrame, "width")
+ S:SetBackdropHitRect(ClassTrainerFrame)
+
+ S:HandleCloseButton(ClassTrainerFrameCloseButton, ClassTrainerFrame.backdrop)
+
+ ClassTrainerListScrollFrame:StripTextures()
+
+ ClassTrainerDetailScrollFrame:StripTextures()
+ ClassTrainerDetailScrollFrame.scrollBarHideable = nil
+
+ ClassTrainerExpandButtonFrame:StripTextures()
+
+ ClassTrainerDetailScrollChildFrame:StripTextures()
+
+ S:HandleDropDownBox(ClassTrainerFrameFilterDropDown)
+
+ S:HandleScrollBar(ClassTrainerListScrollFrameScrollBar)
+ S:HandleScrollBar(ClassTrainerDetailScrollFrameScrollBar)
+
+ ClassTrainerSkillHighlight:SetTexture(E.Media.Textures.Highlight)
+ ClassTrainerSkillHighlight:SetAlpha(0.35)
+
+ ClassTrainerSkillIcon:StripTextures()
+ ClassTrainerSkillIcon:StyleButton(nil, true)
+
+ ClassTrainerCollapseAllButton:SetNormalTexture(E.Media.Textures.Plus)
+ ClassTrainerCollapseAllButton.SetNormalTexture = E.noop
+ ClassTrainerCollapseAllButton:GetNormalTexture():Point("LEFT", 3, 2)
+ ClassTrainerCollapseAllButton:GetNormalTexture():Size(16)
+
+ ClassTrainerCollapseAllButton:SetHighlightTexture("")
+ ClassTrainerCollapseAllButton.SetHighlightTexture = E.noop
+
+ ClassTrainerCollapseAllButton:SetDisabledTexture(E.Media.Textures.Plus)
+ ClassTrainerCollapseAllButton.SetDisabledTexture = E.noop
+ ClassTrainerCollapseAllButton:GetDisabledTexture():Point("LEFT", 3, 2)
+ ClassTrainerCollapseAllButton:GetDisabledTexture():Size(16)
+ ClassTrainerCollapseAllButton:GetDisabledTexture():SetDesaturated(true)
+
+ for i = 1, CLASS_TRAINER_SKILLS_DISPLAYED do
+ local skillButton = _G["ClassTrainerSkill"..i]
+ local highlight = _G["ClassTrainerSkill"..i.."Highlight"]
+
+ skillButton:SetNormalTexture(E.Media.Textures.Plus)
+ skillButton.SetNormalTexture = E.noop
+ skillButton:GetNormalTexture():Size(16)
+
+ highlight:SetTexture("")
+ highlight.SetTexture = E.noop
+
+ hooksecurefunc(skillButton, "SetNormalTexture", function(self, texture)
+ if find(texture, "MinusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Minus)
+ elseif find(texture, "PlusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Plus)
+ else
+ self:GetNormalTexture():SetTexture("")
+ end
+ end)
+ end
+
+ S:HandleButton(ClassTrainerCancelButton)
+ S:HandleButton(ClassTrainerTrainButton)
+
+ ClassTrainerGreetingText:Width(317)
+ ClassTrainerGreetingText:Point("TOPLEFT", 22, -35)
+ ClassTrainerGreetingText:SetJustifyH("CENTER")
+
+ ClassTrainerCollapseAllButton:Point("LEFT", ClassTrainerExpandTabLeft, "RIGHT", -1, 5)
+
+ ClassTrainerFrameFilterDropDown:Point("TOPRIGHT", -32, -60)
+
+ ClassTrainerSkill1:Point("TOPLEFT", 22, -91)
+
+ ClassTrainerListScrollFrame:Size(304, 164)
+ ClassTrainerListScrollFrame.SetHeight = E.noop
+ ClassTrainerListScrollFrame:Point("TOPRIGHT", -61, -88)
+
+ ClassTrainerListScrollFrameScrollBar:Point("TOPLEFT", ClassTrainerListScrollFrame, "TOPRIGHT", 3, -19)
+ ClassTrainerListScrollFrameScrollBar:Point("BOTTOMLEFT", ClassTrainerListScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ ClassTrainerDetailScrollFrame:Size(304, 140)
+ ClassTrainerDetailScrollFrame.SetHeight = E.noop
+ ClassTrainerDetailScrollFrame:Point("TOPLEFT", ClassTrainerListScrollFrame, "BOTTOMLEFT", 0, -7)
+
+ ClassTrainerDetailScrollChildFrame:Width(304)
+ ClassTrainerSkillName:Width(300)
+
+ ClassTrainerDetailScrollFrameScrollBar:Point("TOPLEFT", ClassTrainerDetailScrollFrame, "TOPRIGHT", 3, -19)
+ ClassTrainerDetailScrollFrameScrollBar:Point("BOTTOMLEFT", ClassTrainerDetailScrollFrame, "BOTTOMRIGHT", 3, 19)
+
+ ClassTrainerMoneyFrame:Point("BOTTOMRIGHT", ClassTrainerFrame, "BOTTOMLEFT", 180, 88)
+
+ ClassTrainerCancelButton:Point("CENTER", ClassTrainerFrame, "TOPLEFT", 304, -417)
+ ClassTrainerTrainButton:Point("CENTER", ClassTrainerFrame, "TOPLEFT", 221, -417)
+
+ hooksecurefunc("ClassTrainer_SetToClassTrainer", function()
+ CLASS_TRAINER_SKILLS_DISPLAYED = 10
+ end)
+
+ hooksecurefunc(ClassTrainerCollapseAllButton, "SetNormalTexture", function(self, texture)
+ if find(texture, "MinusButton") then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Minus)
+ else
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Plus)
+ end
+ end)
+
+ hooksecurefunc("ClassTrainer_SetSelection", function()
+ local skillIcon = ClassTrainerSkillIcon:GetNormalTexture()
+ if skillIcon then
+ skillIcon:SetInside()
+ skillIcon:SetTexCoord(unpack(E.TexCoords))
+
+ ClassTrainerSkillIcon:SetTemplate("Default")
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Tutorial.lua b/ElvUI/Modules/Skins/Blizzard/Tutorial.lua
new file mode 100644
index 0000000..7a99934
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Tutorial.lua
@@ -0,0 +1,44 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallback("Skin_Tutorial", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.tutorial then return end
+
+ TutorialFrameAlertButton:StripTextures()
+ TutorialFrameAlertButton:CreateBackdrop("Default", true)
+ TutorialFrameAlertButton:Size(50)
+
+ local TutorialFrameAlertButtonIcon = TutorialFrameAlertButton:GetNormalTexture()
+ TutorialFrameAlertButtonIcon:SetTexture("INTERFACE\\ICONS\\INV_Letter_18")
+ TutorialFrameAlertButtonIcon:Point("TOPLEFT", 5, -5)
+ TutorialFrameAlertButtonIcon:Point("BOTTOMRIGHT", -5, 5)
+ TutorialFrameAlertButtonIcon:SetTexCoord(unpack(E.TexCoords))
+
+ TutorialFrameBackground:Hide()
+-- TutorialFrameTop:Hide()
+-- TutorialFrameBottom:Hide()
+ TutorialFrame:DisableDrawLayer("BORDER")
+
+ TutorialFrame:CreateBackdrop("Transparent")
+ TutorialFrame.backdrop:Point("TOPLEFT", 11, -12)
+ TutorialFrame.backdrop:Point("BOTTOMRIGHT", -1, 2)
+
+ TutorialFrameTitle:Point("TOP", 0, -19)
+
+ S:HandleCloseButton((select(4, TutorialFrame:GetChildren())), TutorialFrame.backdrop)
+
+ S:HandleNextPrevButton(TutorialFrameNextButton)
+ TutorialFrameNextButton:Point("BOTTOMRIGHT", -132, 7)
+ TutorialFrameNextButton:Size(22)
+
+ S:HandleNextPrevButton(TutorialFramePrevButton)
+ TutorialFramePrevButton:Point("BOTTOMLEFT", 30, 7)
+ TutorialFramePrevButton:Size(22)
+
+ S:HandleButton(TutorialFrameOkayButton)
+
+ TutorialFrameCallOut:Kill()
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/WatchFrame.lua b/ElvUI/Modules/Skins/Blizzard/WatchFrame.lua
new file mode 100644
index 0000000..6705beb
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/WatchFrame.lua
@@ -0,0 +1,157 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack = unpack
+local format = string.format
+--WoW API / Variables
+local GetNumQuestWatches = GetNumQuestWatches
+local GetQuestDifficultyColor = GetQuestDifficultyColor
+local GetQuestIndexForWatch = GetQuestIndexForWatch
+local GetQuestLogTitle = GetQuestLogTitle
+local hooksecurefunc = hooksecurefunc
+
+S:AddCallback("Skin_WatchFrame", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.watchframe then return end
+
+ -- WatchFrame Expand/Collapse Button
+ WatchFrameCollapseExpandButton:StripTextures()
+ WatchFrameCollapseExpandButton:Size(18)
+ WatchFrameCollapseExpandButton.tex = WatchFrameCollapseExpandButton:CreateTexture(nil, "OVERLAY")
+ WatchFrameCollapseExpandButton.tex:SetTexture(E.Media.Textures.MinusButton)
+ WatchFrameCollapseExpandButton.tex:SetInside()
+ WatchFrameCollapseExpandButton:SetHighlightTexture("Interface\\Buttons\\UI-PlusButton-Hilight", "ADD")
+ WatchFrameCollapseExpandButton:SetFrameStrata("MEDIUM")
+ WatchFrameCollapseExpandButton:Point("TOPRIGHT", 0, -2)
+
+ hooksecurefunc("WatchFrame_Expand", function()
+ WatchFrameCollapseExpandButton.tex:SetTexture(E.Media.Textures.MinusButton)
+ WatchFrame:Width(WATCHFRAME_EXPANDEDWIDTH)
+ end)
+
+ hooksecurefunc("WatchFrame_Collapse", function()
+ WatchFrameCollapseExpandButton.tex:SetTexture(E.Media.Textures.PlusButton)
+ WatchFrame:Width(WATCHFRAME_EXPANDEDWIDTH)
+ end)
+
+ -- WatchFrame Text
+ hooksecurefunc("WatchFrame_Update", function()
+ local questIndex, title, level, color
+
+ for i = 1, GetNumQuestWatches() do
+ questIndex = GetQuestIndexForWatch(i)
+ if questIndex then
+ title, level = GetQuestLogTitle(questIndex)
+ color = GetQuestDifficultyColor(level)
+
+ for j = 1, #WATCHFRAME_QUESTLINES do
+ if WATCHFRAME_QUESTLINES[j].text:GetText() == title then
+ WATCHFRAME_QUESTLINES[j].text:SetTextColor(color.r, color.g, color.b)
+ WATCHFRAME_QUESTLINES[j].color = color
+ end
+ end
+ end
+ end
+
+ for i = 1, #WATCHFRAME_ACHIEVEMENTLINES do
+ WATCHFRAME_ACHIEVEMENTLINES[i].color = nil
+ end
+
+ -- WatchFrame Items
+ for i = 1, WATCHFRAME_NUM_ITEMS do
+ local button = _G["WatchFrameItem"..i]
+
+ if button and not button.isSkinned then
+ local icon = _G["WatchFrameItem"..i.."IconTexture"]
+ local normal = _G["WatchFrameItem"..i.."NormalTexture"]
+ local cooldown = _G["WatchFrameItem"..i.."Cooldown"]
+
+ button:CreateBackdrop()
+ button.backdrop:SetAllPoints()
+ button:StyleButton()
+ button:Size(25)
+
+ normal:SetAlpha(0)
+
+ icon:SetInside()
+ icon:SetTexCoord(unpack(E.TexCoords))
+
+ E:RegisterCooldown(cooldown)
+
+ button.isSkinned = true
+ end
+ end
+ end)
+
+ -- WatchFrame Highlight
+ hooksecurefunc("WatchFrameLinkButtonTemplate_Highlight", function(self, onEnter)
+ local line
+
+ for index = self.startLine, self.lastLine do
+ line = self.lines[index]
+
+ if line then
+ if index == self.startLine then
+ if onEnter then
+ line.text:SetTextColor(1, 0.80, 0.10)
+ else
+ if line.color then
+ line.text:SetTextColor(line.color.r, line.color.g, line.color.b)
+ else
+ line.text:SetTextColor(0.75, 0.61, 0)
+ end
+ end
+ end
+ end
+ end
+ end)
+
+ -- WatchFrame POI Buttons
+ local function poi_OnEnter(self)
+ self.bg:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
+ end
+
+ local function poi_OnLeave(self)
+ self.bg:SetBackdropBorderColor(unpack(E.media.bordercolor))
+ end
+
+ hooksecurefunc("QuestPOI_DisplayButton", function(parentName, buttonType, buttonIndex)
+ local poiButton = _G[format("poi%s%s_%d", parentName, buttonType, buttonIndex)]
+
+ if poiButton and parentName == "WatchFrameLines" then
+ if not poiButton.isSkinned then
+ poiButton.normalTexture:SetTexture("")
+ poiButton.pushedTexture:SetTexture("")
+ poiButton.highlightTexture:SetTexture("")
+ poiButton.selectionGlow:SetTexture("")
+
+ poiButton:SetScale(1)
+ poiButton:SetHitRectInsets(6, 6, 6, 6)
+
+ poiButton.bg = CreateFrame("Frame", nil, poiButton)
+ poiButton.bg:SetTemplate("Default", true)
+ poiButton.bg:Point("TOPLEFT", 6, -6)
+ poiButton.bg:Point("BOTTOMRIGHT", -6, 6)
+ poiButton.bg:SetFrameLevel(poiButton.bg:GetFrameLevel() - 1)
+
+ poiButton:HookScript("OnEnter", poi_OnEnter)
+ poiButton:HookScript("OnLeave", poi_OnLeave)
+
+ poiButton.isSkinned = true
+ end
+ end
+ end)
+
+ hooksecurefunc("QuestPOI_SelectButton", function(poiButton)
+ if poiButton and poiButton.bg then
+ poiButton.bg:SetBackdropColor(unpack(E.media.rgbvaluecolor))
+ end
+ end)
+
+ hooksecurefunc("QuestPOI_DeselectButton", function(poiButton)
+ if poiButton and poiButton.bg then
+ poiButton.bg:SetBackdropColor(unpack(E.media.backdropcolor))
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/WorldStateFrame.lua b/ElvUI/Modules/Skins/Blizzard/WorldStateFrame.lua
new file mode 100644
index 0000000..fd1a2ad
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/WorldStateFrame.lua
@@ -0,0 +1,84 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+
+S:AddCallback("Skin_WorldStateFrame", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.WorldStateFrame then return end
+
+ local function captureBarCreate(id)
+ local bar = _G["WorldStateCaptureBar"..id]
+ local leftBar = _G["WorldStateCaptureBar"..id.."LeftBar"]
+ local rightBar = _G["WorldStateCaptureBar"..id.."RightBar"]
+ local middleBar = _G["WorldStateCaptureBar"..id.."MiddleBar"]
+
+ select(4, bar:GetRegions()):SetTexture(nil)
+
+ _G["WorldStateCaptureBar"..id.."LeftLine"]:SetTexture(nil)
+ _G["WorldStateCaptureBar"..id.."RightLine"]:SetTexture(nil)
+
+ _G["WorldStateCaptureBar"..id.."LeftIconHighlight"]:SetTexture(nil)
+ _G["WorldStateCaptureBar"..id.."RightIconHighlight"]:SetTexture(nil)
+
+ _G["WorldStateCaptureBar"..id.."Indicator"]:StripTextures()
+
+ bar:Size(173, 16)
+ bar:CreateBackdrop("Default")
+
+ leftBar:Size(85, 16)
+ leftBar:SetPoint("LEFT", 0, 0)
+ leftBar:SetTexture(E.media.glossTex)
+ leftBar:SetTexCoord(1, 0, 1, 0)
+ leftBar:SetVertexColor(0, .44, .87)
+
+ bar.leftBarIcon = bar:CreateTexture("$parentLeftBarIcon", "ARTWORK")
+ bar.leftBarIcon:SetTexture("Interface\\AddOns\\ElvUI\\Media\\Textures\\Alliance-Logo-Small")
+ bar.leftBarIcon:SetPoint("RIGHT", bar, "LEFT", 0, 0)
+ bar.leftBarIcon:SetSize(32, 32)
+
+ rightBar:Size(85, 16)
+ rightBar:SetPoint("RIGHT", 0, 0)
+ rightBar:SetTexture(E.media.glossTex)
+ rightBar:SetTexCoord(1, 0, 1, 0)
+ rightBar:SetVertexColor(.77, .12, .23)
+
+ bar.rightBarIcon = bar:CreateTexture("$parentRightBarIcon", "ARTWORK")
+ bar.rightBarIcon:SetTexture("Interface\\AddOns\\ElvUI\\Media\\Textures\\Horde-Logo-Small")
+ bar.rightBarIcon:SetPoint("LEFT", bar, "RIGHT", 0, 0)
+ bar.rightBarIcon:Size(32, 32)
+
+ middleBar:Size(25, 16)
+ middleBar:SetTexture(E.media.glossTex)
+ middleBar:SetTexCoord(1, 0, 1, 0)
+ middleBar:SetVertexColor(1, 1, 1)
+
+ bar.spark = CreateFrame("Frame", "$parentSpark", bar)
+ bar.spark:SetTemplate("Default", true)
+ bar.spark:Size(4, 18)
+ end
+
+ hooksecurefunc(ExtendedUI["CAPTUREPOINT"], "create", captureBarCreate)
+
+ hooksecurefunc(ExtendedUI["CAPTUREPOINT"], "update", function(id, value, neutralPercent)
+ local bar = _G["WorldStateCaptureBar"..id]
+ local middleBar = _G["WorldStateCaptureBar"..id.."MiddleBar"]
+
+ local barSize = 170
+ local position = 173 * (1 - value / 100)
+
+ if neutralPercent == 0 then
+ middleBar:Width(1)
+ else
+ middleBar:Width(neutralPercent / 100 * barSize)
+ end
+
+ bar.oldValue = position
+
+ if bar.spark then
+ bar.spark:Point("CENTER", bar, "LEFT", position, 0)
+ else
+ captureBarCreate(id)
+ end
+ end)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Blizzard/Worldmap.lua b/ElvUI/Modules/Skins/Blizzard/Worldmap.lua
new file mode 100644
index 0000000..0373999
--- /dev/null
+++ b/ElvUI/Modules/Skins/Blizzard/Worldmap.lua
@@ -0,0 +1,198 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+--WoW API / Variables
+
+S:AddCallback("Skin_WorldMap", function()
+ if not E.private.skins.blizzard.enable or not E.private.skins.blizzard.worldmap then return end
+
+ WorldMapFrame:DisableDrawLayer("BACKGROUND")
+ WorldMapFrame:DisableDrawLayer("ARTWORK")
+ WorldMapFrame:DisableDrawLayer("OVERLAY")
+ WorldMapFrame:CreateBackdrop("Transparent")
+ WorldMapFrame.backdrop:Point("TOPRIGHT", WorldMapFrameCloseButton, -3, 0)
+ WorldMapFrame.backdrop:Point("BOTTOMRIGHT", WorldMapTrackQuest, 0, -3)
+ WorldMapFrame:SetClampRectInsets(3, 0, 2, 1)
+
+ WorldMapFrameTitle:SetDrawLayer("BORDER")
+
+ WorldMapTitleButton:Width(530)
+ WorldMapTitleButton:Point("TOPLEFT", WorldMapFrameMiniBorderLeft, "TOPLEFT", 4, 1)
+
+ WorldMapDetailFrame:CreateBackdrop()
+ WorldMapDetailFrame.backdrop:Point("TOPLEFT", -2, 2)
+ WorldMapDetailFrame.backdrop:Point("BOTTOMRIGHT", 2, -1)
+
+ WorldMapQuestDetailScrollFrame:Width(348)
+ WorldMapQuestDetailScrollFrame:Point("BOTTOMLEFT", WorldMapDetailFrame, "BOTTOMLEFT", -25, -207)
+ WorldMapQuestDetailScrollFrame:CreateBackdrop("Transparent")
+ WorldMapQuestDetailScrollFrame.backdrop:Point("TOPLEFT", 24, 2)
+ WorldMapQuestDetailScrollFrame.backdrop:Point("BOTTOMRIGHT", 23, -4)
+ WorldMapQuestDetailScrollFrame.backdrop:SetFrameLevel(WorldMapQuestDetailScrollFrame:GetFrameLevel())
+ WorldMapQuestDetailScrollFrame:SetHitRectInsets(24, -23, 0, -2)
+
+ WorldMapQuestDetailScrollChildFrame:SetScale(1)
+
+ WorldMapQuestDetailScrollFrameTrack:Kill()
+
+ WorldMapQuestRewardScrollFrame:Width(340)
+ WorldMapQuestRewardScrollFrame:Point("LEFT", WorldMapQuestDetailScrollFrame, "RIGHT", 8, 0)
+ WorldMapQuestRewardScrollFrame:CreateBackdrop("Transparent")
+ WorldMapQuestRewardScrollFrame.backdrop:Point("TOPLEFT", 20, 2)
+ WorldMapQuestRewardScrollFrame.backdrop:Point("BOTTOMRIGHT", 22, -4)
+ WorldMapQuestRewardScrollFrame.backdrop:SetFrameLevel(WorldMapQuestRewardScrollFrame:GetFrameLevel())
+ WorldMapQuestRewardScrollFrame:SetHitRectInsets(20, -22, 0, -2)
+
+ WorldMapQuestRewardScrollChildFrame:SetScale(1)
+
+ WorldMapQuestRewardScrollFrameTrack:SetTexture()
+
+ WorldMapQuestScrollFrame:Point("TOPLEFT", WorldMapDetailFrame, "TOPRIGHT", 6, -1)
+ WorldMapQuestScrollFrame:CreateBackdrop("Transparent")
+ WorldMapQuestScrollFrame.backdrop:Point("TOPLEFT", 0, 2)
+ WorldMapQuestScrollFrame.backdrop:Point("BOTTOMRIGHT", 25, -1)
+ WorldMapQuestScrollFrame.backdrop:SetFrameLevel(WorldMapQuestScrollFrame:GetFrameLevel())
+
+ WorldMapQuestSelectBar:SetTexture(E.Media.Textures.Highlight)
+ WorldMapQuestSelectBar:SetAlpha(0.35)
+
+ WorldMapQuestHighlightBar:SetTexture(E.Media.Textures.Highlight)
+ WorldMapQuestHighlightBar:SetAlpha(0.35)
+
+ S:HandleScrollBar(WorldMapQuestScrollFrameScrollBar)
+ S:HandleScrollBar(WorldMapQuestDetailScrollFrameScrollBar)
+ S:HandleScrollBar(WorldMapQuestRewardScrollFrameScrollBar)
+
+ WorldMapQuestScrollFrameScrollBar:Point("TOPLEFT", WorldMapQuestScrollFrame, "TOPRIGHT", 5, -19)
+ WorldMapQuestScrollFrameScrollBar:Point("BOTTOMLEFT", WorldMapQuestScrollFrame, "BOTTOMRIGHT", 5, 20)
+
+ WorldMapQuestDetailScrollFrameScrollBar:Point("TOPLEFT", WorldMapQuestDetailScrollFrame, "TOPRIGHT", 3, -19)
+ WorldMapQuestDetailScrollFrameScrollBar:Point("BOTTOMLEFT", WorldMapQuestDetailScrollFrame, "BOTTOMRIGHT", 3, 17)
+
+ WorldMapQuestRewardScrollFrameScrollBar:Point("TOPLEFT", WorldMapQuestRewardScrollFrame, "TOPRIGHT", 2, -19)
+ WorldMapQuestRewardScrollFrameScrollBar:Point("BOTTOMLEFT", WorldMapQuestRewardScrollFrame, "BOTTOMRIGHT", 2, 17)
+
+ S:HandleCloseButton(WorldMapFrameCloseButton)
+
+ WorldMapFrameSizeDownButton:ClearAllPoints()
+ WorldMapFrameSizeDownButton:Point("RIGHT", WorldMapFrameCloseButton, "LEFT", 4, 0)
+ WorldMapFrameSizeDownButton.SetPoint = E.noop
+ WorldMapFrameSizeDownButton:GetHighlightTexture():Kill()
+ S:HandleNextPrevButton(WorldMapFrameSizeDownButton, "down", nil, true)
+ WorldMapFrameSizeDownButton:Size(26)
+
+ WorldMapFrameSizeUpButton:ClearAllPoints()
+ WorldMapFrameSizeUpButton:Point("RIGHT", WorldMapFrameCloseButton, "LEFT", 4, 0)
+ WorldMapFrameSizeUpButton:GetHighlightTexture():Kill()
+ S:HandleNextPrevButton(WorldMapFrameSizeUpButton, "up", nil, true)
+ WorldMapFrameSizeUpButton:Size(26)
+
+ S:HandleDropDownBox(WorldMapLevelDropDown)
+ S:HandleDropDownBox(WorldMapZoneMinimapDropDown)
+ S:HandleDropDownBox(WorldMapContinentDropDown)
+ S:HandleDropDownBox(WorldMapZoneDropDown)
+
+ WorldMapLevelUpButton:Point("TOPLEFT", WorldMapLevelDropDown, "TOPRIGHT", -6, 4)
+ WorldMapLevelDownButton:Point("BOTTOMLEFT", WorldMapLevelDropDown, "BOTTOMRIGHT", -6, 0)
+
+ S:HandleButton(WorldMapZoomOutButton)
+ WorldMapZoomOutButton:Point("LEFT", WorldMapZoneDropDown, "RIGHT", 0, 3)
+
+ S:HandleCheckBox(WorldMapTrackQuest)
+ S:HandleCheckBox(WorldMapQuestShowObjectives)
+
+ WorldMapFrameAreaLabel:FontTemplate(nil, 50, "OUTLINE")
+ WorldMapFrameAreaLabel:SetShadowOffset(2, -2)
+ WorldMapFrameAreaLabel:SetTextColor(0.90, 0.8294, 0.6407)
+
+ WorldMapFrameAreaDescription:FontTemplate(nil, 40, "OUTLINE")
+ WorldMapFrameAreaDescription:SetShadowOffset(2, -2)
+
+ WorldMapZoneInfo:FontTemplate(nil, 27, "OUTLINE")
+ WorldMapZoneInfo:SetShadowOffset(2, -2)
+
+ WorldMapLevelDropDown.SetPoint = E.noop
+
+ local setPoint = UIParent.SetPoint
+ local currentMapMode
+
+ local function SmallSkin()
+ if WORLDMAP_SETTINGS.advanced then
+ if currentMapMode == 0 then return end
+ currentMapMode = 0
+
+ WorldMapFrame.backdrop:Point("TOPLEFT", 3, 2)
+ WorldMapFrame.backdrop:Point("TOPRIGHT", WorldMapFrameCloseButton, -3, 0)
+
+ WorldMapDetailFrame.backdrop:Point("TOPLEFT", -2, 2)
+ WorldMapDetailFrame.backdrop:Point("BOTTOMRIGHT", 1, -1)
+
+ setPoint(WorldMapLevelDropDown, "TOPRIGHT", WorldMapPositioningGuide, "TOPRIGHT", -419, -24)
+ else
+ if currentMapMode == 1 then return end
+ currentMapMode = 1
+
+ WorldMapFrame.backdrop:Point("TOPLEFT", 11, -12)
+ WorldMapFrame.backdrop:Point("TOPRIGHT", WorldMapFrameCloseButton, -1, 0)
+
+ WorldMapDetailFrame.backdrop:Point("TOPLEFT", -2, 2)
+ WorldMapDetailFrame.backdrop:Point("BOTTOMRIGHT", 2, -1)
+
+ setPoint(WorldMapLevelDropDown, "TOPRIGHT", WorldMapPositioningGuide, "TOPRIGHT", -439, -38)
+ end
+ end
+
+ local function LargeSkin()
+ if currentMapMode == 2 then return end
+ currentMapMode = 2
+
+ WorldMapFrame.backdrop:Point("TOPLEFT", WorldMapDetailFrame, "TOPLEFT", -8, 70)
+ WorldMapFrame.backdrop:Point("TOPRIGHT", WorldMapFrameCloseButton, -3, 0)
+
+ WorldMapDetailFrame.backdrop:Point("TOPLEFT", -1, 1)
+ WorldMapDetailFrame.backdrop:Point("BOTTOMRIGHT", 1, -1)
+
+ setPoint(WorldMapLevelDropDown, "TOPRIGHT", WorldMapPositioningGuide, "TOPRIGHT", -50, -35)
+ end
+
+ local function QuestSkin()
+ if currentMapMode == 3 then return end
+ currentMapMode = 3
+
+ WorldMapFrame.backdrop:Point("TOPLEFT", WorldMapDetailFrame, "TOPLEFT", -9, 70)
+ WorldMapFrame.backdrop:Point("TOPRIGHT", WorldMapFrameCloseButton, -3, 0)
+
+ WorldMapDetailFrame.backdrop:Point("TOPLEFT", -1, 1)
+ WorldMapDetailFrame.backdrop:Point("BOTTOMRIGHT", 1, -1)
+
+ setPoint(WorldMapLevelDropDown, "TOPRIGHT", WorldMapPositioningGuide, "TOPRIGHT", -50, -35)
+ end
+
+ local function FixSkin()
+ if WORLDMAP_SETTINGS.size == WORLDMAP_FULLMAP_SIZE then
+ LargeSkin()
+ elseif WORLDMAP_SETTINGS.size == WORLDMAP_WINDOWED_SIZE then
+ SmallSkin()
+ elseif WORLDMAP_SETTINGS.size == WORLDMAP_QUESTLIST_SIZE then
+ QuestSkin()
+ end
+ end
+
+ if not E.private.worldmap.enable then
+ WorldMapFrame:EnableMouse(false)
+ WorldMapFrame.EnableMouse = E.noop
+ end
+
+ WorldMapTitleButton:Hide()
+ WorldMapFrame.backdrop:EnableMouse(true)
+
+ FixSkin()
+ S:SetUIPanelWindowInfo(WorldMapFrame, "width", 594)
+
+ hooksecurefunc("WorldMapFrame_SetQuestMapView", QuestSkin)
+ hooksecurefunc("WorldMapFrame_SetFullMapView", LargeSkin)
+ hooksecurefunc("WorldMapFrame_SetMiniMode", SmallSkin)
+ hooksecurefunc("ToggleMapFramerate", FixSkin)
+ hooksecurefunc("WorldMapFrame_ToggleAdvanced", FixSkin)
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Load_Skins.xml b/ElvUI/Modules/Skins/Load_Skins.xml
new file mode 100644
index 0000000..21ca4aa
--- /dev/null
+++ b/ElvUI/Modules/Skins/Load_Skins.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/Skins/Skins.lua b/ElvUI/Modules/Skins/Skins.lua
new file mode 100644
index 0000000..6400f60
--- /dev/null
+++ b/ElvUI/Modules/Skins/Skins.lua
@@ -0,0 +1,1011 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local S = E:GetModule("Skins")
+
+--Lua functions
+local _G = _G
+local unpack, pairs, ipairs, select, type = unpack, pairs, ipairs, select, type
+local floor = math.floor
+local find, format, lower = string.find, string.format, string.lower
+--WoW API / Variables
+local IsAddOnLoaded = IsAddOnLoaded
+local UIPanelWindows = UIPanelWindows
+local UpdateUIPanelPositions = UpdateUIPanelPositions
+local hooksecurefunc = hooksecurefunc
+
+S.allowBypass = {}
+S.addonCallbacks = {}
+S.nonAddonCallbacks = {["CallPriority"] = {}}
+
+S.ArrowRotation = {
+ ["up"] = 0,
+ ["down"] = 3.14,
+ ["left"] = 1.57,
+ ["right"] = -1.57,
+}
+
+function S:SetModifiedBackdrop()
+ if self.backdrop then self = self.backdrop end
+ self:SetBackdropBorderColor(unpack(E.media.rgbvaluecolor))
+end
+
+function S:SetOriginalBackdrop()
+ if self.backdrop then self = self.backdrop end
+ self:SetBackdropBorderColor(unpack(E.media.bordercolor))
+end
+
+function S:StatusBarColorGradient(bar, value, max, backdrop)
+ local current = (not max and value) or (value and max and max ~= 0 and value/max)
+ if not (bar and current) then return end
+ local r, g, b = E:ColorGradient(current, 0.8,0,0, 0.8,0.8,0, 0,0.8,0)
+ local bg = backdrop or bar.backdrop
+ if bg then bg:SetBackdropColor(r*0.25, g*0.25, b*0.25) end
+ bar:SetStatusBarColor(r, g, b)
+end
+
+function S:HandleButton(button, strip, isDeclineButton, useCreateBackdrop, noSetTemplate)
+ if button.isSkinned then return end
+
+ local buttonName = button.GetName and button:GetName()
+ if buttonName then
+ local left = _G[buttonName.."Left"]
+ local middle = _G[buttonName.."Middle"]
+ local right = _G[buttonName.."Right"]
+
+ if left then left:SetAlpha(0) end
+ if middle then middle:SetAlpha(0) end
+ if right then right:SetAlpha(0) end
+ end
+
+ if button.Left then button.Left:SetAlpha(0) end
+ if button.Middle then button.Middle:SetAlpha(0) end
+ if button.Right then button.Right:SetAlpha(0) end
+
+ if button.SetNormalTexture then button:SetNormalTexture("") end
+ if button.SetHighlightTexture then button:SetHighlightTexture("") end
+ if button.SetPushedTexture then button:SetPushedTexture("") end
+ if button.SetDisabledTexture then button:SetDisabledTexture("") end
+
+ if strip then button:StripTextures() end
+
+ if useCreateBackdrop then
+ button:CreateBackdrop(nil, true)
+ elseif not noSetTemplate then
+ button:SetTemplate(nil, true)
+ end
+
+ button:HookScript("OnEnter", S.SetModifiedBackdrop)
+ button:HookScript("OnLeave", S.SetOriginalBackdrop)
+
+ button.isSkinned = true
+end
+
+function S:HandleButtonHighlight(frame, r, g, b, a)
+ if not r then r = 0.9 end
+ if not g then g = 0.9 end
+ if not b then b = 0.9 end
+ if not a then a = 0.35 end
+
+ local highlightTexture
+
+ if frame.SetHighlightTexture then
+ highlightTexture = frame:GetHighlightTexture()
+ highlightTexture:SetAllPoints(frame)
+ elseif frame.SetTexture then
+ highlightTexture = frame
+ frame:SetAllPoints(frame:GetParent())
+ elseif frame.HighlightTexture then
+ highlightTexture = frame.HighlightTexture
+ else
+ highlightTexture = frame:CreateTexture(nil, "HIGHLIGHT")
+ highlightTexture:SetAllPoints(frame)
+ frame.HighlightTexture = highlightTexture
+ end
+
+ highlightTexture:SetTexture(E.Media.Textures.Highlight)
+ highlightTexture:SetVertexColor(r, g, b, a)
+end
+
+function S:HandleScrollBar(frame, horizontal)
+ if frame.backdrop then return end
+
+ local parent = frame:GetParent()
+ local frameName = frame:GetName()
+
+ local scrollUpButton, scrollDownButton
+ local thumb = frame.thumbTexture or frame.GetThumbTexture and frame:GetThumbTexture() or _G[format("%s%s", frameName, "ThumbTexture")]
+ if frameName ~= nil then
+ if not horizontal then
+ scrollUpButton = parent.scrollUp or _G[format("%s%s", frameName, "ScrollUpButton")] or _G[format("%s%s", frameName, "UpButton")] or _G[format("%s%s", frameName, "ScrollUp")]
+ scrollDownButton = parent.scrollDown or _G[format("%s%s", frameName, "ScrollDownButton")] or _G[format("%s%s", frameName, "DownButton")] or _G[format("%s%s", frameName, "ScrollDown")]
+ else
+ scrollUpButton = _G[format("%s%s", frameName, "ScrollLeftButton")] or _G[format("%s%s", frameName, "LeftButton")] or _G[format("%s%s", frameName, "ScrollLeft")]
+ scrollDownButton = _G[format("%s%s", frameName, "ScrollRightButton")] or _G[format("%s%s", frameName, "RightButton")] or _G[format("%s%s", frameName, "ScrollRight")]
+ end
+ end
+
+ if not horizontal then
+ frame:Width(18)
+ else
+ frame:Height(18)
+ end
+
+ local frameLevel = frame:GetFrameLevel()
+ frame:StripTextures()
+ frame:CreateBackdrop()
+ frame.backdrop:SetAllPoints()
+ frame.backdrop:SetFrameLevel(frameLevel)
+
+ if scrollUpButton then
+ if not horizontal then
+ scrollUpButton:Point("BOTTOM", frame, "TOP", 0, 1)
+ S:HandleNextPrevButton(scrollUpButton, "up")
+ else
+ scrollUpButton:Point("RIGHT", frame, "LEFT", -1, 0)
+ S:HandleNextPrevButton(scrollUpButton, "left")
+ end
+ end
+
+ if scrollDownButton then
+ if not horizontal then
+ scrollDownButton:Point("TOP", frame, "BOTTOM", 0, -1)
+ S:HandleNextPrevButton(scrollDownButton, "down")
+ else
+ scrollDownButton:Point("LEFT", frame, "RIGHT", 1, 0)
+ S:HandleNextPrevButton(scrollDownButton, "right")
+ end
+ end
+
+ if thumb and not thumb.backdrop then
+ if not horizontal then
+ thumb:Size(18, 22)
+ else
+ thumb:Size(22, 18)
+ end
+
+ thumb:SetTexture()
+ thumb:CreateBackdrop(nil, true, true)
+ thumb.backdrop:SetFrameLevel(frameLevel + 1)
+ thumb.backdrop:SetBackdropColor(0.6, 0.6, 0.6)
+
+ thumb.backdrop:Point("TOPLEFT", thumb, "TOPLEFT", 2, -2)
+ thumb.backdrop:Point("BOTTOMRIGHT", thumb, "BOTTOMRIGHT", -2, 2)
+
+ if not frame.thumbTexture then
+ frame.thumbTexture = thumb
+ end
+ end
+end
+
+local tabs = {
+ "LeftDisabled",
+ "MiddleDisabled",
+ "RightDisabled",
+ "Left",
+ "Middle",
+ "Right"
+}
+
+function S:HandleTab(tab, noBackdrop)
+ if (not tab) or (tab.backdrop and not noBackdrop) then return end
+
+ for _, object in ipairs(tabs) do
+ local tex = _G[tab:GetName()..object]
+ if tex then
+ tex:SetTexture()
+ end
+ end
+
+ local highlightTex = tab.GetHighlightTexture and tab:GetHighlightTexture()
+ if highlightTex then
+ highlightTex:SetTexture()
+ else
+ tab:StripTextures()
+ end
+
+ if not noBackdrop then
+ tab:CreateBackdrop()
+ tab.backdrop:Point("TOPLEFT", 10, E.PixelMode and -1 or -3)
+ tab.backdrop:Point("BOTTOMRIGHT", -10, 3)
+
+ tab:SetHitRectInsets(10, 10, E.PixelMode and 1 or 3, 3)
+ end
+end
+
+function S:HandleRotateButton(btn)
+ if btn.isSkinned then return end
+
+ btn:SetTemplate()
+ btn:Size(btn:GetWidth() - 14, btn:GetHeight() - 14)
+
+ local normTex = btn:GetNormalTexture()
+ local pushTex = btn:GetPushedTexture()
+ local highlightTex = btn:GetHighlightTexture()
+
+ normTex:SetInside()
+ normTex:SetTexCoord(0.3, 0.29, 0.3, 0.65, 0.69, 0.29, 0.69, 0.65)
+
+ pushTex:SetAllPoints(normTex)
+ pushTex:SetTexCoord(0.3, 0.29, 0.3, 0.65, 0.69, 0.29, 0.69, 0.65)
+
+ highlightTex:SetAllPoints(normTex)
+ highlightTex:SetTexture(1, 1, 1, 0.3)
+
+ btn.isSkinned = true
+end
+
+function S:HandleEditBox(frame)
+ if frame.backdrop then return end
+
+ frame:CreateBackdrop()
+ frame.backdrop:SetFrameLevel(frame:GetFrameLevel())
+
+ local EditBoxName = frame.GetName and frame:GetName()
+ if EditBoxName then
+ if _G[EditBoxName.."Left"] then _G[EditBoxName.."Left"]:SetAlpha(0) end
+ if _G[EditBoxName.."Middle"] then _G[EditBoxName.."Middle"]:SetAlpha(0) end
+ if _G[EditBoxName.."Right"] then _G[EditBoxName.."Right"]:SetAlpha(0) end
+ if _G[EditBoxName.."Mid"] then _G[EditBoxName.."Mid"]:SetAlpha(0) end
+
+ if find(EditBoxName, "Silver") or find(EditBoxName, "Copper") then
+ frame.backdrop:Point("BOTTOMRIGHT", -12, -2)
+ end
+ end
+end
+
+function S:HandleDropDownBox(frame, width, direction)
+ if frame.backdrop then return end
+
+ local FrameName = frame.GetName and frame:GetName()
+ local button = FrameName and _G[FrameName.."Button"]
+ local text = FrameName and _G[FrameName.."Text"]
+
+ frame:StripTextures()
+ frame:CreateBackdrop()
+ frame.backdrop:SetFrameLevel(frame:GetFrameLevel())
+ frame.backdrop:Point("TOPLEFT", 20, -3)
+ frame.backdrop:Point("BOTTOMRIGHT", button, "BOTTOMRIGHT", 2, -2)
+
+ if not width then width = 155 end
+
+ frame:Width(width)
+
+ if text then
+ text:ClearAllPoints()
+ text:Point("RIGHT", button, "LEFT", -2, 0)
+ end
+
+ if button then
+ S:HandleNextPrevButton(button, direction or nil, {1, 0.8, 0})
+ button:ClearAllPoints()
+ button:Point("RIGHT", frame, "RIGHT", -10, 3)
+ button:Size(16, 16)
+ end
+end
+
+function S:HandleStatusBar(frame, color)
+ frame:SetFrameLevel(frame:GetFrameLevel() + 1)
+ frame:StripTextures()
+ frame:CreateBackdrop("Transparent")
+ frame:SetStatusBarTexture(E.media.normTex)
+ frame:SetStatusBarColor(unpack(color or {.01, .39, .1}))
+ E:RegisterStatusBar(frame)
+end
+
+function S:HandleCheckBox(frame, noBackdrop, noReplaceTextures, forceSaturation)
+ if frame.isSkinned then return end
+
+ frame:StripTextures()
+ frame.forceSaturation = forceSaturation
+
+ if noBackdrop then
+ frame:SetTemplate()
+ frame:Size(16)
+ else
+ frame:CreateBackdrop()
+ frame.backdrop:SetInside(nil, 4, 4)
+ end
+
+ if not noReplaceTextures then
+ if frame.SetCheckedTexture then
+ if E.private.skins.checkBoxSkin then
+ frame:SetCheckedTexture(E.Media.Textures.Melli)
+
+ local checkedTexture = frame:GetCheckedTexture()
+ checkedTexture:SetVertexColor(1, 0.82, 0, 0.8)
+ checkedTexture:SetInside(frame.backdrop)
+ else
+ frame:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check")
+
+ if noBackdrop then
+ frame:GetCheckedTexture():SetInside(nil, -4, -4)
+ end
+ end
+ end
+
+ if frame.SetDisabledCheckedTexture then
+ if E.private.skins.checkBoxSkin then
+ frame:SetDisabledCheckedTexture(E.Media.Textures.Melli)
+
+ local disabledCheckedTexture = frame:GetDisabledCheckedTexture()
+ disabledCheckedTexture:SetVertexColor(0.6, 0.6, 0.6, 0.8)
+ disabledCheckedTexture:SetInside(frame.backdrop)
+ else
+ frame:SetDisabledCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check-Disabled")
+
+ if noBackdrop then
+ frame:GetDisabledCheckedTexture():SetInside(nil, -4, -4)
+ end
+ end
+ end
+
+ if frame.SetDisabledTexture then
+ if E.private.skins.checkBoxSkin then
+ frame:SetDisabledTexture(E.Media.Textures.Melli)
+
+ local disabledTexture = frame:GetDisabledTexture()
+ disabledTexture:SetVertexColor(0.6, 0.6, 0.6, 0.8)
+ disabledTexture:SetInside(frame.backdrop)
+ else
+ frame:SetDisabledTexture("Interface\\Buttons\\UI-CheckBox-Check-Disabled")
+
+ if noBackdrop then
+ frame:GetDisabledTexture():SetInside(nil, -4, -4)
+ end
+ end
+ end
+
+ frame:HookScript("OnDisable", function(checkbox)
+ if not checkbox.SetDisabledTexture then return end
+
+ if checkbox:GetChecked() then
+ if E.private.skins.checkBoxSkin then
+ checkbox:SetDisabledTexture(E.Media.Textures.Melli)
+ else
+ checkbox:SetDisabledTexture("Interface\\Buttons\\UI-CheckBox-Check-Disabled")
+ end
+ else
+ checkbox:SetDisabledTexture("")
+ end
+ end)
+
+ hooksecurefunc(frame, "SetNormalTexture", function(checkbox, texPath)
+ if texPath ~= "" then checkbox:SetNormalTexture("") end
+ end)
+ hooksecurefunc(frame, "SetPushedTexture", function(checkbox, texPath)
+ if texPath ~= "" then checkbox:SetPushedTexture("") end
+ end)
+ hooksecurefunc(frame, "SetHighlightTexture", function(checkbox, texPath)
+ if texPath ~= "" then checkbox:SetHighlightTexture("") end
+ end)
+ hooksecurefunc(frame, "SetCheckedTexture", function(checkbox, texPath)
+ if texPath == E.Media.Textures.Melli or texPath == "Interface\\Buttons\\UI-CheckBox-Check" then return end
+ if E.private.skins.checkBoxSkin then
+ checkbox:SetCheckedTexture(E.Media.Textures.Melli)
+ else
+ checkbox:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check")
+ end
+ end)
+ end
+
+ frame.isSkinned = true
+end
+
+function S:HandleColorSwatch(frame, size)
+ if frame.isSkinned then return end
+
+ frame:StripTextures()
+ frame:CreateBackdrop("Default")
+ frame.backdrop:SetFrameLevel(frame:GetFrameLevel())
+
+ if size then
+ frame:Size(size)
+ end
+
+ local normalTexture = frame:GetNormalTexture()
+ normalTexture:SetTexture(E.media.blankTex)
+ normalTexture:ClearAllPoints()
+ normalTexture:SetInside(frame.backdrop)
+
+ frame.isSkinned = true
+end
+
+function S:HandleIcon(icon, parent)
+ parent = parent or icon:GetParent()
+
+ icon:SetTexCoord(unpack(E.TexCoords))
+ parent:CreateBackdrop("Default")
+ icon:SetParent(parent.backdrop)
+ parent.backdrop:SetOutside(icon)
+end
+
+function S:HandleItemButton(b, shrinkIcon)
+ if b.isSkinned then return end
+
+ local icon = b.icon or b.IconTexture or b.iconTexture
+ local texture
+ if b:GetName() and _G[b:GetName().."IconTexture"] then
+ icon = _G[b:GetName().."IconTexture"]
+ elseif b:GetName() and _G[b:GetName().."Icon"] then
+ icon = _G[b:GetName().."Icon"]
+ end
+
+ if icon and icon:GetTexture() then
+ texture = icon:GetTexture()
+ end
+
+ b:StripTextures()
+ b:CreateBackdrop("Default", true)
+ b:StyleButton()
+
+ if icon then
+ icon:SetTexCoord(unpack(E.TexCoords))
+
+ if shrinkIcon then
+ b.backdrop:SetAllPoints()
+ icon:SetInside(b)
+ else
+ b.backdrop:SetOutside(icon)
+ end
+ icon:SetParent(b.backdrop)
+
+ if texture then
+ icon:SetTexture(texture)
+ end
+ end
+
+ b.isSkinned = true
+end
+
+local handleCloseButtonOnEnter = function(btn) if btn.Texture then btn.Texture:SetVertexColor(unpack(E.media.rgbvaluecolor)) end end
+local handleCloseButtonOnLeave = function(btn) if btn.Texture then btn.Texture:SetVertexColor(1, 1, 1) end end
+
+function S:HandleCloseButton(f, point)
+ f:StripTextures()
+
+ if f:GetNormalTexture() then f:SetNormalTexture("") f.SetNormalTexture = E.noop end
+ if f:GetPushedTexture() then f:SetPushedTexture("") f.SetPushedTexture = E.noop end
+
+ if not f.Texture then
+ f.Texture = f:CreateTexture(nil, "OVERLAY")
+ f.Texture:Point("CENTER")
+ f.Texture:SetTexture(E.Media.Textures.Close)
+ f.Texture:Size(12, 12)
+ f:HookScript("OnEnter", handleCloseButtonOnEnter)
+ f:HookScript("OnLeave", handleCloseButtonOnLeave)
+ f:SetHitRectInsets(6, 6, 7, 7)
+ end
+
+ if point then
+ f:Point("TOPRIGHT", point, "TOPRIGHT", 2, 3)
+ end
+end
+
+local sliderOnDisable = function(self) self:GetThumbTexture():SetVertexColor(0.6, 0.6, 0.6, 0.8) end
+local sliderOnEnable = function(self) self:GetThumbTexture():SetVertexColor(1, 0.82, 0, 0.8) end
+
+function S:HandleSliderFrame(frame)
+ local orientation = frame:GetOrientation()
+
+ frame:StripTextures()
+ frame:SetTemplate()
+ frame:SetThumbTexture(E.Media.Textures.Melli)
+
+ local thumb = frame:GetThumbTexture()
+ thumb:SetVertexColor(1, 0.82, 0, 0.8)
+ thumb:Size(10)
+
+ frame:HookScript("OnDisable", sliderOnDisable)
+ frame:HookScript("OnEnable", sliderOnEnable)
+
+ if orientation == "VERTICAL" then
+ frame:Width(12)
+ else
+ frame:Height(12)
+
+ for i = 1, frame:GetNumRegions() do
+ local region = select(i, frame:GetRegions())
+ if region and region:IsObjectType("FontString") then
+ local point, anchor, anchorPoint, x, y = region:GetPoint()
+ if find(anchorPoint, "BOTTOM") then
+ region:Point(point, anchor, anchorPoint, x, y - 4)
+ end
+ end
+ end
+ end
+end
+
+function S:HandleIconSelectionFrame(frame, numIcons, buttonNameTemplate, frameNameOverride)
+ local frameName = frameNameOverride or frame:GetName() --We need override in case Blizzard fucks up the naming (guild bank)
+ local scrollFrame = _G[frameName.."ScrollFrame"]
+ local editBox = _G[frameName.."EditBox"]
+ local okayButton = _G[frameName.."OkayButton"] or _G[frameName.."Okay"]
+ local cancelButton = _G[frameName.."CancelButton"] or _G[frameName.."Cancel"]
+
+ frame:StripTextures()
+ scrollFrame:StripTextures()
+ editBox:DisableDrawLayer("BACKGROUND") --Removes textures around it
+
+ frame:CreateBackdrop("Transparent")
+ frame.backdrop:Point("TOPLEFT", frame, "TOPLEFT", 10, -12)
+ frame.backdrop:Point("BOTTOMRIGHT", cancelButton, "BOTTOMRIGHT", 8, -8)
+
+ S:HandleButton(okayButton)
+ S:HandleButton(cancelButton)
+ S:HandleEditBox(editBox)
+
+ for i = 1, numIcons do
+ local button = _G[buttonNameTemplate..i]
+ local icon = _G[button:GetName().."Icon"]
+ button:StripTextures()
+ button:SetTemplate("Default")
+ button:StyleButton(nil, true)
+ icon:SetInside()
+ icon:SetTexCoord(unpack(E.TexCoords))
+ end
+end
+
+function S:HandleNextPrevButton(btn, arrowDir, color, noBackdrop, stipTexts)
+ if btn.isSkinned then return end
+
+ if not arrowDir then
+ arrowDir = "down"
+ local ButtonName = btn:GetName() and lower(btn:GetName())
+
+ if ButtonName then
+ if (find(ButtonName, "left") or find(ButtonName, "prev") or find(ButtonName, "decrement")) then
+ arrowDir = "left"
+ elseif (find(ButtonName, "right") or find(ButtonName, "next") or find(ButtonName, "increment")) then
+ arrowDir = "right"
+ elseif (find(ButtonName, "scrollup") or find(ButtonName, "upbutton") or find(ButtonName, "top") or find(ButtonName, "promote")) then
+ arrowDir = "up"
+ end
+ end
+ end
+
+ btn:SetHitRectInsets(0, 0, 0, 0)
+
+ btn:StripTextures()
+ if not noBackdrop then
+ S:HandleButton(btn)
+ end
+
+ if stipTexts then
+ btn:StripTexts()
+ end
+
+ btn:SetNormalTexture(E.Media.Textures.ArrowUp)
+ btn:SetPushedTexture(E.Media.Textures.ArrowUp)
+ btn:SetDisabledTexture(E.Media.Textures.ArrowUp)
+
+ local Normal, Disabled, Pushed = btn:GetNormalTexture(), btn:GetDisabledTexture(), btn:GetPushedTexture()
+
+ if noBackdrop then
+ btn:Size(20, 20)
+ Disabled:SetVertexColor(.5, .5, .5)
+ btn.Texture = Normal
+ btn:HookScript("OnEnter", handleCloseButtonOnEnter)
+ btn:HookScript("OnLeave", handleCloseButtonOnLeave)
+ else
+ btn:Size(18, 18)
+ Disabled:SetVertexColor(.3, .3, .3)
+ end
+
+ Normal:SetInside()
+ Pushed:SetInside()
+ Disabled:SetInside()
+
+ Normal:SetTexCoord(0, 1, 0, 1)
+ Pushed:SetTexCoord(0, 1, 0, 1)
+ Disabled:SetTexCoord(0, 1, 0, 1)
+
+ Normal:SetRotation(S.ArrowRotation[arrowDir])
+ Pushed:SetRotation(S.ArrowRotation[arrowDir])
+ Disabled:SetRotation(S.ArrowRotation[arrowDir])
+
+ Normal:SetVertexColor(unpack(color or {1, 1, 1}))
+
+ btn.isSkinned = true
+end
+
+function S:SetNextPrevButtonDirection(frame, arrowDir)
+ local direction = self.ArrowRotation[(arrowDir or "down")]
+
+ frame:GetNormalTexture():SetRotation(direction)
+ frame:GetDisabledTexture():SetRotation(direction)
+ frame:GetPushedTexture():SetRotation(direction)
+end
+
+local function collapseSetNormalTexture_Text(self, texture)
+ if texture then
+ if find(texture, "MinusButton", 1, true) or find(texture, "ZoomOutButton", 1, true) then
+ self.collapseText:SetText("-")
+ return
+ elseif find(texture, "PlusButton", 1, true) or find(texture, "ZoomInButton", 1, true) then
+ self.collapseText:SetText("+")
+ return
+ end
+ end
+ self.collapseText:SetText("")
+end
+local function collapseSetNormalTexture_Texture(self, texture)
+ if texture then
+ if find(texture, "MinusButton", 1, true) or find(texture, "ZoomOutButton", 1, true) then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Minus)
+ self:GetPushedTexture():SetTexture(E.Media.Textures.Minus)
+ self:GetDisabledTexture():SetTexture(E.Media.Textures.Minus)
+ return
+ elseif find(texture, "PlusButton", 1, true) or find(texture, "ZoomInButton", 1, true) then
+ self:GetNormalTexture():SetTexture(E.Media.Textures.Plus)
+ self:GetPushedTexture():SetTexture(E.Media.Textures.Plus)
+ self:GetDisabledTexture():SetTexture(E.Media.Textures.Plus)
+ return
+ end
+ end
+ self:GetNormalTexture():SetTexture(0, 0, 0, 0)
+ self:GetPushedTexture():SetTexture(0, 0, 0, 0)
+ self:GetDisabledTexture():SetTexture(0, 0, 0, 0)
+end
+function S:HandleCollapseExpandButton(button, defaultState, useFontString, xOffset, yOffset)
+ if button.isSkinned then return end
+
+ if defaultState == "auto" then
+ local texture = button:GetNormalTexture():GetTexture()
+ if find(texture, "MinusButton", 1, true) or find(texture, "ZoomOutButton", 1, true) then
+ defaultState = "-"
+ elseif find(texture, "PlusButton", 1, true) or find(texture, "ZoomInButton", 1, true) then
+ defaultState = "+"
+ end
+ end
+
+ button:SetNormalTexture("")
+ button:SetPushedTexture("")
+ button:SetHighlightTexture("")
+ button:SetDisabledTexture("")
+
+ button.SetPushedTexture = E.noop
+ button.SetHighlightTexture = E.noop
+ button.SetDisabledTexture = E.noop
+
+ if useFontString then
+ button.collapseText = button:CreateFontString(nil, "OVERLAY")
+ button.collapseText:FontTemplate(nil, 22)
+ button.collapseText:Point("LEFT", xOffset or 5, yOffset or 0)
+ button.collapseText:SetText("")
+
+ if defaultState == "+" then
+ button.collapseText:SetText("+")
+ elseif defaultState == "-" then
+ button.collapseText:SetText("-")
+ end
+
+ button.SetNormalTexture = collapseSetNormalTexture_Text
+ else
+ local normalTexture = button:GetNormalTexture()
+ normalTexture:Size(16)
+ normalTexture:ClearAllPoints()
+ normalTexture:Point("LEFT", xOffset or 3, yOffset or 0)
+ normalTexture.SetPoint = E.noop
+
+ local pushedTexture = button:GetPushedTexture()
+ pushedTexture:Size(16)
+ pushedTexture:ClearAllPoints()
+ pushedTexture:Point("LEFT", xOffset or 3, yOffset or 0)
+ pushedTexture.SetPoint = E.noop
+
+ local disabledTexture = button:GetDisabledTexture()
+ disabledTexture:Size(16)
+ disabledTexture:ClearAllPoints()
+ disabledTexture:Point("LEFT", xOffset or 3, yOffset or 0)
+ disabledTexture.SetPoint = E.noop
+ disabledTexture:SetVertexColor(0.6, 0.6, 0.6)
+
+ if defaultState == "+" then
+ normalTexture:SetTexture(E.Media.Textures.Plus)
+ pushedTexture:SetTexture(E.Media.Textures.Plus)
+ disabledTexture:SetTexture(E.Media.Textures.Plus)
+ elseif defaultState == "-" then
+ normalTexture:SetTexture(E.Media.Textures.Minus)
+ pushedTexture:SetTexture(E.Media.Textures.Minus)
+ disabledTexture:SetTexture(E.Media.Textures.Minus)
+ end
+
+ button.SetNormalTexture = collapseSetNormalTexture_Texture
+ end
+
+ button.isSkinned = true
+end
+
+do -- Handle collapse like retail (including UIPanelButtonTemplate2)
+ local function UpdateCollapseTexture(button, texture)
+ local tex = button:GetNormalTexture()
+ if strfind(texture, "Plus") or strfind(texture, "Closed") then
+ tex:SetTexture(E.Media.Textures.PlusButton)
+ elseif strfind(texture, "Minus") or strfind(texture, "Open") then
+ tex:SetTexture(E.Media.Textures.MinusButton)
+ end
+ end
+
+ local function UpdatePushedTexture(button)
+ button:GetPushedTexture():SetTexture("")
+ end
+
+ local function syncPushTexture(button, _, skip)
+ if not skip then
+ local normal = button:GetNormalTexture():GetTexture()
+ button:SetPushedTexture(normal, true)
+ end
+ end
+
+ function S:HandleCollapseTexture(button, syncPushed)
+ if syncPushed then -- not needed always
+ hooksecurefunc(button, "SetPushedTexture", syncPushTexture)
+ syncPushTexture(button)
+ else
+ button:SetPushedTexture("")
+ hooksecurefunc(button, "SetPushedTexture", UpdatePushedTexture) -- make it permanent
+ end
+
+ hooksecurefunc(button, 'SetNormalTexture', UpdateCollapseTexture)
+ UpdateCollapseTexture(button, button:GetNormalTexture():GetTexture())
+
+ -- Find the button textures that is still present
+ for i = 1, 3 do
+ local region = select(i, button:GetRegions())
+ if region and region:IsObjectType("Texture") and region:GetTexture() then -- region:GetTexture() nil check so strfind doesn't error
+ if strfind(region:GetTexture(), "Up") then
+ region:Kill() -- Remove the button backdrop texture for good
+ end
+ end
+ end
+ end
+end
+
+function S:ADDON_LOADED(_, addon)
+ S:SkinAce3()
+
+ if self.allowBypass[addon] then
+ if self.addonCallbacks[addon] then
+ --Fire events to the skins that rely on this addon
+ for index, event in ipairs(self.addonCallbacks[addon].CallPriority) do
+ self.addonCallbacks[addon][event] = nil
+ self.addonCallbacks[addon].CallPriority[index] = nil
+ E.callbacks:Fire(event)
+ end
+ end
+ return
+ end
+
+ if not E.initialized then return end
+
+ if self.addonCallbacks[addon] then
+ for index, event in ipairs(self.addonCallbacks[addon].CallPriority) do
+ self.addonCallbacks[addon][event] = nil
+ self.addonCallbacks[addon].CallPriority[index] = nil
+ E.callbacks:Fire(event)
+ end
+ end
+end
+
+local function SetPanelWindowInfo(frame, name, value, igroneUpdate)
+ frame:SetAttribute(name, value)
+
+ if not igroneUpdate and frame:IsShown() then
+ UpdateUIPanelPositions(frame)
+ end
+end
+
+local UI_PANEL_OFFSET = 7
+
+function S:SetUIPanelWindowInfo(frame, name, value, offset, igroneUpdate)
+ local frameName = frame and frame.GetName and frame:GetName()
+ if not (frameName and UIPanelWindows[frameName]) then return end
+
+ name = "UIPanelLayout-"..name
+
+ if name == "UIPanelLayout-width" then
+ value = E:Scale(value or (frame.backdrop and frame.backdrop:GetWidth() or frame:GetWidth())) + (offset or 0) + UI_PANEL_OFFSET
+ end
+
+ local valueChanged = frame:GetAttribute(name) ~= value
+
+ if not frame:CanChangeAttribute() then
+ local frameInfo = format("%s-%s", frameName, name)
+
+ if self.uiPanelQueue[frameInfo] then
+ if not valueChanged then
+ self.uiPanelQueue[frameInfo][3] = nil
+ else
+ self.uiPanelQueue[frameInfo][3] = value
+ self.uiPanelQueue[frameInfo][4] = igroneUpdate
+ end
+ elseif valueChanged then
+ self.uiPanelQueue[frameInfo] = {frame, name, value, igroneUpdate}
+
+ if not self.inCombat then
+ self.inCombat = true
+ S:RegisterEvent("PLAYER_REGEN_ENABLED")
+ end
+ end
+ elseif valueChanged then
+ SetPanelWindowInfo(frame, name, value, igroneUpdate)
+ end
+end
+
+function S:SetBackdropHitRect(frame, backdrop, clampRect, attempt)
+ if not frame then return end
+
+ backdrop = backdrop or frame.backdrop
+ if not backdrop then return end
+
+ local left = frame:GetLeft()
+ local bleft = backdrop:GetLeft()
+
+ if not left or not bleft then
+ if attempt ~= 10 then
+ E:Delay(0.1, S.SetBackdropHitRect, S, frame, backdrop, clampRect, attempt and attempt + 1 or 1)
+ end
+
+ return
+ end
+
+ left = floor(left + 0.5)
+ local right = floor(frame:GetRight() + 0.5)
+ local top = floor(frame:GetTop() + 0.5)
+ local bottom = floor(frame:GetBottom() + 0.5)
+
+ bleft = floor(bleft + 0.5)
+ local bright = floor(backdrop:GetRight() + 0.5)
+ local btop = floor(backdrop:GetTop() + 0.5)
+ local bbottom = floor(backdrop:GetBottom() + 0.5)
+
+ left = bleft - left
+ right = right - bright
+ top = top - btop
+ bottom = bbottom - bottom
+
+ if not frame:CanChangeAttribute() then
+ self.hitRectQueue[frame] = {left, right, top, bottom, clampRect}
+
+ if not self.inCombat then
+ self.inCombat = true
+ S:RegisterEvent("PLAYER_REGEN_ENABLED")
+ end
+ else
+ frame:SetHitRectInsets(left, right, top, bottom)
+
+ if clampRect then
+ frame:SetClampRectInsets(left, -right, -top, bottom)
+ end
+ end
+end
+
+function S:PLAYER_REGEN_ENABLED()
+ self.inCombat = nil
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED")
+
+ for frameInfo, info in pairs(self.uiPanelQueue) do
+ if info[3] then
+ SetPanelWindowInfo(info[1], info[2], info[3], info[4])
+ end
+ self.uiPanelQueue[frameInfo] = nil
+ end
+
+ for frame, info in pairs(self.hitRectQueue) do
+ frame:SetHitRectInsets(info[1], info[2], info[3], info[4])
+
+ if info[5] then
+ frame:SetClampRectInsets(info[1], info[2], info[3], info[4])
+ end
+
+ self.hitRectQueue[frame] = nil
+ end
+end
+
+--Add callback for skin that relies on another addon.
+--These events will be fired when the addon is loaded.
+function S:AddCallbackForAddon(addonName, eventName, loadFunc, forceLoad, bypass)
+ if not addonName or type(addonName) ~= "string" then
+ E:Print("Invalid argument #1 to S:AddCallbackForAddon (string expected)")
+ return
+ elseif not eventName or type(eventName) ~= "string" then
+ E:Print("Invalid argument #2 to S:AddCallbackForAddon (string expected)")
+ return
+ elseif not loadFunc or type(loadFunc) ~= "function" then
+ E:Print("Invalid argument #3 to S:AddCallbackForAddon (function expected)")
+ return
+ end
+
+ if bypass then
+ self.allowBypass[addonName] = true
+ end
+
+ --Create an event registry for this addon, so that we can fire multiple events when this addon is loaded
+ if not self.addonCallbacks[addonName] then
+ self.addonCallbacks[addonName] = {["CallPriority"] = {}}
+ end
+
+ if self.addonCallbacks[addonName][eventName] or E.ModuleCallbacks[eventName] or E.InitialModuleCallbacks[eventName] then
+ --Don't allow a registered callback to be overwritten
+ E:Print("Invalid argument #2 to S:AddCallbackForAddon (event name:", eventName, "is already registered, please use a unique event name)")
+ return
+ end
+
+ --Register loadFunc to be called when event is fired
+ E.RegisterCallback(E, eventName, loadFunc)
+
+ if forceLoad then
+ E.callbacks:Fire(eventName)
+ else
+ --Insert eventName in this addons' registry
+ self.addonCallbacks[addonName][eventName] = true
+ self.addonCallbacks[addonName].CallPriority[#self.addonCallbacks[addonName].CallPriority + 1] = eventName
+ end
+end
+
+--Add callback for skin that does not rely on a another addon.
+--These events will be fired when the Skins module is initialized.
+function S:AddCallback(eventName, loadFunc)
+ if not eventName or type(eventName) ~= "string" then
+ E:Print("Invalid argument #1 to S:AddCallback (string expected)")
+ return
+ elseif not loadFunc or type(loadFunc) ~= "function" then
+ E:Print("Invalid argument #2 to S:AddCallback (function expected)")
+ return
+ end
+
+ if self.nonAddonCallbacks[eventName] or E.ModuleCallbacks[eventName] or E.InitialModuleCallbacks[eventName] then
+ --Don't allow a registered callback to be overwritten
+ E:Print("Invalid argument #1 to S:AddCallback (event name:", eventName, "is already registered, please use a unique event name)")
+ return
+ end
+
+ --Add event name to registry
+ self.nonAddonCallbacks[eventName] = true
+ self.nonAddonCallbacks.CallPriority[#self.nonAddonCallbacks.CallPriority + 1] = eventName
+
+ --Register loadFunc to be called when event is fired
+ E.RegisterCallback(E, eventName, loadFunc)
+end
+
+function S:SkinAce3()
+ S:HookAce3(LibStub("AceGUI-3.0", true))
+ S:Ace3_SkinTooltip(LibStub("AceConfigDialog-3.0", true))
+ S:Ace3_SkinTooltip(E.Libs.AceConfigDialog, E.LibsMinor.AceConfigDialog)
+end
+
+function S:Initialize()
+ self.Initialized = true
+
+ self.db = E.private.skins
+
+ self.uiPanelQueue = {}
+ self.hitRectQueue = {}
+
+ S:SkinAce3()
+
+ --Fire event for all skins that doesn't rely on a Blizzard addon
+ for index, event in ipairs(self.nonAddonCallbacks.CallPriority) do
+ self.nonAddonCallbacks[event] = nil
+ self.nonAddonCallbacks.CallPriority[index] = nil
+ E.callbacks:Fire(event)
+ end
+
+ --Fire events for Blizzard addons that are already loaded
+ for addon in pairs(self.addonCallbacks) do
+ if IsAddOnLoaded(addon) then
+ for index, event in ipairs(S.addonCallbacks[addon].CallPriority) do
+ self.addonCallbacks[addon][event] = nil
+ self.addonCallbacks[addon].CallPriority[index] = nil
+ E.callbacks:Fire(event)
+ end
+ end
+ end
+end
+
+S:RegisterEvent("ADDON_LOADED")
+
+local function InitializeCallback()
+ S:Initialize()
+end
+
+E:RegisterModule(S:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/Tooltip/Load_Tooltip.xml b/ElvUI/Modules/Tooltip/Load_Tooltip.xml
new file mode 100644
index 0000000..1e62dbe
--- /dev/null
+++ b/ElvUI/Modules/Tooltip/Load_Tooltip.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/Tooltip/Tooltip.lua b/ElvUI/Modules/Tooltip/Tooltip.lua
new file mode 100644
index 0000000..4983540
--- /dev/null
+++ b/ElvUI/Modules/Tooltip/Tooltip.lua
@@ -0,0 +1,714 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local TT = E:GetModule("Tooltip")
+
+--Lua functions
+local _G = _G
+local unpack, tonumber, select = unpack, tonumber, select
+local twipe, tinsert, tconcat = table.wipe, table.insert, table.concat
+local floor = math.floor
+local find, format, sub, match = string.find, string.format, string.sub, string.match
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetTime = GetTime
+local UnitGUID = UnitGUID
+local InCombatLockdown = InCombatLockdown
+local IsShiftKeyDown = IsShiftKeyDown
+local IsControlKeyDown = IsControlKeyDown
+local IsAltKeyDown = IsAltKeyDown
+local GetInventoryItemLink = GetInventoryItemLink
+local GetInventorySlotInfo = GetInventorySlotInfo
+local UnitExists = UnitExists
+local CanInspect = CanInspect
+local NotifyInspect = NotifyInspect
+local GetMouseFocus = GetMouseFocus
+local UnitLevel = UnitLevel
+local UnitIsPlayer = UnitIsPlayer
+local UnitClass = UnitClass
+local UnitName = UnitName
+local GetGuildInfo = GetGuildInfo
+local UnitPVPName = UnitPVPName
+local UnitIsAFK = UnitIsAFK
+local UnitIsDND = UnitIsDND
+local GetQuestDifficultyColor = GetQuestDifficultyColor
+local UnitRace = UnitRace
+local UnitIsTapped = UnitIsTapped
+local UnitIsTappedByPlayer = UnitIsTappedByPlayer
+local UnitReaction = UnitReaction
+local UnitClassification = UnitClassification
+local UnitCreatureType = UnitCreatureType
+local UnitIsPVP = UnitIsPVP
+local UnitHasVehicleUI = UnitHasVehicleUI
+local GetNumPartyMembers = GetNumPartyMembers
+local GetNumRaidMembers = GetNumRaidMembers
+local UnitIsUnit = UnitIsUnit
+local UnitIsDeadOrGhost = UnitIsDeadOrGhost
+local GetItemCount = GetItemCount
+local UnitAura = UnitAura
+local SetTooltipMoney = SetTooltipMoney
+local GameTooltip_ClearMoney = GameTooltip_ClearMoney
+local TARGET = TARGET
+local DEAD = DEAD
+local FOREIGN_SERVER_LABEL = FOREIGN_SERVER_LABEL
+local PVP = PVP
+local FACTION_ALLIANCE = FACTION_ALLIANCE
+local FACTION_HORDE = FACTION_HORDE
+local LEVEL = LEVEL
+local FACTION_BAR_COLORS = FACTION_BAR_COLORS
+local ID = ID
+
+local GameTooltip, GameTooltipStatusBar = GameTooltip, GameTooltipStatusBar
+local targetList, inspectCache = {}, {}
+local TAPPED_COLOR = {r=.6, g=.6, b=.6}
+local AFK_LABEL = " |cffFFFFFF[|r|cffE7E716"..L["AFK"].."|r|cffFFFFFF]|r"
+local DND_LABEL = " |cffFFFFFF[|r|cffFF0000"..L["DND"].."|r|cffFFFFFF]|r"
+local keybindFrame
+
+local classification = {
+ worldboss = format("|cffAF5050 %s|r", BOSS),
+ rareelite = format("|cffAF5050+ %s|r", ITEM_QUALITY3_DESC),
+ elite = "|cffAF5050+|r",
+ rare = format("|cffAF5050 %s|r", ITEM_QUALITY3_DESC)
+}
+
+local inventorySlots = {
+ "HeadSlot", "NeckSlot", "ShoulderSlot", "BackSlot", "ChestSlot", "WristSlot",
+ "HandsSlot", "WaistSlot", "LegsSlot", "FeetSlot", "Finger0Slot", "Finger1Slot",
+ "Trinket0Slot", "Trinket1Slot", "MainHandSlot", "SecondaryHandSlot", "RangedSlot"
+}
+
+local updateUnitModifiers = {
+ ["LSHIFT"] = true,
+ ["RSHIFT"] = true,
+ ["LCTRL"] = true,
+ ["RCTRL"] = true,
+ ["LALT"] = true,
+ ["RALT"] = true,
+}
+
+function TT:GameTooltip_SetDefaultAnchor(tt, parent)
+ if not E.private.tooltip.enable then return end
+ if not self.db.visibility then return end
+
+ if tt:GetAnchorType() ~= "ANCHOR_NONE" then return end
+ if InCombatLockdown() and self.db.visibility.combat then
+ local modifier = self.db.visibility.combatOverride
+ if (not(
+ (modifier == "SHIFT" and IsShiftKeyDown())
+ or
+ (modifier == "CTRL" and IsControlKeyDown())
+ or
+ (modifier == "ALT" and IsAltKeyDown())
+ )) then
+ tt:Hide()
+ return
+ end
+ end
+
+ local ownerName = tt:GetOwner() and tt:GetOwner().GetName and tt:GetOwner():GetName()
+ if self.db.visibility.actionbars ~= "NONE" and ownerName and (find(ownerName, "ElvUI_Bar") or find(ownerName, "ElvUI_StanceBar") or find(ownerName, "PetAction")) and not keybindFrame.active then
+ local modifier = self.db.visibility.actionbars
+
+ if modifier == "ALL" or not ((modifier == "SHIFT" and IsShiftKeyDown()) or (modifier == "CTRL" and IsControlKeyDown()) or (modifier == "ALT" and IsAltKeyDown())) then
+ tt:Hide()
+ return
+ end
+ end
+
+ if tt.StatusBar then
+ if self.db.healthBar.statusPosition == "BOTTOM" then
+ if tt.StatusBar.anchoredToTop then
+ tt.StatusBar:ClearAllPoints()
+ tt.StatusBar:Point("TOPLEFT", tt, "BOTTOMLEFT", E.Border, -(E.Spacing * 3))
+ tt.StatusBar:Point("TOPRIGHT", tt, "BOTTOMRIGHT", -E.Border, -(E.Spacing * 3))
+ tt.StatusBar.text:Point("CENTER", tt.StatusBar, 0, 0)
+ tt.StatusBar.anchoredToTop = nil
+ end
+ else
+ if not tt.StatusBar.anchoredToTop then
+ tt.StatusBar:ClearAllPoints()
+ tt.StatusBar:Point("BOTTOMLEFT", tt, "TOPLEFT", E.Border, (E.Spacing * 3))
+ tt.StatusBar:Point("BOTTOMRIGHT", tt, "TOPRIGHT", -E.Border, (E.Spacing * 3))
+ tt.StatusBar.text:Point("CENTER", tt.StatusBar, 0, 0)
+ tt.StatusBar.anchoredToTop = true
+ end
+ end
+ end
+
+ if parent then
+ if self.db.cursorAnchor then
+ tt:SetOwner(parent, self.db.cursorAnchorType, self.db.cursorAnchorX, self.db.cursorAnchorY)
+ return
+ else
+ tt:SetOwner(parent, "ANCHOR_NONE")
+ end
+ end
+
+ local _, anchor = tt:GetPoint()
+
+ if anchor == nil or (ElvUI_ContainerFrame and anchor == ElvUI_ContainerFrame) or anchor == RightChatPanel or anchor == TooltipMover or anchor == _G.UIParent or anchor == E.UIParent then
+ tt:ClearAllPoints()
+ if not E:HasMoverBeenMoved("TooltipMover") then
+ if ElvUI_ContainerFrame and ElvUI_ContainerFrame:IsShown() then
+ tt:Point("BOTTOMRIGHT", ElvUI_ContainerFrame, "TOPRIGHT", 0, 18)
+ elseif RightChatPanel:GetAlpha() == 1 and RightChatPanel:IsShown() then
+ tt:Point("BOTTOMRIGHT", RightChatPanel, "TOPRIGHT", 0, 18)
+ else
+ tt:Point("BOTTOMRIGHT", RightChatPanel, "BOTTOMRIGHT", 0, 18)
+ end
+ else
+ local point = E:GetScreenQuadrant(TooltipMover)
+ if point == "TOPLEFT" then
+ tt:Point("TOPLEFT", TooltipMover, "BOTTOMLEFT")
+ elseif point == "TOPRIGHT" then
+ tt:Point("TOPRIGHT", TooltipMover, "BOTTOMRIGHT")
+ elseif point == "BOTTOMLEFT" or point == "LEFT" then
+ tt:Point("BOTTOMLEFT", TooltipMover, "TOPLEFT")
+ else
+ tt:Point("BOTTOMRIGHT", TooltipMover, "TOPRIGHT")
+ end
+ end
+ end
+end
+
+function TT:GetItemLvL(unit)
+ local total, items = 0, 0
+ for i = 1, #inventorySlots do
+ local itemLink = GetInventoryItemLink(unit, GetInventorySlotInfo(inventorySlots[i]))
+
+ if itemLink then
+ local iLvl = select(4, GetItemInfo(itemLink))
+ if iLvl and iLvl > 0 then
+ items = items + 1
+ total = total + iLvl
+ end
+ end
+ end
+
+ if items == 0 then
+ return 0
+ end
+
+ return E:Round(total / items, 2)
+end
+
+function TT:RemoveTrashLines(tt)
+ for i = 3, tt:NumLines() do
+ local tiptext = _G["GameTooltipTextLeft"..i]
+ local linetext = tiptext:GetText()
+
+ if linetext == PVP or linetext == FACTION_ALLIANCE or linetext == FACTION_HORDE then
+ tiptext:SetText(nil)
+-- tiptext:Hide()
+ end
+ end
+end
+
+function TT:GetLevelLine(tt, offset)
+ for i = offset, tt:NumLines() do
+ local tipText = _G["GameTooltipTextLeft"..i]
+ if tipText:GetText() and find(tipText:GetText(), LEVEL) then
+ return tipText
+ end
+ end
+end
+
+function TT:SetUnitText(tt, unit, level, isShiftKeyDown)
+ local color
+ if UnitIsPlayer(unit) then
+ local localeClass, class = UnitClass(unit)
+ if not localeClass or not class then return end
+
+ local name, realm = UnitName(unit)
+ local guildName, guildRankName = GetGuildInfo(unit)
+ local pvpName = UnitPVPName(unit)
+
+ color = E.media.herocolor
+
+ if self.db.playerTitles and pvpName then
+ name = pvpName
+ end
+
+ if realm and realm ~= "" then
+ if isShiftKeyDown or self.db.alwaysShowRealm then
+ name = name.."-"..realm
+ else
+ name = name..FOREIGN_SERVER_LABEL
+ end
+ end
+
+ if UnitIsAFK(unit) then
+ name = name..AFK_LABEL
+ elseif UnitIsDND(unit) then
+ name = name..DND_LABEL
+ end
+
+ GameTooltipTextLeft1:SetFormattedText("%s%s", E:RGBToHex(color.r, color.g, color.b), name)
+
+ local lineOffset = 2
+ if guildName then
+ if self.db.guildRanks then
+ GameTooltipTextLeft2:SetFormattedText("<|cff00ff10%s|r> [|cff00ff10%s|r]", guildName, guildRankName)
+ else
+ GameTooltipTextLeft2:SetFormattedText("<|cff00ff10%s|r>", guildName)
+ end
+
+ lineOffset = 3
+ end
+
+ local levelLine = self:GetLevelLine(tt, lineOffset)
+ if levelLine then
+ local diffColor = GetQuestDifficultyColor(level)
+ local race = UnitRace(unit)
+ levelLine:SetFormattedText("|cff%02x%02x%02x%s|r %s %s%s|r", diffColor.r * 255, diffColor.g * 255, diffColor.b * 255, level > 0 and level or "??", race or "", E:RGBToHex(color.r, color.g, color.b), localeClass)
+ end
+ else
+ if UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) then
+ color = TAPPED_COLOR
+ else
+ local unitReaction = UnitReaction(unit, "player")
+ if E.db.tooltip.useCustomFactionColors then
+ if unitReaction then
+ color = E.db.tooltip.factionColors[unitReaction]
+ end
+ else
+ color = FACTION_BAR_COLORS[unitReaction]
+ end
+ end
+
+ if not color then
+ color = E.media.herocolor
+ end
+
+ local levelLine = self:GetLevelLine(tt, 2)
+ if levelLine then
+ local creatureClassification = UnitClassification(unit)
+ local creatureType = UnitCreatureType(unit)
+ local pvpFlag = ""
+ local diffColor = GetQuestDifficultyColor(level)
+
+ if UnitIsPVP(unit) then
+ pvpFlag = format(" (%s)", PVP)
+ end
+
+ levelLine:SetFormattedText("|cff%02x%02x%02x%s|r%s %s%s", diffColor.r * 255, diffColor.g * 255, diffColor.b * 255, level > 0 and level or "??", classification[creatureClassification] or "", creatureType or "", pvpFlag)
+ end
+ end
+
+ return color
+end
+
+function TT:INSPECT_TALENT_READY(event, unit)
+ if not unit then
+ if self.lastGUID ~= UnitGUID("mouseover") then return end
+
+ self:UnregisterEvent(event)
+
+ unit = "mouseover"
+ if not UnitExists(unit) then return end
+ end
+
+ local itemLevel = self:GetItemLvL(unit)
+ inspectCache[self.lastGUID] = {time = GetTime()}
+
+ if itemLevel then
+ inspectCache[self.lastGUID].itemLevel = itemLevel
+ end
+
+ GameTooltip:SetUnit(unit)
+end
+
+function TT:ShowInspectInfo(tt, unit, r, g, b)
+ local canInspect = CanInspect(unit)
+ if not canInspect then return end
+
+ local GUID = UnitGUID(unit)
+ if GUID == E.myguid then
+ tt:AddDoubleLine(L["Item Level:"], self:GetItemLvL("player"), nil, nil, nil, 1, 1, 1)
+ return
+ elseif inspectCache[GUID] then
+ local itemLevel = inspectCache[GUID].itemLevel
+
+ if (GetTime() - inspectCache[GUID].time) < 900 and itemLevel then
+ tt:AddDoubleLine(L["Item Level:"], itemLevel, nil, nil, nil, 1, 1, 1)
+ return
+ else
+ inspectCache[GUID] = nil
+ end
+ end
+
+ if InspectFrame and InspectFrame.unit then
+ if UnitIsUnit(InspectFrame.unit, unit) then
+ self.lastGUID = GUID
+ self:INSPECT_TALENT_READY(nil, unit)
+ end
+ else
+ self.lastGUID = GUID
+ NotifyInspect(unit)
+ self:RegisterEvent("INSPECT_TALENT_READY")
+ end
+end
+
+function TT:GameTooltip_OnTooltipSetUnit(tt)
+ local isShiftKeyDown = IsShiftKeyDown()
+ local isControlKeyDown = IsControlKeyDown()
+
+ if tt:GetOwner() ~= UIParent and (self.db.visibility and self.db.visibility.unitFrames ~= "NONE") then
+ local modifier = self.db.visibility.unitFrames
+
+ if modifier == "ALL" or not ((modifier == "SHIFT" and isShiftKeyDown) or (modifier == "CTRL" and isControlKeyDown) or (modifier == "ALT" and IsAltKeyDown())) then
+ tt:Hide()
+ return
+ end
+ end
+
+ local _, unit = tt:GetUnit()
+
+ if not unit then
+ local GMF = GetMouseFocus()
+ if GMF and GMF:GetAttribute("unit") then
+ unit = GMF:GetAttribute("unit")
+ end
+
+ if not unit or not UnitExists(unit) then return end
+ end
+
+ self:RemoveTrashLines(tt)
+
+ if not isShiftKeyDown and not isControlKeyDown and self.db.targetInfo then
+ local unitTarget = unit.."target"
+ if unit ~= "player" and UnitExists(unitTarget) then
+ local targetColor
+ if UnitIsPlayer(unitTarget) and not UnitHasVehicleUI(unitTarget) then
+ targetColor = E.media.herocolor
+ else
+ targetColor = E.db.tooltip.useCustomFactionColors and E.db.tooltip.factionColors[UnitReaction(unitTarget, "player")] or FACTION_BAR_COLORS[UnitReaction(unitTarget, "player")]
+ end
+
+ if not targetColor then
+ targetColor = E.media.herocolor
+ end
+
+ tt:AddDoubleLine(format("%s:", TARGET), format("|cff%02x%02x%02x%s|r", targetColor.r * 255, targetColor.g * 255, targetColor.b * 255, UnitName(unitTarget)))
+ end
+
+ local numParty = GetNumPartyMembers()
+ local numRaid = GetNumRaidMembers()
+ local inRaid = numRaid > 0
+
+ if inRaid or numParty > 0 then
+ for i = 1, (inRaid and numRaid or numParty) do
+ local groupUnit = (inRaid and "raid"..i or "party"..i)
+
+ if not UnitIsUnit(groupUnit, "player") and UnitIsUnit(groupUnit.."target", unit) then
+ local classColor = E.media.herocolor
+
+ tinsert(targetList, format("%s%s", E:RGBToHex(classColor.r, classColor.g, classColor.b), UnitName(groupUnit)))
+ end
+ end
+
+ local numList = #targetList
+ if numList > 0 then
+ tt:AddLine(format("%s (|cffffffff%d|r): %s", L["Targeted By:"], numList, tconcat(targetList, ", ")), nil, nil, nil, 1)
+ twipe(targetList)
+ end
+ end
+ end
+
+ local isPlayerUnit = UnitIsPlayer(unit)
+ local color = self:SetUnitText(tt, unit, UnitLevel(unit), isShiftKeyDown)
+
+ if isShiftKeyDown and isPlayerUnit then
+ self:ShowInspectInfo(tt, unit, color.r, color.g, color.b)
+ end
+
+ if unit and self.db.npcID and not isPlayerUnit then
+ local guid = UnitGUID(unit)
+ if guid then
+ local id = tonumber(sub(guid, 8, 12), 16)
+ if id then
+ tt:AddLine(format("|cFFCA3C3C%s|r %d", ID, id))
+ end
+ end
+ end
+
+ if color then
+ tt.StatusBar:SetStatusBarColor(color.r, color.g, color.b)
+ else
+ tt.StatusBar:SetStatusBarColor(0.6, 0.6, 0.6)
+ end
+
+ local textWidth = tt.StatusBar.text:GetStringWidth()
+ if textWidth then
+ tt:SetMinimumWidth(textWidth)
+ end
+end
+
+function TT:GameTooltipStatusBar_OnValueChanged(tt, value)
+ if not value or not tt.text or not self.db.healthBar.text then return end
+
+ local _, unit = tt:GetParent():GetUnit()
+
+ if not unit then
+ local GMF = GetMouseFocus()
+ if GMF and GMF:GetAttribute("unit") then
+ unit = GMF:GetAttribute("unit")
+ end
+ end
+
+ local _, max = tt:GetMinMaxValues()
+ if value > 0 and max == 1 then
+ tt.text:SetFormattedText("%d%%", floor(value * 100))
+ tt:SetStatusBarColor(TAPPED_COLOR.r, TAPPED_COLOR.g, TAPPED_COLOR.b)
+ elseif value == 0 or (unit and UnitIsDeadOrGhost(unit)) then
+ tt.text:SetText(DEAD)
+ else
+ tt.text:SetText(E:ShortValue(value).." / "..E:ShortValue(max))
+ end
+end
+
+function TT:GameTooltip_OnTooltipCleared(tt)
+ tt.itemCleared = nil
+end
+
+function TT:GameTooltip_OnTooltipSetItem(tt)
+ if self.db.visibility and self.db.visibility.bags ~= "NONE" then
+ local ownerName = tt:GetOwner() and tt:GetOwner().GetName and tt:GetOwner():GetName()
+
+ if ownerName and (find(ownerName, "ElvUI_Container") or find(ownerName, "ElvUI_BankContainer")) then
+ local modifier = self.db.visibility.bags
+
+ if modifier == "ALL" or not ((modifier == "SHIFT" and IsShiftKeyDown()) or (modifier == "CTRL" and IsControlKeyDown()) or (modifier == "ALT" and IsAltKeyDown())) then
+ tt.itemCleared = true
+ tt:Hide()
+ return
+ end
+ end
+ end
+
+ if tt.itemCleared then return end
+
+ local _, link = tt:GetItem()
+ if not link then return end
+
+ local num = GetItemCount(link)
+ local numall = GetItemCount(link, true)
+ local left, right, bankCount
+
+ if self.db.spellID then
+ left = format("|cFFCA3C3C%s|r %d", ID, tonumber(match(link, ":(%d+)")))
+ end
+
+ if self.db.itemCount == "BAGS_ONLY" then
+ right = format("|cFFCA3C3C%s|r %d", L["Count"], num)
+ elseif self.db.itemCount == "BANK_ONLY" then
+ bankCount = format("|cFFCA3C3C%s|r %d", L["Bank"], (numall - num))
+ elseif self.db.itemCount == "BOTH" then
+ right = format("|cFFCA3C3C%s|r %d", L["Count"], num)
+ bankCount = format("|cFFCA3C3C%s|r %d", L["Bank"], (numall - num))
+ end
+
+ if left or right then
+ tt:AddLine(" ")
+ tt:AddDoubleLine(left or " ", right or " ")
+ end
+ if bankCount then
+ tt:AddDoubleLine(" ", bankCount)
+ end
+
+ tt.itemCleared = true
+end
+
+function TT:GameTooltip_ShowStatusBar(tt)
+ local sb = _G[tt:GetName().."StatusBar"..tt.shownStatusBars]
+ if not sb or sb.backdrop then return end
+
+ sb:StripTextures()
+ sb:CreateBackdrop(nil, nil, true)
+ sb:SetStatusBarTexture(E.media.normTex)
+end
+
+function TT:CheckBackdropColor(tt)
+ if tt:GetAnchorType() == "ANCHOR_CURSOR" then
+ local r, g, b = unpack(E.media.backdropfadecolor, 1, 3)
+ tt:SetBackdropColor(r, g, b, self.db.colorAlpha)
+ end
+end
+
+function TT:SetStyle(tt)
+ if not tt.template then
+ tt:SetTemplate("Transparent")
+ else
+ tt:SetBackdropBorderColor(unpack(E.media.bordercolor, 1, 3))
+ end
+
+ local r, g, b = unpack(E.media.backdropfadecolor, 1, 3)
+ tt:SetBackdropColor(r, g, b, self.db.colorAlpha)
+end
+
+function TT:MODIFIER_STATE_CHANGED(_, key)
+ if updateUnitModifiers[key] then
+ local owner = GameTooltip:GetOwner()
+ local notOnAuras = not (owner and owner.UpdateTooltip)
+ if notOnAuras and UnitExists("mouseover") then
+ GameTooltip:SetUnit("mouseover")
+ end
+ end
+end
+
+function TT:SetUnitAura(tt, ...)
+ local caster, _, _, id = select(8, UnitAura(...))
+ if id and self.db.spellID then
+ if caster then
+ local name = UnitName(caster)
+ local color = E.media.herocolor
+ tt:AddDoubleLine(format("|cFFCA3C3C%s|r %d", ID, id), format("%s%s", E:RGBToHex(color.r, color.g, color.b), name))
+ else
+ tt:AddLine(format("|cFFCA3C3C%s|r %d", ID, id))
+ end
+
+ tt:Show()
+ end
+end
+
+function TT:GameTooltip_OnTooltipSetSpell(tt)
+ local id = select(3, tt:GetSpell())
+ if not id or not self.db.spellID then return end
+
+ local displayString = format("|cFFCA3C3C%s|r %d", ID, id)
+
+ for i = 1, tt:NumLines() do
+ local line = _G[format("GameTooltipTextLeft%d", i)]
+ if line and line:GetText() and find(line:GetText(), displayString) then
+ return
+ end
+ end
+
+ tt:AddLine(displayString)
+ tt:Show()
+end
+
+function TT:SetHyperlink(refTooltip, link)
+ if self.db.spellID and (find(link, "^spell:") or find(link, "^item:")) then
+ refTooltip:AddLine(format("|cFFCA3C3C%s|r %d", ID, tonumber(match(link, "(%d+)"))))
+ refTooltip:Show()
+ end
+end
+
+function TT:SetTooltipFonts()
+ local font = E.Libs.LSM:Fetch("font", E.db.tooltip.font)
+ local fontOutline = E.db.tooltip.fontOutline
+ local headerSize = E.db.tooltip.headerFontSize
+ local textSize = E.db.tooltip.textFontSize
+ local smallTextSize = E.db.tooltip.smallTextFontSize
+
+ GameTooltipHeaderText:FontTemplate(font, headerSize, fontOutline)
+ GameTooltipText:FontTemplate(font, textSize, fontOutline)
+ GameTooltipTextSmall:FontTemplate(font, smallTextSize, fontOutline)
+ if GameTooltip.hasMoney then
+ for i = 1, GameTooltip.numMoneyFrames do
+ _G["GameTooltipMoneyFrame"..i.."PrefixText"]:FontTemplate(font, textSize, fontOutline)
+ _G["GameTooltipMoneyFrame"..i.."SuffixText"]:FontTemplate(font, textSize, fontOutline)
+ _G["GameTooltipMoneyFrame"..i.."GoldButtonText"]:FontTemplate(font, textSize, fontOutline)
+ _G["GameTooltipMoneyFrame"..i.."SilverButtonText"]:FontTemplate(font, textSize, fontOutline)
+ _G["GameTooltipMoneyFrame"..i.."CopperButtonText"]:FontTemplate(font, textSize, fontOutline)
+ end
+ end
+
+ -- Ignore header font size on DatatextTooltip
+ if DatatextTooltip then
+ DatatextTooltipTextLeft1:FontTemplate(font, textSize, fontOutline)
+ DatatextTooltipTextRight1:FontTemplate(font, textSize, fontOutline)
+ end
+
+ --These show when you compare items ("Currently Equipped", name of item, item level)
+ --Since they appear at the top of the tooltip, we set it to use the header font size.
+ for i = 1, 2 do
+ for j = 1, 4 do
+ _G["ShoppingTooltip"..i.."TextLeft"..j]:FontTemplate(font, headerSize, fontOutline)
+ _G["ShoppingTooltip"..i.."TextRight"..j]:FontTemplate(font, headerSize, fontOutline)
+ end
+ end
+end
+
+--This changes the growth direction of the toast frame depending on position of the mover
+local function PostBNToastMove(mover)
+ local x, y = mover:GetCenter()
+ local screenHeight = E.UIParent:GetTop()
+ local screenWidth = E.UIParent:GetRight()
+
+ local anchorPoint
+ if y > (screenHeight / 2) then
+ anchorPoint = (x > (screenWidth / 2)) and "TOPRIGHT" or "TOPLEFT"
+ else
+ anchorPoint = (x > (screenWidth / 2)) and "BOTTOMRIGHT" or "BOTTOMLEFT"
+ end
+ mover.anchorPoint = anchorPoint
+
+ BNToastFrame:ClearAllPoints()
+ BNToastFrame:Point(anchorPoint, mover)
+end
+
+function TT:RepositionBNET(frame, _, anchor)
+ if anchor ~= BNETMover then
+ frame:ClearAllPoints()
+ frame:Point("TOPLEFT", BNETMover, "TOPLEFT")
+ end
+end
+
+function TT:Initialize()
+ self.db = E.db.tooltip
+
+ BNToastFrame:Point("TOPRIGHT", MMHolder, "BOTTOMRIGHT", 0, -10)
+ E:CreateMover(BNToastFrame, "BNETMover", L["BNet Frame"], nil, nil, PostBNToastMove)
+ self:SecureHook(BNToastFrame, "SetPoint", "RepositionBNET")
+
+ if not E.private.tooltip.enable then return end
+
+ SetCVar("showItemLevel", 1)
+
+ GameTooltip.StatusBar = GameTooltipStatusBar
+ GameTooltip.StatusBar:Height(self.db.healthBar.height)
+ GameTooltip.StatusBar:SetScript("OnValueChanged", nil)
+ GameTooltip.StatusBar.text = GameTooltip.StatusBar:CreateFontString(nil, "OVERLAY")
+ GameTooltip.StatusBar.text:Point("CENTER", GameTooltip.StatusBar, 0, 0)
+ GameTooltip.StatusBar.text:FontTemplate(E.Libs.LSM:Fetch("font", self.db.healthBar.font), self.db.healthBar.fontSize, self.db.healthBar.fontOutline)
+
+ --Tooltip Fonts
+ if not GameTooltip.hasMoney then
+ --Force creation of the money lines, so we can set font for it
+ SetTooltipMoney(GameTooltip, 1, nil, "", "")
+ SetTooltipMoney(GameTooltip, 1, nil, "", "")
+ GameTooltip_ClearMoney(GameTooltip)
+ end
+ self:SetTooltipFonts()
+
+ local GameTooltipAnchor = CreateFrame("Frame", "GameTooltipAnchor", E.UIParent)
+ GameTooltipAnchor:Point("BOTTOMRIGHT", RightChatToggleButton, "BOTTOMRIGHT")
+ GameTooltipAnchor:Size(130, 20)
+ GameTooltipAnchor:SetFrameLevel(GameTooltipAnchor:GetFrameLevel() + 400)
+ E:CreateMover(GameTooltipAnchor, "TooltipMover", L["Tooltip"], nil, nil, nil, nil, nil, "tooltip,general")
+
+ self:SecureHook(ItemRefTooltip, "SetHyperlink")
+ self:SecureHook("GameTooltip_SetDefaultAnchor")
+ self:SecureHook(GameTooltip, "SetUnitAura")
+ self:SecureHook(GameTooltip, "SetUnitBuff", "SetUnitAura")
+ self:SecureHook(GameTooltip, "SetUnitDebuff", "SetUnitAura")
+ self:HookScript(GameTooltip, "OnTooltipSetSpell", "GameTooltip_OnTooltipSetSpell")
+ self:HookScript(GameTooltip, "OnTooltipCleared", "GameTooltip_OnTooltipCleared")
+ self:HookScript(GameTooltip, "OnTooltipSetItem", "GameTooltip_OnTooltipSetItem")
+ self:HookScript(GameTooltip, "OnTooltipSetUnit", "GameTooltip_OnTooltipSetUnit")
+ self:HookScript(GameTooltip.StatusBar, "OnValueChanged", "GameTooltipStatusBar_OnValueChanged")
+ self:RegisterEvent("MODIFIER_STATE_CHANGED")
+
+ --Variable is localized at top of file, then set here when we're sure the frame has been created
+ --Used to check if keybinding is active, if so then don"t hide tooltips on actionbars
+ keybindFrame = ElvUI_KeyBinder
+
+ self.Initialized = true
+end
+
+local function InitializeCallback()
+ TT:Initialize()
+end
+
+E:RegisterModule(TT:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/ConfigEnviroment.lua b/ElvUI/Modules/UnitFrames/ConfigEnviroment.lua
new file mode 100644
index 0000000..e382a32
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/ConfigEnviroment.lua
@@ -0,0 +1,315 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+
+--Lua functions
+local _G = _G
+local setmetatable, getfenv, setfenv = setmetatable, getfenv, setfenv
+local type, unpack, select, pairs = type, unpack, select, pairs
+local min, random = math.min, math.random
+local find, format = string.find, string.format
+--WoW API / Variables
+local UnitPower = UnitPower
+local UnitPowerMax = UnitPowerMax
+local UnitHealth = UnitHealth
+local UnitHealthMax = UnitHealthMax
+local UnitName = UnitName
+local UnitClass = UnitClass
+local InCombatLockdown = InCombatLockdown
+local UnregisterUnitWatch = UnregisterUnitWatch
+local RegisterUnitWatch = RegisterUnitWatch
+local RegisterStateDriver = RegisterStateDriver
+local LOCALIZED_CLASS_NAMES_MALE = LOCALIZED_CLASS_NAMES_MALE
+local CLASS_SORT_ORDER = CLASS_SORT_ORDER
+local MAX_RAID_MEMBERS = MAX_RAID_MEMBERS
+
+local attributeBlacklist = {["showRaid"] = true, ["showParty"] = true, ["showSolo"] = true}
+local configEnv
+local originalEnvs = {}
+local overrideFuncs = {}
+
+local function createConfigEnv()
+ if configEnv then return end
+ configEnv = setmetatable({
+ UnitPower = function (unit, displayType)
+ if find(unit, "target") or find(unit, "focus") then
+ return UnitPower(unit, displayType)
+ end
+
+ return random(1, UnitPowerMax(unit, displayType) or 1)
+ end,
+ UnitHealth = function(unit)
+ if find(unit, "target") or find(unit, "focus") then
+ return UnitHealth(unit)
+ end
+
+ return random(1, UnitHealthMax(unit))
+ end,
+ UnitName = function(unit)
+ if find(unit, "target") or find(unit, "focus") then
+ return UnitName(unit)
+ end
+ if E.CreditsList then
+ local max = #E.CreditsList
+ return E.CreditsList[random(1, max)]
+ end
+ return "Test Name"
+ end,
+ UnitClass = function(unit)
+ if find(unit, "target") or find(unit, "focus") then
+ return UnitClass(unit)
+ end
+
+ local classToken = CLASS_SORT_ORDER[random(1, #(CLASS_SORT_ORDER))]
+ return LOCALIZED_CLASS_NAMES_MALE[classToken], classToken
+ end,
+ Hex = function(r, g, b)
+ if type(r) == "table" then
+ if r.r then r, g, b = r.r, r.g, r.b else r, g, b = unpack(r) end
+ end
+ return format("|cff%02x%02x%02x", r*255, g*255, b*255)
+ end,
+ ColorGradient = ElvUF.ColorGradient,
+ _COLORS = ElvUF.colors
+ }, {
+ __index = _G,
+ __newindex = function(_, key, value) _G[key] = value end,
+ })
+
+ overrideFuncs["namecolor"] = ElvUF.Tags.Methods["namecolor"]
+ overrideFuncs["name:veryshort"] = ElvUF.Tags.Methods["name:veryshort"]
+ overrideFuncs["name:short"] = ElvUF.Tags.Methods["name:short"]
+ overrideFuncs["name:medium"] = ElvUF.Tags.Methods["name:medium"]
+ overrideFuncs["name:long"] = ElvUF.Tags.Methods["name:long"]
+
+ overrideFuncs["healthcolor"] = ElvUF.Tags.Methods["healthcolor"]
+ overrideFuncs["health:current"] = ElvUF.Tags.Methods["health:current"]
+ overrideFuncs["health:deficit"] = ElvUF.Tags.Methods["health:deficit"]
+ overrideFuncs["health:current-percent"] = ElvUF.Tags.Methods["health:current-percent"]
+ overrideFuncs["health:current-max"] = ElvUF.Tags.Methods["health:current-max"]
+ overrideFuncs["health:current-max-percent"] = ElvUF.Tags.Methods["health:current-max-percent"]
+ overrideFuncs["health:max"] = ElvUF.Tags.Methods["health:max"]
+ overrideFuncs["health:percent"] = ElvUF.Tags.Methods["health:percent"]
+
+ overrideFuncs["powercolor"] = ElvUF.Tags.Methods["powercolor"]
+ overrideFuncs["power:current"] = ElvUF.Tags.Methods["power:current"]
+ overrideFuncs["power:deficit"] = ElvUF.Tags.Methods["power:deficit"]
+ overrideFuncs["power:current-percent"] = ElvUF.Tags.Methods["power:current-percent"]
+ overrideFuncs["power:current-max"] = ElvUF.Tags.Methods["power:current-max"]
+ overrideFuncs["power:current-max-percent"] = ElvUF.Tags.Methods["power:current-max-percent"]
+ overrideFuncs["power:max"] = ElvUF.Tags.Methods["power:max"]
+ overrideFuncs["power:percent"] = ElvUF.Tags.Methods["power:percent"]
+
+ overrideFuncs["energycolor"] = ElvUF.Tags.Methods["energycolor"]
+ overrideFuncs["energy:current"] = ElvUF.Tags.Methods["energy:current"]
+ overrideFuncs["energy:deficit"] = ElvUF.Tags.Methods["energy:deficit"]
+ overrideFuncs["energy:current-percent"] = ElvUF.Tags.Methods["energy:current-percent"]
+ overrideFuncs["energy:current-max"] = ElvUF.Tags.Methods["energy:current-max"]
+ overrideFuncs["energy:current-max-percent"] = ElvUF.Tags.Methods["energy:current-max-percent"]
+ overrideFuncs["energy:max"] = ElvUF.Tags.Methods["energy:max"]
+ overrideFuncs["energy:percent"] = ElvUF.Tags.Methods["energy:percent"]
+
+ overrideFuncs["ragecolor"] = ElvUF.Tags.Methods["ragecolor"]
+ overrideFuncs["rage:current"] = ElvUF.Tags.Methods["rage:current"]
+ overrideFuncs["rage:deficit"] = ElvUF.Tags.Methods["rage:deficit"]
+ overrideFuncs["rage:current-percent"] = ElvUF.Tags.Methods["rage:current-percent"]
+ overrideFuncs["rage:current-max"] = ElvUF.Tags.Methods["rage:current-max"]
+ overrideFuncs["rage:current-max-percent"] = ElvUF.Tags.Methods["rage:current-max-percent"]
+ overrideFuncs["rage:max"] = ElvUF.Tags.Methods["rage:max"]
+ overrideFuncs["rage:percent"] = ElvUF.Tags.Methods["rage:percent"]
+end
+
+function UF:ForceShow(frame)
+ if InCombatLockdown() then return end
+
+ if not frame.isForced then
+ frame.oldUnit = frame.unit
+ frame.unit = "player"
+ frame.isForced = true
+ frame.oldOnUpdate = frame:GetScript("OnUpdate")
+ end
+
+ frame:SetScript("OnUpdate", nil)
+ frame.forceShowAuras = true
+ UnregisterUnitWatch(frame)
+ RegisterUnitWatch(frame, true)
+
+ frame:Show()
+ if frame:IsVisible() and frame.Update then
+ frame:Update()
+ end
+
+ if _G[frame:GetName().."Target"] then
+ self:ForceShow(_G[frame:GetName().."Target"])
+ end
+
+ if _G[frame:GetName().."Pet"] then
+ self:ForceShow(_G[frame:GetName().."Pet"])
+ end
+end
+
+function UF:UnforceShow(frame)
+ if InCombatLockdown() then return end
+ if not frame.isForced then return end
+
+ frame.forceShowAuras = nil
+ frame.isForced = nil
+
+ -- Ask the SecureStateDriver to show/hide the frame for us
+ UnregisterUnitWatch(frame)
+ RegisterUnitWatch(frame)
+
+ if frame.oldOnUpdate then
+ frame:SetScript("OnUpdate", frame.oldOnUpdate)
+ frame.oldOnUpdate = nil
+ end
+
+ frame.unit = frame.oldUnit or frame.unit
+ -- If we're visible force an update so everything is properly in a
+ -- non-config mode state
+ if frame:IsVisible() and frame.Update then
+ frame:Update()
+ end
+
+ if _G[frame:GetName().."Target"] then
+ self:UnforceShow(_G[frame:GetName().."Target"])
+ end
+
+ if _G[frame:GetName().."Pet"] then
+ self:UnforceShow(_G[frame:GetName().."Pet"])
+ end
+end
+
+function UF:ShowChildUnits(header, ...)
+ header.isForced = true
+
+ for i = 1, select("#", ...) do
+ local frame = select(i, ...)
+ frame:RegisterForClicks(nil)
+ frame:SetID(i)
+ self:ForceShow(frame)
+ end
+end
+
+function UF:UnshowChildUnits(header, ...)
+ header.isForced = nil
+
+ for i = 1, select("#", ...) do
+ local frame = select(i, ...)
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+ self:UnforceShow(frame)
+ end
+end
+
+local function OnAttributeChanged(self)
+ if not self:GetParent().forceShow and not self.forceShow then return end
+ if not self:IsShown() then return end
+
+ local db = self.db or self:GetParent().db
+ local maxUnits = MAX_RAID_MEMBERS
+
+ local startingIndex = db.raidWideSorting and -(min(db.numGroups * (db.groupsPerRowCol * 5), maxUnits) + 1) or -4
+ if self:GetAttribute("startingIndex") ~= startingIndex then
+ self:SetAttribute("startingIndex", startingIndex)
+ UF:ShowChildUnits(self, self:GetChildren())
+ end
+end
+
+function UF:HeaderConfig(header, configMode)
+ if InCombatLockdown() then return end
+
+ createConfigEnv()
+ header.forceShow = configMode
+ header.forceShowAuras = configMode
+ header.isForced = configMode
+
+ if configMode then
+ for _, func in pairs(overrideFuncs) do
+ if type(func) == "function" then
+ if not originalEnvs[func] then
+ originalEnvs[func] = getfenv(func)
+ setfenv(func, configEnv)
+ end
+ end
+ end
+
+ RegisterStateDriver(header, "visibility", "show")
+ else
+ for func, env in pairs(originalEnvs) do
+ setfenv(func, env)
+ originalEnvs[func] = nil
+ end
+
+ RegisterStateDriver(header, "visibility", header.db.visibility)
+
+ if header:GetScript("OnEvent") then
+ header:GetScript("OnEvent")(header, "PLAYER_ENTERING_WORLD")
+ end
+ end
+
+ for i = 1, #header.groups do
+ local group = header.groups[i]
+
+ if group:IsShown() then
+ group.forceShow = header.forceShow
+ group.forceShowAuras = header.forceShowAuras
+ group:HookScript("OnAttributeChanged", OnAttributeChanged)
+ if configMode then
+ for key in pairs(attributeBlacklist) do
+ group:SetAttribute(key, nil)
+ end
+
+ OnAttributeChanged(group)
+
+ group:Update()
+ else
+ for key in pairs(attributeBlacklist) do
+ group:SetAttribute(key, true)
+ end
+
+ UF:UnshowChildUnits(group, group:GetChildren())
+ group:SetAttribute("startingIndex", 1)
+
+ group:Update()
+ end
+ end
+ end
+
+ UF.headerFunctions[header.groupName]:AdjustVisibility(header)
+end
+
+function UF:PLAYER_REGEN_DISABLED()
+ for _, header in pairs(UF.headers) do
+ if header.forceShow then
+ self:HeaderConfig(header)
+ end
+ end
+
+ for _, unit in pairs(UF.units) do
+ local frame = self[unit]
+ if frame and frame.forceShow then
+ self:UnforceShow(frame)
+ end
+ end
+
+ for i = 1, 5 do
+ if self["arena"..i] and self["arena"..i].isForced then
+ self:UnforceShow(self["arena"..i])
+ end
+ end
+
+ for i = 1, 4 do
+ if self["boss"..i] and self["boss"..i].isForced then
+ self:UnforceShow(self["boss"..i])
+ end
+ end
+
+ for i = 1, 4 do
+ if self["party"..i] and self["party"..i].isForced then
+ self:UnforceShow(self["party"..i])
+ end
+ end
+end
+
+UF:RegisterEvent("PLAYER_REGEN_DISABLED")
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/AuraBars.lua b/ElvUI/Modules/UnitFrames/Elements/AuraBars.lua
new file mode 100644
index 0000000..68775e7
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/AuraBars.lua
@@ -0,0 +1,280 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local tostring, select = tostring, select
+local format, strmatch, strsplit = string.format, strmatch, strsplit
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local IsShiftKeyDown = IsShiftKeyDown
+local IsAltKeyDown = IsAltKeyDown
+local IsControlKeyDown = IsControlKeyDown
+local UnitIsFriend = UnitIsFriend
+local UnitIsUnit = UnitIsUnit
+local UnitCanAttack = UnitCanAttack
+
+local function OnClick(self)
+ local mod = E.db.unitframe.auraBlacklistModifier
+ if mod == "NONE" or not ((mod == "SHIFT" and IsShiftKeyDown()) or (mod == "ALT" and IsAltKeyDown()) or (mod == "CTRL" and IsControlKeyDown())) then return end
+ local auraName = self:GetParent().aura.name
+
+ if auraName then
+ E:Print(format(L["The spell '%s' has been added to the Blacklist unitframe aura filter."], auraName))
+ E.global.unitframe.aurafilters.Blacklist.spells[auraName] = {enable = true, priority = 0}
+ UF:Update_AllFrames()
+ end
+end
+
+function UF:Construct_AuraBars()
+ local bar = self.statusBar
+
+ self:SetTemplate(nil, nil, nil, UF.thinBorders, true)
+ local inset = UF.thinBorders and E.mult or nil
+ bar:SetInside(self, inset, inset)
+ UF.statusbars[bar] = true
+ UF:Update_StatusBar(bar)
+
+ UF:Configure_FontString(bar.spelltime)
+ UF:Configure_FontString(bar.spellname)
+ UF:Update_FontString(bar.spelltime)
+ UF:Update_FontString(bar.spellname)
+
+ bar.spellname:ClearAllPoints()
+ bar.spellname:Point("LEFT", bar, "LEFT", 2, 0)
+ bar.spellname:Point("RIGHT", bar.spelltime, "LEFT", -4, 0)
+ bar.spellname:SetWordWrap(false)
+
+ bar.iconHolder:SetTemplate(nil, nil, nil, UF.thinBorders, true)
+ bar.icon:SetInside(bar.iconHolder, inset, inset)
+ bar.icon:SetDrawLayer("OVERLAY")
+
+ bar.bg = bar:CreateTexture(nil, "BORDER")
+ bar.bg:Show()
+
+ bar.iconHolder:RegisterForClicks("RightButtonUp")
+ bar.iconHolder:SetScript("OnClick", OnClick)
+end
+
+function UF:Construct_AuraBarHeader(frame)
+ local auraBar = CreateFrame("Frame", nil, frame)
+ auraBar:SetFrameLevel(frame.RaisedElementParent:GetFrameLevel() + 10) --Make them appear above any text element
+ auraBar.PostCreateBar = UF.Construct_AuraBars
+ auraBar.gap = (-frame.BORDER + frame.SPACING*3)
+ auraBar.spacing = (-frame.BORDER + frame.SPACING*3)
+ auraBar.spark = true
+ auraBar.filter = UF.AuraBarFilter
+ auraBar.PostUpdate = UF.ColorizeAuraBars
+
+ return auraBar
+end
+
+function UF:Configure_AuraBars(frame)
+ if not frame.VARIABLES_SET then return end
+
+ local auraBars = frame.AuraBars
+ local db = frame.db
+ if db.aurabar.enable then
+ if not frame:IsElementEnabled("AuraBars") then
+ frame:EnableElement("AuraBars")
+ end
+ auraBars:Show()
+ auraBars.friendlyAuraType = db.aurabar.friendlyAuraType
+ auraBars.enemyAuraType = db.aurabar.enemyAuraType
+ auraBars.scaleTime = db.aurabar.uniformThreshold
+
+ local buffColor = self.db.colors.auraBarBuff
+ local debuffColor = self.db.colors.auraBarDebuff
+ local attachTo = frame
+
+ if db.aurabar.attachTo == "BUFFS" then
+ attachTo = frame.Buffs
+ elseif db.aurabar.attachTo == "DEBUFFS" then
+ attachTo = frame.Debuffs
+ elseif db.aurabar.attachTo == "PLAYER_AURABARS" and ElvUF_Player then
+ attachTo = ElvUF_Player.AuraBars
+ end
+
+ local anchorPoint, anchorTo = "BOTTOM", "TOP"
+ if db.aurabar.anchorPoint == "BELOW" then
+ anchorPoint, anchorTo = "TOP", "BOTTOM"
+ end
+
+ local yOffset
+ local spacing = (((db.aurabar.attachTo == "FRAME" and 3) or (db.aurabar.attachTo == "PLAYER_AURABARS" and 4) or 2) * frame.SPACING)
+ local border = (((db.aurabar.attachTo == "FRAME" or db.aurabar.attachTo == "PLAYER_AURABARS") and 2 or 1) * frame.BORDER)
+
+ if db.aurabar.anchorPoint == "BELOW" then
+ yOffset = -spacing + border - (not db.aurabar.yOffset and 0 or db.aurabar.yOffset)
+ else
+ yOffset = spacing - border + (not db.aurabar.yOffset and 0 or db.aurabar.yOffset)
+ end
+
+ local xOffset = (db.aurabar.attachTo == "FRAME" and frame.SPACING or 0)
+ local offsetLeft = xOffset + ((db.aurabar.attachTo == "FRAME" and ((anchorTo == "TOP" and frame.ORIENTATION ~= "LEFT") or (anchorTo == "BOTTOM" and frame.ORIENTATION == "LEFT"))) and frame.POWERBAR_OFFSET or 0)
+ local offsetRight = -xOffset - ((db.aurabar.attachTo == "FRAME" and ((anchorTo == "TOP" and frame.ORIENTATION ~= "RIGHT") or (anchorTo == "BOTTOM" and frame.ORIENTATION == "RIGHT"))) and frame.POWERBAR_OFFSET or 0)
+
+ auraBars.auraBarHeight = db.aurabar.height
+ auraBars:ClearAllPoints()
+ auraBars:Point(anchorPoint.."LEFT", attachTo, anchorTo.."LEFT", offsetLeft, yOffset)
+ auraBars:Point(anchorPoint.."RIGHT", attachTo, anchorTo.."RIGHT", offsetRight, yOffset)
+ auraBars.buffColor = {buffColor.r, buffColor.g, buffColor.b}
+ if UF.db.colors.auraBarByType then
+ auraBars.debuffColor = nil
+ auraBars.defaultDebuffColor = {debuffColor.r, debuffColor.g, debuffColor.b}
+ else
+ auraBars.debuffColor = {debuffColor.r, debuffColor.g, debuffColor.b}
+ auraBars.defaultDebuffColor = nil
+ end
+ auraBars.down = db.aurabar.anchorPoint == "BELOW"
+
+ if db.aurabar.sort == "TIME_REMAINING" then
+ auraBars.sort = true --default function
+ elseif db.aurabar.sort == "TIME_REMAINING_REVERSE" then
+ auraBars.sort = self.SortAuraBarReverse
+ elseif db.aurabar.sort == "TIME_DURATION" then
+ auraBars.sort = self.SortAuraBarDuration
+ elseif db.aurabar.sort == "TIME_DURATION_REVERSE" then
+ auraBars.sort = self.SortAuraBarDurationReverse
+ elseif db.aurabar.sort == "NAME" then
+ auraBars.sort = self.SortAuraBarName
+ else
+ auraBars.sort = nil
+ end
+
+ auraBars.maxBars = db.aurabar.maxBars
+ auraBars.forceShow = frame.forceShowAuras
+ auraBars.spacing = ((-frame.BORDER + frame.SPACING*3) + db.aurabar.spacing)
+ auraBars:SetAnchors()
+ else
+ if frame:IsElementEnabled("AuraBars") then
+ frame:DisableElement("AuraBars")
+ auraBars:Hide()
+ end
+ end
+end
+
+local huge = math.huge
+function UF.SortAuraBarReverse(a, b)
+ local compa, compb = a.noTime and huge or a.expirationTime, b.noTime and huge or b.expirationTime
+ return compa < compb
+end
+
+function UF.SortAuraBarDuration(a, b)
+ local compa, compb = a.noTime and huge or a.duration, b.noTime and huge or b.duration
+ return compa > compb
+end
+
+function UF.SortAuraBarDurationReverse(a, b)
+ local compa, compb = a.noTime and huge or a.duration, b.noTime and huge or b.duration
+ return compa < compb
+end
+
+function UF.SortAuraBarName(a, b)
+ return a.name > b.name
+end
+
+function UF:CheckFilter(name, caster, spellID, isFriend, isPlayer, isUnit, allowDuration, noDuration, canDispell, ...)
+ for i = 1, select("#", ...) do
+ local filterName = select(i, ...)
+ local friendCheck = (isFriend and strmatch(filterName, "^Friendly:([^,]*)")) or (not isFriend and strmatch(filterName, "^Enemy:([^,]*)")) or nil
+ if friendCheck ~= false then
+ if friendCheck ~= nil and (G.unitframe.specialFilters[friendCheck] or E.global.unitframe.aurafilters[friendCheck]) then
+ filterName = friendCheck -- this is for our filters to handle Friendly and Enemy
+ end
+ local filter = E.global.unitframe.aurafilters[filterName]
+ if filter then
+ local filterType = filter.type
+ local spellList = filter.spells
+ local spell = spellList and (spellList[spellID] or spellList[name])
+
+ if filterType and (filterType == "Whitelist") and (spell and spell.enable) and allowDuration then
+ return true, spell.priority -- this is the only difference from auarbars code
+ elseif filterType and (filterType == "Blacklist") and (spell and spell.enable) then
+ return false
+ end
+ elseif filterName == "Personal" and isPlayer and allowDuration then
+ return true
+ elseif filterName == "nonPersonal" and (not isPlayer) and allowDuration then
+ return true
+ elseif filterName == "CastByUnit" and (caster and isUnit) and allowDuration then
+ return true
+ elseif filterName == "notCastByUnit" and (caster and not isUnit) and allowDuration then
+ return true
+ elseif filterName == "Dispellable" and canDispell and allowDuration then
+ return true
+ elseif filterName == "notDispellable" and (not canDispell) and allowDuration then
+ return true
+ elseif filterName == "blockNoDuration" and noDuration then
+ return false
+ elseif filterName == "blockNonPersonal" and (not isPlayer) then
+ return false
+ elseif filterName == "blockDispellable" and canDispell then
+ return false
+ elseif filterName == "blockNotDispellable" and (not canDispell) then
+ return false
+ end
+ end
+ end
+end
+
+function UF:AuraBarFilter(unit, name, _, _, _, debuffType, duration, _, unitCaster, isStealable, _, spellID)
+ if not self.db then return end
+ local db = self.db.aurabar
+
+ if not name then return nil end
+ local filterCheck, isUnit, isFriend, isPlayer, canDispell, allowDuration, noDuration
+
+ if db.priority ~= "" then
+ noDuration = (not duration or duration == 0)
+ isFriend = unit and UnitIsFriend("player", unit) and not UnitCanAttack("player", unit)
+ isPlayer = (unitCaster == "player" or unitCaster == "vehicle")
+ isUnit = unit and unitCaster and UnitIsUnit(unit, unitCaster)
+ canDispell = (self.type == "Buffs" and isStealable) or (self.type == "Debuffs" and debuffType)
+ allowDuration = noDuration or (duration and (duration > 0) and (db.maxDuration == 0 or duration <= db.maxDuration) and (db.minDuration == 0 or duration >= db.minDuration))
+ filterCheck = UF:CheckFilter(name, unitCaster, spellID, isFriend, isPlayer, isUnit, allowDuration, noDuration, canDispell, strsplit(",", db.priority))
+ else
+ filterCheck = true -- Allow all auras to be shown when the filter list is empty
+ end
+
+ return filterCheck
+end
+
+function UF:ColorizeAuraBars()
+ local bars = self.bars
+ for index = 1, #bars do
+ local frame = bars[index]
+ if not frame:IsVisible() then break end
+
+ local sb = frame.statusBar
+ local spellName = sb.aura.name
+ local spellID = sb.aura.spellID
+ local colors = E.global.unitframe.AuraBarColors[spellID] or E.global.unitframe.AuraBarColors[tostring(spellID)] or E.global.unitframe.AuraBarColors[spellName]
+
+ sb.custom_backdrop = UF.db.colors.customaurabarbackdrop and UF.db.colors.aurabar_backdrop
+ if E.db.unitframe.colors.auraBarTurtle and (E.global.unitframe.aurafilters.TurtleBuffs.spells[spellID] or E.global.unitframe.aurafilters.TurtleBuffs.spells[spellName]) and not colors then
+ colors = E.db.unitframe.colors.auraBarTurtleColor
+ end
+
+ if sb.bg then
+ if (UF.db.colors.transparentAurabars and not sb.isTransparent) or (sb.isTransparent and (not UF.db.colors.transparentAurabars or sb.invertColors ~= UF.db.colors.invertAurabars)) then
+ UF:ToggleTransparentStatusBar(UF.db.colors.transparentAurabars, sb, sb.bg, nil, UF.db.colors.invertAurabars)
+ else
+ local sbTexture = sb:GetStatusBarTexture()
+ if not sb.bg:GetTexture() then UF:Update_StatusBar(sb.bg, sbTexture:GetTexture()) end
+
+ UF:SetStatusBarBackdropPoints(sb, sbTexture, sb.bg)
+ end
+ end
+
+ if colors then
+ sb:SetStatusBarColor(colors.r, colors.g, colors.b)
+
+ if not sb.hookedColor then
+ UF.UpdateBackdropTextureColor(sb, colors.r, colors.g, colors.b)
+ end
+ else
+ local r, g, b = sb:GetStatusBarColor()
+ UF.UpdateBackdropTextureColor(sb, r, g, b)
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/Auras.lua b/ElvUI/Modules/UnitFrames/Elements/Auras.lua
new file mode 100644
index 0000000..a1f3bce
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/Auras.lua
@@ -0,0 +1,529 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local LSM = E.Libs.LSM
+
+--Lua functions
+local unpack = unpack
+local ceil = math.ceil
+local find, format, split = string.find, string.format, string.split
+local sort = table.sort
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local IsShiftKeyDown = IsShiftKeyDown
+local IsAltKeyDown = IsAltKeyDown
+local IsControlKeyDown = IsControlKeyDown
+local UnitCanAttack = UnitCanAttack
+local UnitIsFriend = UnitIsFriend
+local UnitIsUnit = UnitIsUnit
+
+function UF:Construct_Buffs(frame)
+ local buffs = CreateFrame("Frame", frame:GetName().."Buffs", frame)
+ buffs.spacing = E.Spacing
+ buffs.PreSetPosition = (not frame:GetScript("OnUpdate")) and self.SortAuras or nil
+ buffs.PostCreateIcon = self.Construct_AuraIcon
+ buffs.PostUpdateIcon = self.PostUpdateAura
+ buffs.CustomFilter = self.AuraFilter
+ buffs:SetFrameLevel(frame.RaisedElementParent:GetFrameLevel() + 10) --Make them appear above any text element
+ buffs.type = "buffs"
+ --Set initial width to prevent division by zero. This value doesn't matter, as it will be updated later
+ buffs:Width(100)
+
+ return buffs
+end
+
+function UF:Construct_Debuffs(frame)
+ local debuffs = CreateFrame("Frame", frame:GetName().."Debuffs", frame)
+ debuffs.spacing = E.Spacing
+ debuffs.PreSetPosition = (not frame:GetScript("OnUpdate")) and self.SortAuras or nil
+ debuffs.PostCreateIcon = self.Construct_AuraIcon
+ debuffs.PostUpdateIcon = self.PostUpdateAura
+ debuffs.CustomFilter = self.AuraFilter
+ debuffs.type = "debuffs"
+ debuffs:SetFrameLevel(frame.RaisedElementParent:GetFrameLevel() + 10) --Make them appear above any text element
+ --Set initial width to prevent division by zero. This value doesn't matter, as it will be updated later
+ debuffs:Width(100)
+
+ return debuffs
+end
+
+local function OnClick(btn)
+ local mod = E.db.unitframe.auraBlacklistModifier
+ if mod == "NONE" or not ((mod == "SHIFT" and IsShiftKeyDown()) or (mod == "ALT" and IsAltKeyDown()) or (mod == "CTRL" and IsControlKeyDown())) then return end
+ local auraName = btn.name
+
+ if auraName then
+ E:Print(format(L["The spell '%s' has been added to the Blacklist unitframe aura filter."], auraName))
+ E.global.unitframe.aurafilters.Blacklist.spells[btn.spellID] = {enable = true, priority = 0}
+
+ UF:Update_AllFrames()
+ end
+end
+
+function UF:Construct_AuraIcon(button)
+ local offset = UF.thinBorders and E.mult or E.Border
+ button:SetTemplate(nil, nil, nil, UF.thinBorders, true)
+
+ button.cd.noOCC = true
+ button.cd.noCooldownCount = true
+ button.cd:SetReverse(true)
+ button.cd:SetInside(button, offset, offset)
+
+ button.icon:SetInside(button, offset, offset)
+ button.icon:SetDrawLayer("ARTWORK")
+
+ button.count:ClearAllPoints()
+ button.count:Point("BOTTOMRIGHT", 1, 1)
+ button.count:SetJustifyH("RIGHT")
+
+ button.overlay:SetTexture()
+ button.stealable:SetTexture()
+
+ button:RegisterForClicks("RightButtonUp")
+ button:SetScript("OnClick", OnClick)
+
+ button.cd.CooldownOverride = "unitframe"
+ E:RegisterCooldown(button.cd)
+
+ local auras = button:GetParent()
+ local frame = auras:GetParent()
+ button.db = frame.db and frame.db[auras.type]
+
+ UF:UpdateAuraSettings(auras, button)
+end
+
+function UF:UpdateAuraSettings(auras, button)
+ if button.db then
+ button.count:FontTemplate(LSM:Fetch("font", button.db.countFont), button.db.countFontSize, button.db.countFontOutline)
+ end
+ if button.icon then
+ button.icon:SetTexCoord(unpack(E.TexCoords))
+ end
+
+ button:Size((auras and auras.size) or 30)
+
+ button.needsUpdateCooldownPosition = true
+end
+
+function UF:EnableDisable_Auras(frame)
+ if frame.db.debuffs.enable or frame.db.buffs.enable then
+ if not frame:IsElementEnabled("Auras") then
+ frame:EnableElement("Auras")
+ end
+ else
+ if frame:IsElementEnabled("Auras") then
+ frame:DisableElement("Auras")
+ end
+ end
+end
+
+local function ReverseUpdate(frame)
+ UF:Configure_Auras(frame, "Debuffs")
+ UF:Configure_Auras(frame, "Buffs")
+end
+
+function UF:UpdateAuraCooldownPosition(button)
+ button.cd.timer.text:ClearAllPoints()
+ local point = (button.db and button.db.durationPosition) or "CENTER"
+ if point == "CENTER" then
+ button.cd.timer.text:Point(point, 1, 0)
+ else
+ local bottom, right = find(point, "BOTTOM"), find(point, "RIGHT")
+ button.cd.timer.text:Point(point, right and -1 or 1, bottom and 1 or -1)
+ end
+
+ button.needsUpdateCooldownPosition = nil
+end
+
+function UF:Configure_Auras(frame, auraType)
+ if not frame.VARIABLES_SET then return end
+
+ local db = frame.db
+ local auras = frame[auraType]
+ auraType = string.lower(auraType)
+ auras.db = db[auraType]
+
+ local rows = auras.db.numrows
+ auras.forceShow = frame.forceShowAuras
+ auras.num = auras.db.perrow * rows
+ auras.size = auras.db.sizeOverride ~= 0 and auras.db.sizeOverride or ((((auras:GetWidth() - (auras.spacing*(auras.num/rows - 1))) / auras.num)) * rows)
+ auras.disableMouse = auras.db.clickThrough
+
+ if auras.db.sizeOverride and auras.db.sizeOverride > 0 then
+ auras:Width(auras.db.perrow * auras.db.sizeOverride)
+ else
+ local totalWidth = frame.UNIT_WIDTH - frame.SPACING*2
+ if frame.USE_POWERBAR_OFFSET then
+ if not (auras.db.attachTo == "POWER" and frame.ORIENTATION == "MIDDLE") then
+ local powerOffset = ((frame.ORIENTATION == "MIDDLE" and 2 or 1) * frame.POWERBAR_OFFSET)
+ totalWidth = totalWidth - powerOffset
+ end
+ end
+ auras:Width(totalWidth)
+ end
+
+ local index = 1
+ while auras[index] do
+ local button = auras[index]
+ if button then
+ button.db = auras.db
+ UF:UpdateAuraSettings(auras, button)
+ end
+
+ index = index + 1
+ end
+
+ local attachTo = self:GetAuraAnchorFrame(frame, auras.db.attachTo, db.debuffs.attachTo == "BUFFS" and db.buffs.attachTo == "DEBUFFS")
+ local x, y = E:GetXYOffset(auras.db.anchorPoint, frame.SPACING) --Use frame.SPACING override since it may be different from E.Spacing due to forced thin borders
+
+ if auras.db.attachTo == "FRAME" then
+ y = 0
+ elseif auras.db.attachTo == "HEALTH" or auras.db.attachTo == "POWER" then
+ local newX = E:GetXYOffset(auras.db.anchorPoint, -frame.BORDER)
+ local _, newY = E:GetXYOffset(auras.db.anchorPoint, (frame.BORDER + frame.SPACING))
+ x = newX
+ y = newY
+ else
+ x = 0
+ end
+
+ if (auraType == "buffs" and frame.Debuffs.attachTo and frame.Debuffs.attachTo == frame.Buffs and auras.db.attachTo == "DEBUFFS") then
+ --Update Debuffs first, as we would otherwise get conflicting anchor points
+ --This is usually only an issue on profile change
+ ReverseUpdate(frame)
+ return
+ end
+
+ auras:ClearAllPoints()
+ auras:Point(E.InversePoints[auras.db.anchorPoint], attachTo, auras.db.anchorPoint, x + auras.db.xOffset, y + auras.db.yOffset)
+ auras:Height(auras.size * rows)
+ auras["growth-y"] = find(auras.db.anchorPoint, "TOP") and "UP" or "DOWN"
+ auras["growth-x"] = auras.db.anchorPoint == "LEFT" and "LEFT" or auras.db.anchorPoint == "RIGHT" and "RIGHT" or (find(auras.db.anchorPoint, "LEFT") and "RIGHT" or "LEFT")
+ auras.initialAnchor = E.InversePoints[auras.db.anchorPoint]
+
+ --These are needed for SmartAuraPosition
+ auras.attachTo = attachTo
+ auras.point = E.InversePoints[auras.db.anchorPoint]
+ auras.anchorPoint = auras.db.anchorPoint
+ auras.xOffset = x + auras.db.xOffset
+ auras.yOffset = y + auras.db.yOffset
+
+ if auras.db.enable then
+ auras:Show()
+ else
+ auras:Hide()
+ end
+
+ local position = db.smartAuraPosition
+ if position == "BUFFS_ON_DEBUFFS" then
+ if db.debuffs.attachTo == "BUFFS" then
+ E:Print(format(L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."], L["Buffs"], L["Debuffs"], L["Frame"]))
+ db.debuffs.attachTo = "FRAME"
+ frame.Debuffs.attachTo = frame
+ end
+ db.buffs.attachTo = "DEBUFFS"
+ frame.Buffs.attachTo = frame.Debuffs
+ frame.Buffs.PostUpdate = nil
+ frame.Debuffs.PostUpdate = UF.UpdateBuffsHeaderPosition
+ elseif position == "DEBUFFS_ON_BUFFS" then
+ if db.buffs.attachTo == "DEBUFFS" then
+ E:Print(format(L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."], L["Debuffs"], L["Buffs"], L["Frame"]))
+ db.buffs.attachTo = "FRAME"
+ frame.Buffs.attachTo = frame
+ end
+ db.debuffs.attachTo = "BUFFS"
+ frame.Debuffs.attachTo = frame.Buffs
+ frame.Buffs.PostUpdate = UF.UpdateDebuffsHeaderPosition
+ frame.Debuffs.PostUpdate = nil
+ elseif position == "FLUID_BUFFS_ON_DEBUFFS" then
+ if db.debuffs.attachTo == "BUFFS" then
+ E:Print(format(L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."], L["Buffs"], L["Debuffs"], L["Frame"]))
+ db.debuffs.attachTo = "FRAME"
+ frame.Debuffs.attachTo = frame
+ end
+ db.buffs.attachTo = "DEBUFFS"
+ frame.Buffs.attachTo = frame.Debuffs
+ frame.Buffs.PostUpdate = UF.UpdateBuffsHeight
+ frame.Debuffs.PostUpdate = UF.UpdateBuffsPositionAndDebuffHeight
+ elseif position == "FLUID_DEBUFFS_ON_BUFFS" then
+ if db.buffs.attachTo == "DEBUFFS" then
+ E:Print(format(L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."], L["Debuffs"], L["Buffs"], L["Frame"]))
+ db.buffs.attachTo = "FRAME"
+ frame.Buffs.attachTo = frame
+ end
+ db.debuffs.attachTo = "BUFFS"
+ frame.Debuffs.attachTo = frame.Buffs
+ frame.Buffs.PostUpdate = UF.UpdateDebuffsPositionAndBuffHeight
+ frame.Debuffs.PostUpdate = UF.UpdateDebuffsHeight
+ else
+ frame.Buffs.PostUpdate = nil
+ frame.Debuffs.PostUpdate = nil
+ end
+end
+
+local function SortAurasByTime(a, b)
+ if a and b and a:GetParent().db then
+ if a:IsShown() and b:IsShown() then
+ local sortDirection = a:GetParent().db.sortDirection
+ local aTime = a.expiration or -1
+ local bTime = b.expiration or -1
+ if (aTime and bTime) then
+ if sortDirection == "DESCENDING" then
+ return aTime < bTime
+ else
+ return aTime > bTime
+ end
+ end
+ elseif a:IsShown() then
+ return true
+ end
+ end
+end
+
+local function SortAurasByName(a, b)
+ if a and b and a:GetParent().db then
+ if a:IsShown() and b:IsShown() then
+ local sortDirection = a:GetParent().db.sortDirection
+ local aName = a.spell or ""
+ local bName = b.spell or ""
+ if aName and bName then
+ if sortDirection == "DESCENDING" then
+ return aName < bName
+ else
+ return aName > bName
+ end
+ end
+ elseif a:IsShown() then
+ return true
+ end
+ end
+end
+
+local function SortAurasByDuration(a, b)
+ if a and b and a:GetParent().db then
+ if a:IsShown() and b:IsShown() then
+ local sortDirection = a:GetParent().db.sortDirection
+ local aTime = a.duration or -1
+ local bTime = b.duration or -1
+ if aTime and bTime then
+ if sortDirection == "DESCENDING" then
+ return aTime < bTime
+ else
+ return aTime > bTime
+ end
+ end
+ elseif a:IsShown() then
+ return true
+ end
+ end
+end
+
+local function SortAurasByCaster(a, b)
+ if a and b and a:GetParent().db then
+ if a:IsShown() and b:IsShown() then
+ local sortDirection = a:GetParent().db.sortDirection
+ local aPlayer = a.isPlayer or false
+ local bPlayer = b.isPlayer or false
+ if sortDirection == "DESCENDING" then
+ return (aPlayer and not bPlayer)
+ else
+ return (not aPlayer and bPlayer)
+ end
+ elseif a:IsShown() then
+ return true
+ end
+ end
+end
+
+function UF:SortAuras()
+ if not self.db then return end
+
+ --Sorting by Index is Default
+ if self.db.sortMethod == "TIME_REMAINING" then
+ sort(self, SortAurasByTime)
+ elseif self.db.sortMethod == "NAME" then
+ sort(self, SortAurasByName)
+ elseif self.db.sortMethod == "DURATION" then
+ sort(self, SortAurasByDuration)
+ elseif self.db.sortMethod == "PLAYER" then
+ sort(self, SortAurasByCaster)
+ end
+
+ --Look into possibly applying filter priorities for auras here.
+
+ return 1, #self --from/to range needed for the :SetPosition call in oUF aura element. Without this aura icon position gets all whacky when not sorted by index
+end
+
+local unstableAffliction = GetSpellInfo(30108)
+local vampiricTouch = GetSpellInfo(34914)
+function UF:PostUpdateAura(unit, button)
+ if button.isDebuff then
+ if not button.isFriend and not button.isPlayer then --[[and (not E.isDebuffWhiteList[name])]]
+ button:SetBackdropBorderColor(0.9, 0.1, 0.1)
+ button.icon:SetDesaturated((unit and not find(unit, "arena%d")) and true or false)
+ else
+ local color = (button.dtype and DebuffTypeColor[button.dtype]) or DebuffTypeColor.none
+ if button.name and (button.name == unstableAffliction or button.name == vampiricTouch) then
+ button:SetBackdropBorderColor(0.05, 0.85, 0.94)
+ else
+ button:SetBackdropBorderColor(color.r * 0.6, color.g * 0.6, color.b * 0.6)
+ end
+ button.icon:SetDesaturated(false)
+ end
+ else
+ if button.isStealable and not button.isFriend then
+ button:SetBackdropBorderColor(0.93, 0.91, 0.55, 1.0)
+ else
+ button:SetBackdropBorderColor(unpack(E.media.unitframeBorderColor))
+ end
+ end
+
+ if button.needsUpdateCooldownPosition and (button.cd and button.cd.timer and button.cd.timer.text) then
+ UF:UpdateAuraCooldownPosition(button)
+ end
+end
+
+function UF:AuraFilter(unit, button, name, _, _, _, debuffType, duration, expiration, caster, isStealable, _, spellID)
+ if not name then return end -- checking for an aura that is not there, pass nil to break while loop
+
+ local parent = self:GetParent()
+ local db = parent.db and parent.db[self.type]
+ if not db then return true end
+
+ local isPlayer = (caster == "player" or caster == "vehicle")
+ local isFriend = unit and UnitIsFriend("player", unit) and not UnitCanAttack("player", unit)
+
+ button.isPlayer = isPlayer
+ button.isFriend = isFriend
+ button.isStealable = isStealable
+ button.dtype = debuffType
+ button.duration = duration
+ button.expiration = expiration
+ button.name = name
+ button.spellID = spellID
+ button.owner = caster --what uses this?
+ button.spell = name --what uses this? (SortAurasByName?)
+ button.priority = 0
+
+ local noDuration = (not duration or duration == 0)
+ local allowDuration = noDuration or (duration and (duration > 0) and (db.maxDuration == 0 or duration <= db.maxDuration) and (db.minDuration == 0 or duration >= db.minDuration))
+ local filterCheck, spellPriority
+
+ if db.priority ~= "" then
+ local isUnit = unit and caster and UnitIsUnit(unit, caster)
+ local canDispell = (self.type == "buffs" and isStealable) or (self.type == "debuffs" and debuffType)
+ filterCheck, spellPriority = UF:CheckFilter(name, caster, spellID, isFriend, isPlayer, isUnit, allowDuration, noDuration, canDispell, split(",", db.priority))
+ if spellPriority then button.priority = spellPriority end -- this is the only difference from auarbars code
+ else
+ filterCheck = allowDuration and true -- Allow all auras to be shown when the filter list is empty, while obeying duration sliders
+ end
+
+ return filterCheck
+end
+
+function UF:UpdateBuffsHeaderPosition()
+ local parent = self:GetParent()
+ local buffs = parent.Buffs
+ local debuffs = parent.Debuffs
+ local numDebuffs = self.visibleDebuffs
+
+ if numDebuffs == 0 then
+ buffs:ClearAllPoints()
+ buffs:Point(debuffs.point, debuffs.attachTo, debuffs.anchorPoint, debuffs.xOffset, debuffs.yOffset)
+ else
+ buffs:ClearAllPoints()
+ buffs:Point(buffs.point, buffs.attachTo, buffs.anchorPoint, buffs.xOffset, buffs.yOffset)
+ end
+end
+
+function UF:UpdateDebuffsHeaderPosition()
+ local parent = self:GetParent()
+ local debuffs = parent.Debuffs
+ local buffs = parent.Buffs
+ local numBuffs = self.visibleBuffs
+
+ if numBuffs == 0 then
+ debuffs:ClearAllPoints()
+ debuffs:Point(buffs.point, buffs.attachTo, buffs.anchorPoint, buffs.xOffset, buffs.yOffset)
+ else
+ debuffs:ClearAllPoints()
+ debuffs:Point(debuffs.point, debuffs.attachTo, debuffs.anchorPoint, debuffs.xOffset, debuffs.yOffset)
+ end
+end
+
+function UF:UpdateBuffsPositionAndDebuffHeight()
+ local parent = self:GetParent()
+ local db = parent.db
+ local buffs = parent.Buffs
+ local debuffs = parent.Debuffs
+ local numDebuffs = self.visibleDebuffs
+
+ if numDebuffs == 0 then
+ buffs:ClearAllPoints()
+ buffs:Point(debuffs.point, debuffs.attachTo, debuffs.anchorPoint, debuffs.xOffset, debuffs.yOffset)
+ else
+ buffs:ClearAllPoints()
+ buffs:Point(buffs.point, buffs.attachTo, buffs.anchorPoint, buffs.xOffset, buffs.yOffset)
+ end
+
+ if numDebuffs > 0 then
+ local numRows = ceil(numDebuffs/db.debuffs.perrow)
+ debuffs:Height(debuffs.size * (numRows > db.debuffs.numrows and db.debuffs.numrows or numRows))
+ else
+ debuffs:Height(debuffs.size)
+ end
+end
+
+function UF:UpdateDebuffsPositionAndBuffHeight()
+ local parent = self:GetParent()
+ local db = parent.db
+ local debuffs = parent.Debuffs
+ local buffs = parent.Buffs
+ local numBuffs = self.visibleBuffs
+
+ if numBuffs == 0 then
+ debuffs:ClearAllPoints()
+ debuffs:Point(buffs.point, buffs.attachTo, buffs.anchorPoint, buffs.xOffset, buffs.yOffset)
+ else
+ debuffs:ClearAllPoints()
+ debuffs:Point(debuffs.point, debuffs.attachTo, debuffs.anchorPoint, debuffs.xOffset, debuffs.yOffset)
+ end
+
+ if numBuffs > 0 then
+ local numRows = ceil(numBuffs/db.buffs.perrow)
+ buffs:Height(buffs.size * (numRows > db.buffs.numrows and db.buffs.numrows or numRows))
+ else
+ buffs:Height(buffs.size)
+ end
+end
+
+function UF:UpdateBuffsHeight()
+ local parent = self:GetParent()
+ local db = parent.db
+ local buffs = parent.Buffs
+ local numBuffs = self.visibleBuffs
+
+ if numBuffs > 0 then
+ local numRows = ceil(numBuffs/db.buffs.perrow)
+ buffs:Height(buffs.size * (numRows > db.buffs.numrows and db.buffs.numrows or numRows))
+ else
+ buffs:Height(buffs.size)
+ -- Any way to get rid of the last row as well?
+ -- Using buffs:Height(0) makes frames anchored to this one disappear
+ end
+end
+
+function UF:UpdateDebuffsHeight()
+ local parent = self:GetParent()
+ local db = parent.db
+ local debuffs = parent.Debuffs
+ local numDebuffs = self.visibleDebuffs
+
+ if numDebuffs > 0 then
+ local numRows = ceil(numDebuffs/db.debuffs.perrow)
+ debuffs:Height(debuffs.size * (numRows > db.debuffs.numrows and db.debuffs.numrows or numRows))
+ else
+ debuffs:Height(debuffs.size)
+ -- Any way to get rid of the last row as well?
+ -- Using debuffs:Height(0) makes frames anchored to this one disappear
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/BuffIndicator.lua b/ElvUI/Modules/UnitFrames/Elements/BuffIndicator.lua
new file mode 100644
index 0000000..5a9b4e0
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/BuffIndicator.lua
@@ -0,0 +1,241 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local LSM = E.Libs.LSM
+
+--Lua functions
+local assert, select, pairs, unpack = assert, select, pairs, unpack
+local tinsert, wipe = tinsert, wipe
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetSpellInfo = GetSpellInfo
+
+function UF:Construct_AuraWatch(frame)
+ local auras = CreateFrame("Frame", nil, frame)
+ auras:SetFrameLevel(frame.RaisedElementParent:GetFrameLevel() + 10)
+ auras:SetInside(frame.Health)
+ auras.presentAlpha = 1
+ auras.missingAlpha = 0
+ auras.strictMatching = false
+ auras.icons = {}
+
+ return auras
+end
+
+local counterOffsets = {
+ ["TOPLEFT"] = {6, 1},
+ ["TOPRIGHT"] = {-6, 1},
+ ["BOTTOMLEFT"] = {6, 1},
+ ["BOTTOMRIGHT"] = {-6, 1},
+ ["LEFT"] = {6, 1},
+ ["RIGHT"] = {-6, 1},
+ ["TOP"] = {0, 0},
+ ["BOTTOM"] = {0, 0}
+}
+
+local textCounterOffsets = {
+ ["TOPLEFT"] = {"LEFT", "RIGHT", -2, 0},
+ ["TOPRIGHT"] = {"RIGHT", "LEFT", 2, 0},
+ ["BOTTOMLEFT"] = {"LEFT", "RIGHT", -2, 0},
+ ["BOTTOMRIGHT"] = {"RIGHT", "LEFT", 2, 0},
+ ["LEFT"] = {"LEFT", "RIGHT", -2, 0},
+ ["RIGHT"] = {"RIGHT", "LEFT", 2, 0},
+ ["TOP"] = {"RIGHT", "LEFT", 2, 0},
+ ["BOTTOM"] = {"RIGHT", "LEFT", 2, 0}
+}
+
+function UF:UpdateAuraWatchFromHeader(group, petOverride)
+ assert(self[group], "Invalid group specified.")
+ group = self[group]
+ for i = 1, group:GetNumChildren() do
+ local frame = select(i, group:GetChildren())
+ if frame and frame.Health then
+ UF:UpdateAuraWatch(frame, petOverride, group.db)
+ elseif frame then
+ for n = 1, frame:GetNumChildren() do
+ local child = select(n, frame:GetChildren())
+ if child and child.Health then
+ UF:UpdateAuraWatch(child, petOverride, group.db)
+ end
+ end
+ end
+ end
+end
+
+local buffs = {}
+function UF:UpdateAuraWatch(frame, petOverride, db)
+ wipe(buffs)
+ local auras = frame.AuraWatch
+ db = db and db.buffIndicator or frame.db.buffIndicator
+
+ if not db.enable then
+ auras:Hide()
+ return
+ else
+ auras:Show()
+ end
+
+ if frame.unit == "pet" and not petOverride then
+ local petWatch = E.global.unitframe.buffwatch.PET or {}
+ for _, value in pairs(petWatch) do
+ tinsert(buffs, value)
+ end
+ else
+ local buffWatch = not db.profileSpecific and (E.global.unitframe.buffwatch[E.myclass] or {}) or (E.db.unitframe.filters.buffwatch or {})
+ for _, value in pairs(buffWatch) do
+ tinsert(buffs, value)
+ end
+ end
+
+ --CLEAR CACHE
+ if auras.icons then
+ for i = 1, #auras.icons do
+ local matchFound = false
+ for j = 1, #buffs do
+ if buffs[j].id and buffs[j].id == auras.icons[i] then
+ matchFound = true
+ break
+ end
+ end
+
+ if not matchFound then
+ auras.icons[i]:Hide()
+ auras.icons[i] = nil
+ end
+ end
+ end
+
+ local unitframeFont = LSM:Fetch("font", E.db.unitframe.font)
+
+ for i = 1, #buffs do
+ if buffs[i].id then
+ local name, _, image = GetSpellInfo(buffs[i].id)
+ if name then
+ local icon
+ if not auras.icons[buffs[i].id] then
+ icon = CreateFrame("Frame", nil, auras)
+ else
+ icon = auras.icons[buffs[i].id]
+ end
+ icon.name = name
+ icon.image = image
+ icon.spellID = buffs[i].id
+ icon.anyUnit = buffs[i].anyUnit
+ icon.style = buffs[i].style
+ icon.onlyShowMissing = buffs[i].onlyShowMissing
+ icon.presentAlpha = icon.onlyShowMissing and 0 or 1
+ icon.missingAlpha = icon.onlyShowMissing and 1 or 0
+ icon.textThreshold = buffs[i].textThreshold or -1
+ icon.displayText = buffs[i].displayText
+ icon.decimalThreshold = buffs[i].decimalThreshold
+ icon.size = (buffs[i].sizeOverride ~= nil and buffs[i].sizeOverride > 0 and buffs[i].sizeOverride or db.size)
+
+ icon:Width(icon.size)
+ icon:Height(icon.size)
+ --Protect against missing .point value
+ if not buffs[i].point then buffs[i].point = "TOPLEFT" end
+
+ icon:ClearAllPoints()
+ icon:Point(buffs[i].point or "TOPLEFT", frame.Health, buffs[i].point or "TOPLEFT", buffs[i].xOffset, buffs[i].yOffset)
+
+ if not icon.icon then
+ icon.icon = icon:CreateTexture(nil, "BORDER")
+ icon.icon:SetAllPoints(icon)
+ end
+
+ if not icon.text then
+ local f = CreateFrame("Frame", nil, icon)
+ f:SetFrameLevel(icon:GetFrameLevel() + 50)
+ icon.text = f:CreateFontString(nil, "BORDER")
+ end
+
+ if not icon.border then
+ icon.border = icon:CreateTexture(nil, "BACKGROUND")
+ icon.border:Point("TOPLEFT", -E.mult, E.mult)
+ icon.border:Point("BOTTOMRIGHT", E.mult, -E.mult)
+ icon.border:SetTexture(E.media.blankTex)
+ icon.border:SetVertexColor(0, 0, 0)
+ end
+
+ if not icon.cd then
+ icon.cd = CreateFrame("Cooldown", nil, icon, "CooldownFrameTemplate")
+ icon.cd:SetAllPoints(icon)
+ icon.cd.noOCC = true
+ icon.cd.noCooldownCount = true
+ icon.cd:SetReverse(true)
+ icon.cd:SetFrameLevel(icon:GetFrameLevel())
+ end
+
+ if icon.style == "coloredIcon" then
+ icon.icon:SetTexture(E.media.blankTex)
+
+ if buffs[i].color then
+ icon.icon:SetVertexColor(buffs[i].color.r, buffs[i].color.g, buffs[i].color.b)
+ else
+ icon.icon:SetVertexColor(0.8, 0.8, 0.8)
+ end
+ icon.icon:Show()
+ icon.border:Show()
+ icon.cd:SetAlpha(1)
+ elseif icon.style == "texturedIcon" then
+ icon.icon:SetVertexColor(1, 1, 1)
+ --icon.icon:SetTexCoord(.18, .82, .18, .82)
+ icon.icon:SetTexCoord(unpack(E.TexCoords))
+ icon.icon:SetTexture(icon.image)
+ icon.icon:Show()
+ icon.border:Show()
+ icon.cd:SetAlpha(1)
+ else
+ icon.border:Hide()
+ icon.icon:Hide()
+ icon.cd:SetAlpha(0)
+ end
+
+ if icon.displayText then
+ icon.text:Show()
+ local r, g, b = 1, 1, 1
+ if buffs[i].textColor then
+ r, g, b = buffs[i].textColor.r, buffs[i].textColor.g, buffs[i].textColor.b
+ end
+
+ icon.text:SetTextColor(r, g, b)
+ else
+ icon.text:Hide()
+ end
+
+ if not icon.count then
+ icon.count = icon:CreateFontString(nil, "OVERLAY")
+ end
+
+ icon.count:ClearAllPoints()
+ if icon.displayText then
+ local point, anchorPoint, x, y = unpack(textCounterOffsets[buffs[i].point])
+ icon.count:Point(point, icon.text, anchorPoint, x, y)
+ else
+ icon.count:Point("CENTER", unpack(counterOffsets[buffs[i].point]))
+ end
+
+ icon.count:FontTemplate(unitframeFont, db.fontSize, E.db.unitframe.fontOutline)
+ icon.text:FontTemplate(unitframeFont, db.fontSize, E.db.unitframe.fontOutline)
+ icon.text:ClearAllPoints()
+ icon.text:Point(buffs[i].point, icon, buffs[i].point)
+
+ if buffs[i].enabled then
+ auras.icons[buffs[i].id] = icon
+ if auras.watched then
+ auras.watched[buffs[i].id] = icon
+ end
+ else
+ auras.icons[buffs[i].id] = nil
+ if auras.watched then
+ auras.watched[buffs[i].id] = nil
+ end
+ icon:Hide()
+ end
+ end
+ end
+ end
+
+ if frame.AuraWatch.Update then
+ frame.AuraWatch.Update(frame)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/CastBar.lua b/ElvUI/Modules/UnitFrames/Elements/CastBar.lua
new file mode 100644
index 0000000..cddad13
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/CastBar.lua
@@ -0,0 +1,423 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local unpack = unpack
+local abs, min = math.abs, math.min
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local UnitIsPlayer = UnitIsPlayer
+local UnitReaction = UnitReaction
+local UnitCanAttack = UnitCanAttack
+
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+local INVERT_ANCHORPOINT = {
+ TOPLEFT = "BOTTOMRIGHT",
+ LEFT = "RIGHT",
+ BOTTOMLEFT = "TOPRIGHT",
+ RIGHT = "LEFT",
+ TOPRIGHT = "BOTTOMLEFT",
+ BOTTOMRIGHT = "TOPLEFT",
+ CENTER = "CENTER",
+ TOP = "BOTTOM",
+ BOTTOM = "TOP"
+}
+
+local ticks = {}
+
+function UF:Construct_Castbar(frame, moverName)
+ local castbar = CreateFrame("StatusBar", nil, frame)
+ castbar:SetFrameLevel(frame.RaisedElementParent:GetFrameLevel() + 30) --Make it appear above everything else
+ self.statusbars[castbar] = true
+ castbar.CustomDelayText = self.CustomCastDelayText
+ castbar.CustomTimeText = self.CustomTimeText
+ castbar.PostCastStart = self.PostCastStart
+ castbar.PostCastStop = self.PostCastStop
+ castbar.PostCastInterruptible = self.PostCastInterruptible
+ castbar:SetClampedToScreen(true)
+ castbar:CreateBackdrop(nil, nil, nil, self.thinBorders, true)
+
+ castbar.Time = castbar:CreateFontString(nil, "OVERLAY")
+ self:Configure_FontString(castbar.Time)
+ castbar.Time:Point("RIGHT", castbar, "RIGHT", -4, 0)
+ castbar.Time:SetTextColor(0.84, 0.75, 0.65)
+ castbar.Time:SetJustifyH("RIGHT")
+
+ castbar.Text = castbar:CreateFontString(nil, "OVERLAY")
+ self:Configure_FontString(castbar.Text)
+ castbar.Text:Point("LEFT", castbar, "LEFT", 4, 0)
+ castbar.Text:SetTextColor(0.84, 0.75, 0.65)
+ castbar.Text:SetJustifyH("LEFT")
+ castbar.Text:SetWordWrap(false)
+
+ castbar.Spark_ = castbar:CreateTexture(nil, "OVERLAY")
+ castbar.Spark_:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
+ castbar.Spark_:SetBlendMode("ADD")
+ castbar.Spark_:SetVertexColor(1, 1, 1)
+ castbar.Spark_:Size(20, 40)
+
+ --Set to castbar.SafeZone
+ castbar.LatencyTexture = castbar:CreateTexture(nil, "OVERLAY")
+ castbar.LatencyTexture:SetTexture(E.media.blankTex)
+ castbar.LatencyTexture:SetVertexColor(0.69, 0.31, 0.31, 0.75)
+
+ castbar.bg = castbar:CreateTexture(nil, "BORDER")
+ castbar.bg:SetAllPoints()
+ castbar.bg:SetTexture(E.media.blankTex)
+ castbar.bg:Show()
+
+ local button = CreateFrame("Frame", nil, castbar)
+ local holder = CreateFrame("Frame", nil, castbar)
+ button:SetTemplate(nil, nil, nil, self.thinBorders, true)
+
+ castbar.Holder = holder
+ --these are placeholder so the mover can be created.. it will be changed.
+ castbar.Holder:Point("TOPLEFT", frame, "BOTTOMLEFT", 0, -(frame.BORDER - frame.SPACING))
+ castbar:Point("BOTTOMLEFT", castbar.Holder, "BOTTOMLEFT", frame.BORDER, frame.BORDER)
+ button:Point("RIGHT", castbar, "LEFT", -E.Spacing*3, 0)
+
+ if moverName then
+ local name = frame:GetName()
+ local configName = string.lower(string.gsub(name, "^ElvUF_", ""))
+ E:CreateMover(castbar.Holder, name.."CastbarMover", moverName, nil, -6, nil, "ALL,SOLO", nil, "unitframe,"..configName..",castbar")
+ end
+
+ local icon = button:CreateTexture(nil, "ARTWORK")
+ local offset = frame.BORDER --use frame.BORDER since it may be different from E.Border due to forced thin borders
+ icon:SetInside(nil, offset, offset)
+ icon.bg = button
+
+ --Set to castbar.Icon
+ castbar.ButtonIcon = icon
+
+ return castbar
+end
+
+function UF:Configure_Castbar(frame)
+ if not frame.VARIABLES_SET then return end
+ local castbar = frame.Castbar
+ local db = frame.db
+
+ if db.castbar.enable then
+ if not frame:IsElementEnabled("Castbar") then
+ frame:EnableElement("Castbar")
+ end
+
+ castbar:Width(db.castbar.width - ((frame.BORDER+frame.SPACING)*2))
+ castbar:Height(db.castbar.height - ((frame.BORDER+frame.SPACING)*2))
+ castbar.Holder:Width(db.castbar.width)
+ castbar.Holder:Height(db.castbar.height)
+
+ local color = E.db.unitframe.colors.borderColor
+ castbar.ButtonIcon.bg:SetBackdropBorderColor(color.r, color.g, color.b)
+
+ local oSC = castbar.Holder:GetScript("OnSizeChanged")
+ if oSC then oSC(castbar.Holder) end
+
+ if db.castbar.strataAndLevel and db.castbar.strataAndLevel.useCustomStrata then
+ castbar:SetFrameStrata(db.castbar.strataAndLevel.frameStrata)
+ end
+
+ if db.castbar.strataAndLevel and db.castbar.strataAndLevel.useCustomLevel then
+ castbar:SetFrameLevel(db.castbar.strataAndLevel.frameLevel)
+ end
+
+ castbar.timeToHold = db.castbar.timeToHold
+
+ --Latency
+ if db.castbar.latency then
+ castbar.SafeZone = castbar.LatencyTexture
+ castbar.LatencyTexture:Show()
+ else
+ castbar.SafeZone = nil
+ castbar.LatencyTexture:Hide()
+ end
+
+ --Icon
+ if db.castbar.icon then
+ castbar.Icon = castbar.ButtonIcon
+ castbar.Icon:SetTexCoord(unpack(E.TexCoords))
+
+ if not db.castbar.iconAttached then
+ castbar.Icon.bg:Size(db.castbar.iconSize)
+ else
+ if db.castbar.insideInfoPanel and frame.USE_INFO_PANEL then
+ castbar.Icon.bg:Size(db.infoPanel.height - frame.SPACING*2)
+ else
+ castbar.Icon.bg:Size(db.castbar.height - frame.SPACING*2)
+ end
+
+ castbar:Width(db.castbar.width - castbar.Icon.bg:GetWidth() - (frame.BORDER + frame.SPACING*5))
+ end
+
+ castbar.Icon.bg:Show()
+ else
+ castbar.ButtonIcon.bg:Hide()
+ castbar.Icon = nil
+ end
+
+ if db.castbar.spark then
+ castbar.Spark = castbar.Spark_
+ castbar.Spark:Point("CENTER", castbar:GetStatusBarTexture(), "RIGHT", 0, 0)
+ castbar.Spark:Height(db.castbar.height * 2)
+ elseif castbar.Spark then
+ castbar.Spark:Hide()
+ castbar.Spark = nil
+ end
+
+ castbar:ClearAllPoints()
+ if db.castbar.insideInfoPanel and frame.USE_INFO_PANEL then
+ if not db.castbar.iconAttached then
+ castbar:SetInside(frame.InfoPanel, 0, 0)
+ else
+ local iconWidth = db.castbar.icon and (castbar.Icon.bg:GetWidth() - frame.BORDER) or 0
+ if frame.ORIENTATION == "RIGHT" then
+ castbar:Point("TOPLEFT", frame.InfoPanel, "TOPLEFT")
+ castbar:Point("BOTTOMRIGHT", frame.InfoPanel, "BOTTOMRIGHT", -iconWidth - frame.SPACING*3, 0)
+ else
+ castbar:Point("TOPLEFT", frame.InfoPanel, "TOPLEFT", iconWidth + frame.SPACING*3, 0)
+ castbar:Point("BOTTOMRIGHT", frame.InfoPanel, "BOTTOMRIGHT")
+ end
+ end
+
+ if db.castbar.spark then
+ castbar.Spark:Height(db.infoPanel and db.infoPanel.height * 2) -- Grab the height from the infopanel.
+ end
+
+ if castbar.Holder.mover then
+ E:DisableMover(castbar.Holder.mover:GetName())
+ end
+ else
+ local isMoved = E:HasMoverBeenMoved(frame:GetName().."CastbarMover") or not castbar.Holder.mover
+ if not isMoved then
+ castbar.Holder.mover:ClearAllPoints()
+ end
+
+ castbar:ClearAllPoints()
+ if frame.ORIENTATION ~= "RIGHT" then
+ castbar:Point("BOTTOMRIGHT", castbar.Holder, "BOTTOMRIGHT", -(frame.BORDER+frame.SPACING), frame.BORDER+frame.SPACING)
+ if not isMoved then
+ castbar.Holder.mover:Point("TOPRIGHT", frame, "BOTTOMRIGHT", 0, -(frame.BORDER - frame.SPACING))
+ end
+ else
+ castbar:Point("BOTTOMLEFT", castbar.Holder, "BOTTOMLEFT", frame.BORDER+frame.SPACING, frame.BORDER+frame.SPACING)
+ if not isMoved then
+ castbar.Holder.mover:Point("TOPLEFT", frame, "BOTTOMLEFT", 0, -(frame.BORDER - frame.SPACING))
+ end
+ end
+
+ if castbar.Holder.mover then
+ E:EnableMover(castbar.Holder.mover:GetName())
+ end
+ end
+
+ if not db.castbar.iconAttached and db.castbar.icon then
+ local attachPoint = db.castbar.iconAttachedTo == "Frame" and frame or frame.Castbar
+ local anchorPoint = db.castbar.iconPosition
+ castbar.Icon.bg:ClearAllPoints()
+ castbar.Icon.bg:Point(INVERT_ANCHORPOINT[anchorPoint], attachPoint, anchorPoint, db.castbar.iconXOffset, db.castbar.iconYOffset)
+ elseif db.castbar.icon then
+ castbar.Icon.bg:ClearAllPoints()
+ if frame.ORIENTATION == "RIGHT" then
+ castbar.Icon.bg:Point("LEFT", castbar, "RIGHT", frame.SPACING*3, 0)
+ else
+ castbar.Icon.bg:Point("RIGHT", castbar, "LEFT", -frame.SPACING*3, 0)
+ end
+ end
+
+ --Adjust tick heights
+ castbar.tickHeight = castbar:GetHeight()
+
+ if db.castbar.ticks then --Only player unitframe has this
+ --Set tick width and color
+ castbar.tickWidth = db.castbar.tickWidth
+ castbar.tickColor = db.castbar.tickColor
+
+ for i = 1, #ticks do
+ ticks[i]:SetVertexColor(castbar.tickColor.r, castbar.tickColor.g, castbar.tickColor.b, castbar.tickColor.a)
+ ticks[i]:Width(castbar.tickWidth)
+ end
+ end
+
+ castbar.custom_backdrop = UF.db.colors.customcastbarbackdrop and UF.db.colors.castbar_backdrop
+ UF:ToggleTransparentStatusBar(UF.db.colors.transparentCastbar, castbar, castbar.bg, nil, UF.db.colors.invertCastbar)
+ else
+ if not db.castbar.enable and frame:IsElementEnabled("Castbar") then
+ frame:DisableElement("Castbar")
+
+ if castbar.Holder.mover then
+ E:DisableMover(castbar.Holder.mover:GetName())
+ end
+ end
+ end
+end
+
+function UF:CustomCastDelayText(duration)
+ local db = self:GetParent().db
+ if not (db and db.castbar) then return end
+ db = db.castbar.format
+
+ if self.channeling then
+ if db == "CURRENT" then
+ self.Time:SetFormattedText("%.1f |cffaf5050%.2f|r", abs(duration - self.max), self.delay)
+ elseif db == "CURRENTMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%.2f|r", abs(duration - self.max), self.max, self.delay)
+ elseif db == "REMAINING" then
+ self.Time:SetFormattedText("%.1f |cffaf5050%.2f|r", duration, self.delay)
+ elseif db == "REMAININGMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%.2f|r", duration, self.max, self.delay)
+ end
+ else
+ if db == "CURRENT" then
+ self.Time:SetFormattedText("%.1f |cffaf5050%s %.2f|r", duration, "+", self.delay)
+ elseif db == "CURRENTMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%s %.2f|r", duration, self.max, "+", self.delay)
+ elseif db == "REMAINING" then
+ self.Time:SetFormattedText("%.1f |cffaf5050%s %.2f|r", abs(duration - self.max), "+", self.delay)
+ elseif db == "REMAININGMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%s %.2f|r", abs(duration - self.max), self.max, "+", self.delay)
+ end
+ end
+end
+
+function UF:CustomTimeText(duration)
+ local db = self:GetParent().db
+ if not (db and db.castbar) then return end
+ db = db.castbar.format
+
+ if self.channeling then
+ if db == "CURRENT" then
+ self.Time:SetFormattedText("%.1f", abs(duration - self.max))
+ elseif db == "CURRENTMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f", abs(duration - self.max), self.max)
+ elseif db == "REMAINING" then
+ self.Time:SetFormattedText("%.1f", duration)
+ elseif db == "REMAININGMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f", duration, self.max)
+ end
+ else
+ if db == "CURRENT" then
+ self.Time:SetFormattedText("%.1f", duration)
+ elseif db == "CURRENTMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f", duration, self.max)
+ elseif db == "REMAINING" then
+ self.Time:SetFormattedText("%.1f", abs(duration - self.max))
+ elseif db == "REMAININGMAX" then
+ self.Time:SetFormattedText("%.1f / %.2f", abs(duration - self.max), self.max)
+ end
+ end
+end
+
+function UF:HideTicks()
+ for i = 1, #ticks do
+ ticks[i]:Hide()
+ end
+end
+
+function UF:SetCastTicks(frame, numTicks)
+ UF:HideTicks()
+ if numTicks and numTicks <= 0 then return end
+ local w = frame:GetWidth()
+ local d = w / numTicks
+
+ for i = 1, numTicks do
+ if not ticks[i] then
+ ticks[i] = frame:CreateTexture(nil, "OVERLAY")
+ ticks[i]:SetTexture(E.media.normTex)
+ E:RegisterStatusBar(ticks[i])
+ ticks[i]:SetVertexColor(frame.tickColor.r, frame.tickColor.g, frame.tickColor.b, frame.tickColor.a)
+ ticks[i]:Width(frame.tickWidth)
+ end
+
+ ticks[i]:Height(frame.tickHeight)
+ ticks[i]:ClearAllPoints()
+ ticks[i]:Point("RIGHT", frame, "LEFT", d * i, 0)
+ ticks[i]:Show()
+ end
+end
+
+function UF:PostCastStart(unit)
+ local db = self:GetParent().db
+ if not db or not db.castbar then return end
+
+ if unit == "vehicle" then unit = "player" end
+
+ if db.castbar.displayTarget and self.curTarget then
+ self.Text:SetText(self.spellName.." > "..self.curTarget)
+ end
+
+ -- Get length of Time, then calculate available length for Text
+ local timeWidth = self.Time:GetStringWidth()
+ local textWidth = self:GetWidth() - timeWidth - 10
+ local textStringWidth = self.Text:GetStringWidth()
+
+ if timeWidth == 0 or textStringWidth == 0 then
+ E:Delay(0.05, function() -- Delay may need tweaking
+ textWidth = self:GetWidth() - self.Time:GetStringWidth() - 10
+ textStringWidth = self.Text:GetStringWidth()
+ if textWidth > 0 then self.Text:Width(min(textWidth, textStringWidth)) end
+ end)
+ else
+ self.Text:Width(min(textWidth, textStringWidth))
+ end
+
+ self.unit = unit
+
+ if self.channeling and db.castbar.ticks and unit == "player" then
+ local unitframe = E.global.unitframe
+ local baseTicks = unitframe.ChannelTicks[self.spellName]
+
+ if baseTicks then
+ UF:SetCastTicks(self, baseTicks)
+ self.hadTicks = true
+ else
+ UF:HideTicks()
+ end
+ end
+
+ local colors = ElvUF.colors
+ local r, g, b = colors.castColor[1], colors.castColor[2], colors.castColor[3]
+
+ if (self.notInterruptible and unit ~= "player") and UnitCanAttack("player", unit) then
+ r, g, b = colors.castNoInterrupt[1], colors.castNoInterrupt[2], colors.castNoInterrupt[3]
+ elseif UF.db.colors.castClassColor and UnitIsPlayer(unit) then
+ local t = E.media.herocolor
+ if t then r, g, b = t[1], t[2], t[3] end
+ elseif UF.db.colors.castReactionColor then
+ local Reaction = UnitReaction(unit, "player")
+ local t = Reaction and ElvUF.colors.reaction[Reaction]
+ if t then r, g, b = t[1], t[2], t[3] end
+ end
+
+ self:SetStatusBarColor(r, g, b)
+end
+
+function UF:PostCastStop(unit)
+ if self.hadTicks and unit == "player" then
+ UF:HideTicks()
+ self.hadTicks = false
+ end
+end
+
+function UF:PostCastInterruptible(unit)
+ if unit == "vehicle" or unit == "player" then return end
+
+ local colors = ElvUF.colors
+ local r, g, b = colors.castColor[1], colors.castColor[2], colors.castColor[3]
+
+ if self.notInterruptible and UnitCanAttack("player", unit) then
+ r, g, b = colors.castNoInterrupt[1], colors.castNoInterrupt[2], colors.castNoInterrupt[3]
+ elseif UF.db.colors.castClassColor and UnitIsPlayer(unit) then
+ local t = E.media.herocolor
+ if t then r, g, b = t[1], t[2], t[3] end
+ elseif UF.db.colors.castReactionColor then
+ local Reaction = UnitReaction(unit, "player")
+ local t = Reaction and ElvUF.colors.reaction[Reaction]
+ if t then r, g, b = t[1], t[2], t[3] end
+ end
+
+ self:SetStatusBarColor(r, g, b)
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/ClassBars.lua b/ElvUI/Modules/UnitFrames/Elements/ClassBars.lua
new file mode 100644
index 0000000..d7a3d85
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/ClassBars.lua
@@ -0,0 +1,411 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local select = select
+local strfind, strsub, gsub = strfind, strsub, gsub
+local floor, max = floor, max
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+function UF:Configure_ClassBar(frame)
+ if not frame.VARIABLES_SET then return end
+ local bars = frame[frame.ClassBar]
+ if not bars then return end
+
+ local db = frame.db
+ bars.Holder = frame.ClassBarHolder
+ bars.origParent = frame
+
+ --Fix height in case it is lower than the theme allows, or in case it's higher than 30px when not detached
+ if (not self.thinBorders and not E.PixelMode) and frame.CLASSBAR_HEIGHT > 0 and frame.CLASSBAR_HEIGHT < 7 then --A height of 7 means 6px for borders and just 1px for the actual power statusbar
+ frame.CLASSBAR_HEIGHT = 7
+ if db.classbar then db.classbar.height = 7 end
+ UF.ToggleResourceBar(bars) --Trigger update to health if needed
+ elseif (self.thinBorders or E.PixelMode) and frame.CLASSBAR_HEIGHT > 0 and frame.CLASSBAR_HEIGHT < 3 then --A height of 3 means 2px for borders and just 1px for the actual power statusbar
+ frame.CLASSBAR_HEIGHT = 3
+ if db.classbar then db.classbar.height = 3 end
+ UF.ToggleResourceBar(bars) --Trigger update to health if needed
+ elseif (not frame.CLASSBAR_DETACHED and frame.CLASSBAR_HEIGHT > 30) then
+ frame.CLASSBAR_HEIGHT = 10
+ if db.classbar then db.classbar.height = 10 end
+ --Override visibility if Classbar is Additional Power in order to fix a bug when Auto Hide is enabled, height is higher than 30 and it goes from detached to not detached
+ local overrideVisibility = frame.ClassBar == "AdditionalPower"
+ UF.ToggleResourceBar(bars, overrideVisibility) --Trigger update to health if needed
+ end
+
+ --We don't want to modify the original frame.CLASSBAR_WIDTH value, as it bugs out when the classbar gains more buttons
+ local CLASSBAR_WIDTH = frame.CLASSBAR_WIDTH
+
+ if frame.USE_MINI_CLASSBAR and not frame.CLASSBAR_DETACHED then
+ if frame.MAX_CLASS_BAR == 1 or frame.ClassBar == "AdditionalPower" then
+ CLASSBAR_WIDTH = CLASSBAR_WIDTH * 2/3
+ else
+ CLASSBAR_WIDTH = CLASSBAR_WIDTH * (frame.MAX_CLASS_BAR - 1) / frame.MAX_CLASS_BAR
+ end
+ elseif frame.CLASSBAR_DETACHED then
+ CLASSBAR_WIDTH = db.classbar.detachedWidth - ((frame.BORDER + frame.SPACING) * 2)
+ end
+
+ bars:Width(CLASSBAR_WIDTH)
+ bars:Height(frame.CLASSBAR_HEIGHT - ((frame.BORDER + frame.SPACING) * 2))
+
+ local color = E.db.unitframe.colors.borderColor
+ bars.backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
+
+ if frame.ClassBar == "Runes" then
+ if (not frame.USE_MINI_CLASSBAR) and frame.USE_CLASSBAR then
+ bars.backdrop:Show()
+ else
+ bars.backdrop:Hide()
+ end
+ local maxClassBarButtons = max(UF.classMaxResourceBar[E.myclass] or 0)
+ for i = 1, maxClassBarButtons do
+ bars[i]:Hide()
+
+ if i <= frame.MAX_CLASS_BAR then
+ bars[i].backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
+ bars[i]:Height(bars:GetHeight())
+
+ if frame.MAX_CLASS_BAR == 1 then
+ bars[i]:Width(CLASSBAR_WIDTH)
+ elseif frame.USE_MINI_CLASSBAR then
+ if frame.CLASSBAR_DETACHED and db.classbar.orientation == "VERTICAL" then
+ bars[i]:Width(CLASSBAR_WIDTH)
+ else
+ bars[i]:Width((CLASSBAR_WIDTH - ((5 + (frame.BORDER * 2 + frame.SPACING * 2)) * (frame.MAX_CLASS_BAR - 1))) / frame.MAX_CLASS_BAR) --Width accounts for 5px spacing between each button, excluding borders
+ end
+ elseif i ~= frame.MAX_CLASS_BAR then
+ bars[i]:Width((CLASSBAR_WIDTH - ((frame.MAX_CLASS_BAR - 1) * (frame.BORDER-frame.SPACING))) / frame.MAX_CLASS_BAR) --classbar width minus total width of dividers between each button, divided by number of buttons
+ end
+
+ bars[i]:GetStatusBarTexture():SetHorizTile(false)
+ bars[i]:ClearAllPoints()
+ if i == 1 then
+ bars[i]:Point("LEFT", bars)
+ else
+ if frame.USE_MINI_CLASSBAR then
+ if frame.CLASSBAR_DETACHED and db.classbar.orientation == "VERTICAL" then
+ bars[i]:Point("BOTTOM", bars[i - 1], "TOP", 0, (db.classbar.spacing + frame.BORDER * 2 + frame.SPACING * 2))
+ elseif frame.CLASSBAR_DETACHED and db.classbar.orientation == "HORIZONTAL" then
+ bars[i]:Point("LEFT", bars[i - 1], "RIGHT", (db.classbar.spacing + frame.BORDER * 2 + frame.SPACING * 2), 0) --5px spacing between borders of each button(replaced with Detached Spacing option)
+ else
+ bars[i]:Point("LEFT", bars[i - 1], "RIGHT", (5 + frame.BORDER * 2 + frame.SPACING * 2), 0) --5px spacing between borders of each button
+ end
+ elseif i == frame.MAX_CLASS_BAR then
+ bars[i]:Point("LEFT", bars[i - 1], "RIGHT", frame.BORDER-frame.SPACING, 0)
+ bars[i]:Point("RIGHT", bars)
+ else
+ bars[i]:Point("LEFT", bars[i - 1], "RIGHT", frame.BORDER-frame.SPACING, 0)
+ end
+ end
+
+ if frame.CLASSBAR_DETACHED and db.classbar.verticalOrientation then
+ bars[i]:SetOrientation("VERTICAL")
+ else
+ bars[i]:SetOrientation("HORIZONTAL")
+ end
+
+ bars[i]:Show()
+ end
+ end
+ elseif frame.ClassBar == "AdditionalPower" then
+ if frame.CLASSBAR_DETACHED and db.classbar.verticalOrientation then
+ bars:SetOrientation("VERTICAL")
+ else
+ bars:SetOrientation("HORIZONTAL")
+ end
+ end
+
+ if frame.USE_MINI_CLASSBAR and not frame.CLASSBAR_DETACHED then
+ bars:ClearAllPoints()
+ bars:Point("CENTER", frame.Health.backdrop, "TOP", 0, 0)
+
+ bars:SetParent(frame)
+ bars:SetFrameLevel(50) --RaisedElementParent uses 100, we want it lower than this
+
+ if bars.Holder and bars.Holder.mover then
+ bars.Holder.mover:SetScale(0.0001)
+ bars.Holder.mover:SetAlpha(0)
+ end
+ elseif frame.CLASSBAR_DETACHED then
+ if frame.USE_MINI_CLASSBAR and not (frame.MAX_CLASS_BAR == 1 or frame.ClassBar == "AdditionalPower") then
+ local widthMult = UF.classMaxResourceBar[E.myclass] - 1
+ if db.classbar.orientation == "HORIZONTAL" then
+ bars.Holder:Size(db.classbar.detachedWidth + (db.classbar.spacing * widthMult) - (widthMult * 5), db.classbar.height)
+ else
+ bars.Holder:Size(db.classbar.detachedWidth, (db.classbar.height * UF.classMaxResourceBar[E.myclass]) + (db.classbar.spacing * widthMult))
+ end
+ else
+ bars.Holder:Size(db.classbar.detachedWidth, db.classbar.height)
+ end
+
+ if not bars.Holder.mover then
+ bars:ClearAllPoints()
+ bars:Point("BOTTOMLEFT", bars.Holder, "BOTTOMLEFT", frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING)
+ E:CreateMover(bars.Holder, "ClassBarMover", L["Classbar"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,player,classbar")
+ else
+ bars:ClearAllPoints()
+ bars:Point("BOTTOMLEFT", bars.Holder, "BOTTOMLEFT", frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING)
+ bars.Holder.mover:SetScale(1)
+ bars.Holder.mover:SetAlpha(1)
+ end
+
+ if db.classbar.parent == "UIPARENT" then
+ bars:SetParent(E.UIParent)
+ else
+ bars:SetParent(frame)
+ end
+
+ if not db.classbar.strataAndLevel.useCustomStrata then
+ bars:SetFrameStrata("LOW")
+ else
+ bars:SetFrameStrata(db.classbar.strataAndLevel.frameStrata)
+ end
+
+ if not db.classbar.strataAndLevel.useCustomLevel then
+ bars:SetFrameLevel(frame.Health:GetFrameLevel() + 10) --Health uses 10, Power uses (Health + 5) when attached
+ else
+ bars:SetFrameLevel(db.classbar.strataAndLevel.frameLevel)
+ end
+ else
+ bars:ClearAllPoints()
+
+ if frame.ORIENTATION == "RIGHT" then
+ bars:Point("BOTTOMRIGHT", frame.Health.backdrop, "TOPRIGHT", -frame.BORDER, frame.SPACING*3)
+ else
+ bars:Point("BOTTOMLEFT", frame.Health.backdrop, "TOPLEFT", frame.BORDER, frame.SPACING*3)
+ end
+
+ bars:SetParent(frame)
+ bars:SetFrameStrata("LOW")
+ bars:SetFrameLevel(frame.Health:GetFrameLevel() + 10) --Health uses 10, Power uses (Health + 5) when attached
+
+ if bars.Holder and bars.Holder.mover then
+ bars.Holder.mover:SetScale(0.0001)
+ bars.Holder.mover:SetAlpha(0)
+ end
+ end
+
+ if frame.USE_CLASSBAR then
+ if frame.AdditionalPower and not frame:IsElementEnabled("AdditionalPower") then
+ frame:EnableElement("AdditionalPower")
+ end
+ if frame.Runes and not frame:IsElementEnabled("Runes") then
+ frame:EnableElement("Runes")
+ end
+ else
+ if frame.AdditionalPower and frame:IsElementEnabled("AdditionalPower") then
+ frame:DisableElement("AdditionalPower")
+ end
+ if frame.Runes and frame:IsElementEnabled("Runes") then
+ frame:DisableElement("Runes")
+ end
+ end
+end
+
+local function ToggleResourceBar(bars, overrideVisibility)
+ local frame = bars.origParent or bars:GetParent()
+ local db = frame.db
+ if not db then return end
+
+ frame.CLASSBAR_SHOWN = (not not overrideVisibility) or bars:IsShown()
+
+ local height
+ if db.classbar then
+ height = db.classbar.height
+ elseif db.combobar then
+ height = db.combobar.height
+ elseif frame.AlternativePower then
+ height = db.power.height
+ end
+
+ if bars.text then
+ if frame.CLASSBAR_SHOWN then
+ bars.text:SetAlpha(1)
+ else
+ bars.text:SetAlpha(0)
+ end
+ end
+
+ frame.CLASSBAR_HEIGHT = (frame.USE_CLASSBAR and (frame.CLASSBAR_SHOWN and height) or 0)
+ frame.CLASSBAR_YOFFSET = (not frame.USE_CLASSBAR or not frame.CLASSBAR_SHOWN or frame.CLASSBAR_DETACHED) and 0 or (frame.USE_MINI_CLASSBAR and ((frame.SPACING+(frame.CLASSBAR_HEIGHT/2))) or (frame.CLASSBAR_HEIGHT - (frame.BORDER-frame.SPACING)))
+
+ if not frame.CLASSBAR_DETACHED then --Only update when necessary
+ UF:Configure_HealthBar(frame)
+ UF:Configure_Portrait(frame, true) --running :Hide on portrait makes the frame all funky
+ UF:Configure_Threat(frame)
+ end
+end
+UF.ToggleResourceBar = ToggleResourceBar --Make available to combobar
+
+-------------------------------------------------------------
+-- DEATHKNIGHT
+-------------------------------------------------------------
+function UF:Construct_DeathKnightResourceBar(frame)
+ local runes = CreateFrame("Frame", nil, frame)
+ runes:CreateBackdrop(nil, nil, nil, self.thinBorders, true)
+
+ for i = 1, UF.classMaxResourceBar[E.myclass] do
+ runes[i] = CreateFrame("StatusBar", frame:GetName().."RuneButton"..i, runes)
+ runes[i]:SetStatusBarTexture(E.media.blankTex)
+ runes[i]:GetStatusBarTexture():SetHorizTile(false)
+ UF.statusbars[runes[i]] = true
+
+ runes[i]:CreateBackdrop(nil, nil, nil, self.thinBorders, true)
+ runes[i].backdrop:SetParent(runes)
+ runes[i].backdrop:SetFrameLevel(runes[i]:GetFrameLevel() - 1)
+
+ runes[i].bg = runes[i]:CreateTexture(nil, "BORDER")
+ runes[i].bg:SetAllPoints()
+ runes[i].bg:SetTexture(E.media.blankTex)
+ runes[i].bg:SetParent(runes[i].backdrop)
+ runes[i].bg.multiplier = 0.35
+ end
+
+ runes.PostUpdateType = UF.PostUpdateRuneType
+ runes.PostUpdateVisibility = UF.PostVisibilityRunes
+
+ runes:SetScript("OnShow", ToggleResourceBar)
+ runes:SetScript("OnHide", ToggleResourceBar)
+
+ return runes
+end
+
+function UF:PostUpdateRuneType(rune)
+ local custom_backdrop = UF.db.colors.customclasspowerbackdrop and UF.db.colors.classpower_backdrop
+
+ if custom_backdrop then
+ rune.bg:SetVertexColor(custom_backdrop.r, custom_backdrop.g, custom_backdrop.b)
+ end
+end
+
+function UF:PostVisibilityRunes(enabled, stateChanged)
+ local frame = self.origParent or self:GetParent()
+
+ if enabled then
+ frame.MAX_CLASS_BAR = #self
+ end
+
+ if stateChanged then
+ ToggleResourceBar(frame[frame.ClassBar])
+ UF:Configure_ClassBar(frame)
+ UF:Configure_HealthBar(frame)
+ UF:Configure_Power(frame)
+ UF:Configure_InfoPanel(frame, true) --2nd argument is to prevent it from setting template, which removes threat border
+ end
+end
+
+-------------------------------------------------------------
+-- DRUID
+-------------------------------------------------------------
+function UF:Construct_AdditionalPowerBar(frame)
+ local additionalPower = CreateFrame("StatusBar", "AdditionalPowerBar", frame)
+ additionalPower:SetStatusBarTexture(E.media.blankTex)
+ UF.statusbars[additionalPower] = true
+
+ additionalPower.colorPower = true
+
+ additionalPower:CreateBackdrop(nil, nil, nil, self.thinBorders, true)
+
+ additionalPower.BG = additionalPower:CreateTexture(nil, "BORDER")
+ additionalPower.BG:SetAllPoints(additionalPower)
+ additionalPower.BG:SetTexture(E.media.blankTex)
+
+ additionalPower.text = additionalPower:CreateFontString(nil, "OVERLAY")
+ UF:Configure_FontString(additionalPower.text)
+
+ additionalPower.PostUpdate = UF.PostUpdateAdditionalPower
+ additionalPower.PostUpdateVisibility = UF.PostVisibilityAdditionalPower
+
+ additionalPower:SetScript("OnShow", ToggleResourceBar)
+ additionalPower:SetScript("OnHide", ToggleResourceBar)
+
+ return additionalPower
+end
+
+function UF:PostUpdateAdditionalPower(_, MIN, MAX, event)
+ local frame = self.origParent or self:GetParent()
+ local db = frame.db
+
+ if frame.USE_CLASSBAR and ((MIN ~= MAX or (not db.classbar.autoHide)) and (event ~= "ElementDisable")) then
+ if db.classbar.additionalPowerText then
+ local powerValue = frame.Power.value
+ local powerValueText = powerValue:GetText()
+ local powerValueParent = powerValue:GetParent()
+ local powerTextPosition = db.power.position
+ local color = ElvUF.colors.power.MANA
+ color = E:RGBToHex(color[1], color[2], color[3])
+
+ --Attempt to remove |cFFXXXXXX color codes in order to determine if power text is really empty
+ if powerValueText then
+ local _, endIndex = strfind(powerValueText, "|cff")
+ if endIndex then
+ endIndex = endIndex + 7 --Add hex code
+ powerValueText = strsub(powerValueText, endIndex)
+ powerValueText = gsub(powerValueText, "%s+", "")
+ end
+ end
+
+ self.text:ClearAllPoints()
+ if not frame.CLASSBAR_DETACHED then
+ self.text:SetParent(powerValueParent)
+ if powerValueText and (powerValueText ~= "" and powerValueText ~= " ") then
+ if strfind(powerTextPosition, "RIGHT") then
+ self.text:Point("RIGHT", powerValue, "LEFT", 3, 0)
+ self.text:SetFormattedText(color.."%d%%|r |cffD7BEA5- |r", floor(MIN / MAX * 100))
+ elseif strfind(powerTextPosition, "LEFT") then
+ self.text:Point("LEFT", powerValue, "RIGHT", -3, 0)
+ self.text:SetFormattedText("|cffD7BEA5 -|r"..color.." %d%%|r", floor(MIN / MAX * 100))
+ else
+ if select(4, powerValue:GetPoint()) <= 0 then
+ self.text:Point("LEFT", powerValue, "RIGHT", -3, 0)
+ self.text:SetFormattedText(" |cffD7BEA5-|r"..color.." %d%%|r", floor(MIN / MAX * 100))
+ else
+ self.text:Point("RIGHT", powerValue, "LEFT", 3, 0)
+ self.text:SetFormattedText(color.."%d%%|r |cffD7BEA5- |r", floor(MIN / MAX * 100))
+ end
+ end
+ else
+ self.text:Point(powerValue:GetPoint())
+ self.text:SetFormattedText(color.."%d%%|r", floor(MIN / MAX * 100))
+ end
+ else
+ self.text:SetParent(frame.RaisedElementParent) -- needs to be 'frame.RaisedElementParent' otherwise the new PowerPrediction Bar will overlap
+ self.text:Point("CENTER", self, 0, 1)
+ self.text:SetFormattedText(color.."%d%%|r", floor(MIN / MAX * 100))
+ end
+ else --Text disabled
+ self.text:SetText("")
+ end
+
+ local custom_backdrop = UF.db.colors.customclasspowerbackdrop and UF.db.colors.classpower_backdrop
+ if custom_backdrop then
+ self.BG:SetVertexColor(custom_backdrop.r, custom_backdrop.g, custom_backdrop.b)
+ else
+ local r, g, b = self:GetStatusBarColor()
+ self.BG:SetVertexColor(r * 0.35, g * 0.35, b * 0.35)
+ end
+
+ self:Show()
+ else --Bar disabled
+ self.text:SetText("")
+ self:Hide()
+ end
+end
+
+function UF:PostVisibilityAdditionalPower(enabled, stateChanged)
+ local frame = self.origParent or self:GetParent()
+
+ if stateChanged then
+ ToggleResourceBar(frame[frame.ClassBar])
+ UF:Configure_ClassBar(frame)
+ UF:Configure_HealthBar(frame)
+ UF:Configure_Power(frame)
+ UF:Configure_InfoPanel(frame, true) --2nd argument is to prevent it from setting template, which removes threat border
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/CombatIndicator.lua b/ElvUI/Modules/UnitFrames/Elements/CombatIndicator.lua
new file mode 100644
index 0000000..c34607f
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/CombatIndicator.lua
@@ -0,0 +1,54 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+
+local CombatTextures = {
+ ["COMBAT"] = E.Media.Textures.Combat,
+ ["DEFAULT"] = [[Interface\CharacterFrame\UI-StateIcon]],
+ ["ATTACK"] = [[Interface\CURSOR\Attack]],
+ ["ALERT"] = [[Interface\DialogFrame\UI-Dialog-Icon-AlertNew]],
+ ["ALERT2"] = [[Interface\OptionsFrame\UI-OptionsFrame-NewFeatureIcon]],
+ ["ARTHAS"] = [[Interface\LFGFRAME\UI-LFR-PORTRAIT]],
+ ["SKULL"] = [[Interface\LootFrame\LootPanel-Icon]],
+}
+
+function UF:Construct_CombatIndicator(frame)
+ return frame.RaisedElementParent.TextureParent:CreateTexture(nil, "OVERLAY")
+end
+
+function UF:Configure_CombatIndicator(frame)
+ if not frame.VARIABLES_SET then return end
+ local Icon = frame.CombatIndicator
+ local db = frame.db.CombatIcon
+
+ Icon:ClearAllPoints()
+ Icon:Point("CENTER", frame.Health, db.anchorPoint, db.xOffset, db.yOffset)
+ Icon:Size(db.size)
+
+ if db.defaultColor then
+ Icon:SetVertexColor(1, 1, 1, 1)
+ Icon:SetDesaturated(false)
+ else
+ Icon:SetVertexColor(db.color.r, db.color.g, db.color.b, db.color.a)
+ Icon:SetDesaturated(true)
+ end
+
+ if db.texture == "CUSTOM" and db.customTexture then
+ Icon:SetTexture(db.customTexture)
+ Icon:SetTexCoord(0, 1, 0, 1)
+ elseif db.texture ~= "DEFAULT" and CombatTextures[db.texture] then
+ Icon:SetTexture(CombatTextures[db.texture])
+ Icon:SetTexCoord(0, 1, 0, 1)
+ else
+ Icon:SetTexture(CombatTextures.DEFAULT)
+ Icon:SetTexCoord(.5, 1, 0, .49)
+ end
+
+ if db.enable and not frame:IsElementEnabled("CombatIndicator") then
+ frame:EnableElement("CombatIndicator")
+ elseif not db.enable and frame:IsElementEnabled("CombatIndicator") then
+ frame:DisableElement("CombatIndicator")
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/ComboPoints.lua b/ElvUI/Modules/UnitFrames/Elements/ComboPoints.lua
new file mode 100644
index 0000000..02e2487
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/ComboPoints.lua
@@ -0,0 +1,293 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetComboPoints = GetComboPoints
+local GetShapeshiftForm = GetShapeshiftForm
+local UnitHasVehicleUI = UnitHasVehicleUI
+local MAX_COMBO_POINTS = MAX_COMBO_POINTS
+
+local CombobarDetached
+function UF:CombobarDetachedUpdate()
+ if ElvUF_Target.CLASSBAR_DETACHED and UF.db.units.target.combobar.parent == "UIPARENT" then
+ if not CombobarDetached then
+ CombobarDetached = CreateFrame("Frame", nil, UIParent)
+
+ CombobarDetached:RegisterEvent("PLAYER_ENTERING_WORLD")
+ CombobarDetached:RegisterEvent("UNIT_ENTERED_VEHICLE")
+ CombobarDetached:RegisterEvent("UNIT_EXITING_VEHICLE")
+ CombobarDetached:RegisterEvent("UPDATE_SHAPESHIFT_FORM")
+
+ CombobarDetached:SetScript("OnEvent", function(self, event, unit)
+ if (event == "UNIT_ENTERED_VEHICLE" or event == "UNIT_EXITING_VEHICLE") and unit ~= "player" then return end
+
+ if event == "PLAYER_ENTERING_WORLD" then
+ E:ShapeshiftDelayedUpdate(ElvUF_Target.ComboPoints.Override, ElvUF_Target)
+ end
+
+ ElvUF_Target.ComboPoints.Override(ElvUF_Target, event, unit)
+ end)
+ end
+
+ CombobarDetached:Show()
+ elseif CombobarDetached then
+ CombobarDetached:Hide()
+ end
+end
+
+function UF:Construct_Combobar(frame)
+ local ComboPoints = CreateFrame("Frame", nil, frame)
+ ComboPoints:CreateBackdrop("Default", nil, nil, UF.thinBorders, true)
+ ComboPoints.backdrop:Hide()
+
+ for i = 1, MAX_COMBO_POINTS do
+ ComboPoints[i] = CreateFrame("StatusBar", frame:GetName().."ComboBarButton"..i, ComboPoints)
+ ComboPoints[i]:SetStatusBarTexture(E.media.blankTex)
+ UF.statusbars[ComboPoints[i]] = true
+ ComboPoints[i]:CreateBackdrop("Default", nil, nil, UF.thinBorders, true)
+ ComboPoints[i].backdrop:SetParent(ComboPoints)
+
+ ComboPoints[i].bg = ComboPoints[i]:CreateTexture(nil, "BORDER")
+ ComboPoints[i].bg:SetAllPoints()
+ ComboPoints[i].bg:SetTexture(E.media.blankTex)
+ ComboPoints[i].bg:SetParent(ComboPoints[i].backdrop)
+ end
+
+ frame:RegisterEvent("UNIT_ENTERED_VEHICLE", UF.UpdateComboDisplay)
+ frame:RegisterEvent("UNIT_EXITING_VEHICLE", UF.UpdateComboDisplay)
+
+ -- Do combo points change when you change forms on ascension?
+ frame:RegisterEvent("UPDATE_SHAPESHIFT_FORM", UF.UpdateComboDisplay)
+
+ frame:RegisterEvent("PLAYER_ENTERING_WORLD", function()
+ E:ShapeshiftDelayedUpdate(ElvUF_Target.ComboPoints.Override, ElvUF_Target)
+ end)
+
+ self:CombobarDetachedUpdate()
+
+ ComboPoints.Override = UF.UpdateComboDisplay
+ ComboPoints:SetScript("OnShow", UF.ToggleResourceBar)
+ ComboPoints:SetScript("OnHide", UF.ToggleResourceBar)
+
+ return ComboPoints
+end
+
+function UF:Configure_ComboPoints(frame)
+ if not frame.VARIABLES_SET then return end
+ local ComboPoints = frame.ComboPoints
+ if not ComboPoints then return end
+
+ local db = frame.db
+ ComboPoints.Holder = frame.ComboPointsHolder
+ ComboPoints.origParent = frame
+
+ --Fix height in case it is lower than the theme allows, or in case it's higher than 30px when not detached
+ if (not self.thinBorders and not E.PixelMode) and frame.CLASSBAR_HEIGHT > 0 and frame.CLASSBAR_HEIGHT < 7 then --A height of 7 means 6px for borders and just 1px for the actual power statusbar
+ frame.CLASSBAR_HEIGHT = 7
+ if db.combobar then db.combobar.height = 7 end
+ UF.ToggleResourceBar(ComboPoints) --Trigger update to health if needed
+ elseif (self.thinBorders or E.PixelMode) and frame.CLASSBAR_HEIGHT > 0 and frame.CLASSBAR_HEIGHT < 3 then --A height of 3 means 2px for borders and just 1px for the actual power statusbar
+ frame.CLASSBAR_HEIGHT = 3
+ if db.combobar then db.combobar.height = 3 end
+ UF.ToggleResourceBar(ComboPoints) --Trigger update to health if needed
+ elseif (not frame.CLASSBAR_DETACHED and frame.CLASSBAR_HEIGHT > 30) then
+ frame.CLASSBAR_HEIGHT = 10
+ if db.combobar then db.combobar.height = 10 end
+ UF.ToggleResourceBar(ComboPoints) --Trigger update to health if needed
+ end
+
+ --We don't want to modify the original frame.CLASSBAR_WIDTH value, as it bugs out when the classbar gains more buttons
+ local CLASSBAR_WIDTH = frame.CLASSBAR_WIDTH
+
+ if frame.USE_MINI_CLASSBAR and not frame.CLASSBAR_DETACHED then
+ CLASSBAR_WIDTH = CLASSBAR_WIDTH * (frame.MAX_CLASS_BAR - 1) / frame.MAX_CLASS_BAR
+ elseif frame.CLASSBAR_DETACHED then
+ CLASSBAR_WIDTH = db.combobar.detachedWidth - ((frame.BORDER + frame.SPACING) * 2)
+ end
+
+ ComboPoints:Width(CLASSBAR_WIDTH)
+ ComboPoints:Height(frame.CLASSBAR_HEIGHT - ((frame.BORDER + frame.SPACING) * 2))
+ local color = E.db.unitframe.colors.borderColor
+ ComboPoints.backdrop:SetBackdropColor(color.r, color.g, color.b)
+
+ if not frame.USE_MINI_CLASSBAR then
+ ComboPoints.backdrop:Show()
+ else
+ ComboPoints.backdrop:Hide()
+ end
+
+ for i = 1, frame.MAX_CLASS_BAR do
+ ComboPoints[i]:Hide()
+ ComboPoints[i]:SetStatusBarColor(unpack(ElvUF.colors.ComboPoints[i]))
+ ComboPoints[i].backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
+ ComboPoints[i]:Height(ComboPoints:GetHeight())
+
+ if frame.USE_MINI_CLASSBAR then
+ if frame.CLASSBAR_DETACHED and db.combobar.orientation == "VERTICAL" then
+ ComboPoints[i]:Width(CLASSBAR_WIDTH)
+ else
+ ComboPoints[i]:Width((CLASSBAR_WIDTH - ((5 + (frame.BORDER * 2 + frame.SPACING * 2)) * (frame.MAX_CLASS_BAR - 1))) / frame.MAX_CLASS_BAR) --Width accounts for 5px spacing between each button, excluding borders
+ end
+ elseif i ~= MAX_COMBO_POINTS then
+ ComboPoints[i]:Width((CLASSBAR_WIDTH - ((frame.MAX_CLASS_BAR - 1) * (frame.BORDER-frame.SPACING))) / frame.MAX_CLASS_BAR) --combobar width minus total width of dividers between each button, divided by number of buttons
+ end
+
+ ComboPoints[i]:GetStatusBarTexture():SetHorizTile(false)
+ ComboPoints[i]:ClearAllPoints()
+
+ if i == 1 then
+ ComboPoints[i]:Point("LEFT", ComboPoints)
+ else
+ if frame.USE_MINI_CLASSBAR then
+ if frame.CLASSBAR_DETACHED and db.combobar.orientation == "VERTICAL" then
+ ComboPoints[i]:Point("BOTTOM", ComboPoints[i - 1], "TOP", 0, (db.combobar.spacing + frame.BORDER * 2 + frame.SPACING * 2))
+ elseif frame.CLASSBAR_DETACHED and db.combobar.orientation == "HORIZONTAL" then
+ ComboPoints[i]:Point("LEFT", ComboPoints[i - 1], "RIGHT", (db.combobar.spacing + frame.BORDER * 2 + frame.SPACING * 2), 0) --5px spacing between borders of each button(replaced with Detached Spacing option)
+ else
+ ComboPoints[i]:Point("LEFT", ComboPoints[i - 1], "RIGHT", (5 + frame.BORDER * 2 + frame.SPACING * 2), 0) --5px spacing between borders of each button
+ end
+ elseif i == frame.MAX_CLASS_BAR then
+ ComboPoints[i]:Point("LEFT", ComboPoints[i - 1], "RIGHT", frame.BORDER - frame.SPACING, 0)
+ ComboPoints[i]:Point("RIGHT", ComboPoints)
+ else
+ ComboPoints[i]:Point("LEFT", ComboPoints[i - 1], "RIGHT", frame.BORDER - frame.SPACING, 0)
+ end
+ end
+
+ ComboPoints[i]:SetOrientation("HORIZONTAL")
+ ComboPoints[i]:Show()
+ end
+
+ if frame.USE_MINI_CLASSBAR and not frame.CLASSBAR_DETACHED then
+ ComboPoints:ClearAllPoints()
+ ComboPoints:Point("CENTER", frame.Health.backdrop, "TOP", 0, 0)
+
+ ComboPoints:SetParent(frame)
+ ComboPoints:SetFrameLevel(50) --RaisedElementParent uses 100, we want it lower than this
+
+ if ComboPoints.Holder and ComboPoints.Holder.mover then
+ ComboPoints.Holder.mover:SetScale(0.0001)
+ ComboPoints.Holder.mover:SetAlpha(0)
+ end
+ elseif frame.CLASSBAR_DETACHED then
+ if frame.USE_MINI_CLASSBAR then
+ if db.combobar.orientation == "HORIZONTAL" then
+ ComboPoints.Holder:Size(db.combobar.detachedWidth + (db.combobar.spacing * 4) - 20, db.combobar.height)
+ else
+ ComboPoints.Holder:Size(db.combobar.detachedWidth, (db.combobar.height * 5) + (db.combobar.spacing * 4))
+ end
+ else
+ ComboPoints.Holder:Size(db.combobar.detachedWidth, db.combobar.height)
+ end
+
+
+ if not ComboPoints.Holder.mover then
+ ComboPoints:ClearAllPoints()
+ ComboPoints:Point("BOTTOMLEFT", ComboPoints.Holder, "BOTTOMLEFT", frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING)
+ E:CreateMover(ComboPoints.Holder, "ComboBarMover", L["Combobar"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,target,combobar")
+ else
+ ComboPoints:ClearAllPoints()
+ ComboPoints:Point("BOTTOMLEFT", ComboPoints.Holder, "BOTTOMLEFT", frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING)
+ ComboPoints.Holder.mover:SetScale(1)
+ ComboPoints.Holder.mover:SetAlpha(1)
+ end
+
+ if db.combobar.parent == "UIPARENT" then
+ ComboPoints:SetParent(E.UIParent)
+ else
+ ComboPoints:SetParent(frame)
+ end
+
+ if not db.combobar.strataAndLevel.useCustomStrata then
+ ComboPoints:SetFrameStrata("LOW")
+ else
+ ComboPoints:SetFrameStrata(db.combobar.strataAndLevel.frameStrata)
+ end
+
+ if not db.combobar.strataAndLevel.useCustomLevel then
+ ComboPoints:SetFrameLevel(frame:GetFrameLevel() + 10) --Health uses 10, Power uses (Health + 5) when attached
+ else
+ ComboPoints:SetFrameLevel(db.combobar.strataAndLevel.frameLevel)
+ end
+ else
+ ComboPoints:ClearAllPoints()
+
+ if frame.ORIENTATION == "RIGHT" then
+ ComboPoints:Point("BOTTOMRIGHT", frame.Health.backdrop, "TOPRIGHT", -frame.BORDER, frame.SPACING*3)
+ else
+ ComboPoints:Point("BOTTOMLEFT", frame.Health.backdrop, "TOPLEFT", frame.BORDER, frame.SPACING*3)
+ end
+
+ ComboPoints:SetParent(frame)
+ ComboPoints:SetFrameStrata("LOW")
+ ComboPoints:SetFrameLevel(frame:GetFrameLevel() + 10) --Health uses 10, Power uses (Health + 5) when attached
+
+ if ComboPoints.Holder and ComboPoints.Holder.mover then
+ ComboPoints.Holder.mover:SetScale(0.0001)
+ ComboPoints.Holder.mover:SetAlpha(0)
+ end
+ end
+
+ self:CombobarDetachedUpdate()
+
+ if frame.USE_CLASSBAR and not frame:IsElementEnabled("ComboPoints") then
+ frame:EnableElement("ComboPoints")
+ ComboPoints:Show()
+ elseif not frame.USE_CLASSBAR and frame:IsElementEnabled("ComboPoints") then
+ frame:DisableElement("ComboPoints")
+ ComboPoints:Hide()
+ end
+
+ if not frame:IsShown() then
+ ComboPoints:ForceUpdate()
+ end
+end
+
+function UF:UpdateComboDisplay(event, unit)
+ if unit == "pet" then return end
+ if unit ~= "player" and (event == "UNIT_ENTERED_VEHICLE" or event == "UNIT_EXITING_VEHICLE") then return end
+
+ local db = self.db
+ if not db then return end
+
+ local element = self.ComboPoints
+
+ if db.combobar.enable then
+ local inVehicle = UnitHasVehicleUI("player") or UnitHasVehicleUI("vehicle")
+
+ local cp
+ if inVehicle then
+ cp = GetComboPoints("vehicle", "target")
+ else
+ cp = GetComboPoints("player", "target")
+ end
+
+ local custom_backdrop = UF.db.colors.customclasspowerbackdrop and UF.db.colors.classpower_backdrop
+ if cp == 0 and db.combobar.autoHide then
+ element:Hide()
+ UF.ToggleResourceBar(element)
+ else
+ element:Show()
+ for i = 1, MAX_COMBO_POINTS do
+ if i <= cp then
+ element[i]:Show()
+ else
+ element[i]:Hide()
+ end
+
+ if custom_backdrop then
+ element[i].bg:SetVertexColor(custom_backdrop.r, custom_backdrop.g, custom_backdrop.b)
+ else
+ local r, g, b = element[i]:GetStatusBarColor()
+ element[i].bg:SetVertexColor(r * 0.35, g * 0.35, b * 0.35)
+ end
+ end
+ UF.ToggleResourceBar(element)
+ end
+ else
+ element:Hide()
+ UF.ToggleResourceBar(element)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/CustomText.lua b/ElvUI/Modules/UnitFrames/Elements/CustomText.lua
new file mode 100644
index 0000000..796b212
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/CustomText.lua
@@ -0,0 +1,52 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local pairs = pairs
+--WoW API / Variables
+
+function UF:Configure_CustomTexts(frame)
+ local db = frame.db
+
+ --Make sure CustomTexts are hidden if they don't exist in current profile
+ for objectName, object in pairs(frame.customTexts) do
+ if (not db.customTexts) or (db.customTexts and not db.customTexts[objectName]) then
+ object:Hide()
+ frame.customTexts[objectName] = nil
+ end
+ end
+
+ if db.customTexts then
+ local customFont = UF.LSM:Fetch("font", UF.db.font)
+ for objectName, _ in pairs(db.customTexts) do
+ if not frame.customTexts[objectName] then
+ frame.customTexts[objectName] = frame.RaisedElementParent:CreateFontString(nil, "OVERLAY")
+ end
+
+ local objectDB = db.customTexts[objectName]
+
+ if objectDB.font then
+ customFont = UF.LSM:Fetch("font", objectDB.font)
+ end
+
+ local attachPoint = self:GetObjectAnchorPoint(frame, objectDB.attachTextTo)
+ frame.customTexts[objectName]:FontTemplate(customFont, objectDB.size or UF.db.fontSize, objectDB.fontOutline or UF.db.fontOutline)
+ frame.customTexts[objectName]:SetJustifyH(objectDB.justifyH or "CENTER")
+ frame.customTexts[objectName]:ClearAllPoints()
+ frame.customTexts[objectName]:Point(objectDB.justifyH or "CENTER", attachPoint, objectDB.justifyH or "CENTER", objectDB.xOffset, objectDB.yOffset)
+
+ --This takes care of custom texts that were added before the enable option was added.
+ if objectDB.enable == nil then
+ objectDB.enable = true
+ end
+
+ if objectDB.enable then
+ frame:Tag(frame.customTexts[objectName], objectDB.text_format or "")
+ frame.customTexts[objectName]:Show()
+ else
+ frame:Untag(frame.customTexts[objectName])
+ frame.customTexts[objectName]:Hide()
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/Cutaway.lua b/ElvUI/Modules/UnitFrames/Elements/Cutaway.lua
new file mode 100644
index 0000000..54b34b3
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/Cutaway.lua
@@ -0,0 +1,87 @@
+local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+
+function UF:Construct_Cutaway(frame)
+ local cutaway = {}
+ local frameName = frame:GetName()
+
+ if frame.Power then
+ local powerTexture = frame.Power:GetStatusBarTexture()
+ local cutawayPower = frame.Power.ClipFrame:CreateTexture(frameName.."CutawayPower")
+ cutawayPower:SetPoint("TOPLEFT", powerTexture, "TOPRIGHT")
+ cutawayPower:SetPoint("BOTTOMLEFT", powerTexture, "BOTTOMRIGHT")
+ cutawayPower:SetTexture(E.media.blankTex)
+ cutaway.Power = cutawayPower
+ end
+
+ local healthTexture = frame.Health:GetStatusBarTexture()
+ local cutawayHealth = frame.Health.ClipFrame:CreateTexture(frameName.."CutawayHealth")
+ cutawayHealth:SetPoint("TOPLEFT", healthTexture, "TOPRIGHT")
+ cutawayHealth:SetPoint("BOTTOMLEFT", healthTexture, "BOTTOMRIGHT")
+ cutawayHealth:SetTexture(E.media.blankTex)
+ cutaway.Health = cutawayHealth
+
+ return cutaway
+end
+
+local cutawayPoints = {
+ [1] = {"TOPLEFT", "TOPRIGHT"},
+ [2] = {"BOTTOMLEFT", "BOTTOMRIGHT"},
+ [3] = {"BOTTOMLEFT", "TOPLEFT"},
+ [4] = {"BOTTOMRIGHT", "TOPRIGHT"}
+}
+
+local DEFAULT_INDEX, VERT_INDEX = 1, 3
+function UF:GetPoints_Cutaway(db)
+ local index
+ if db and db.orientation == "VERTICAL" then
+ index = VERT_INDEX
+ else
+ index = DEFAULT_INDEX
+ end
+
+ return cutawayPoints[index], cutawayPoints[index + 1]
+end
+
+function UF:Configure_Cutaway(frame)
+ local db = frame.db and frame.db.cutaway
+ local healthDB, powerDB = db and db.health, db and db.power
+ local healthEnabled = healthDB and healthDB.enabled
+ local powerEnabled = powerDB and powerDB.enabled
+ if healthEnabled or powerEnabled then
+ if not frame:IsElementEnabled("Cutaway") then
+ frame:EnableElement("Cutaway")
+ end
+
+ frame.Cutaway:UpdateConfigurationValues(db)
+ local health = frame.Cutaway.Health
+ if health and healthEnabled then
+ local point1, point2 = UF:GetPoints_Cutaway(frame.db.health)
+ local barTexture = frame.Health:GetStatusBarTexture()
+
+ health:ClearAllPoints()
+ health:SetPoint(point1[1], barTexture, point1[2])
+ health:SetPoint(point2[1], barTexture, point2[2])
+
+ frame.Health:PostUpdateColor(frame.unit)
+ end
+
+ local power = frame.Cutaway.Power
+ local powerUsable = powerEnabled and frame.USE_POWERBAR
+ if power and powerUsable then
+ local point1, point2 = UF:GetPoints_Cutaway(frame.db.power)
+ local barTexture = frame.Power:GetStatusBarTexture()
+
+ power:ClearAllPoints()
+ power:SetPoint(point1[1], barTexture, point1[2])
+ power:SetPoint(point2[1], barTexture, point2[2])
+
+ frame.Power:PostUpdateColor()
+ end
+ elseif frame:IsElementEnabled("Cutaway") then
+ frame:DisableElement("Cutaway")
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/DebuffHighlight.lua b/ElvUI/Modules/UnitFrames/Elements/DebuffHighlight.lua
new file mode 100644
index 0000000..aa93e50
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/DebuffHighlight.lua
@@ -0,0 +1,65 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+
+function UF:Construct_DebuffHighlight(frame)
+ local dbh = frame:CreateTexture(nil, "OVERLAY")
+ dbh:SetInside(frame.Health.backdrop)
+ dbh:SetTexture(E.media.blankTex)
+ dbh:SetVertexColor(0, 0, 0, 0)
+ dbh:SetBlendMode("ADD")
+
+ frame.DebuffHighlightAlpha = 0.45
+ frame.DebuffHighlightFilterTable = E.global.unitframe.DebuffHighlightColors
+
+ frame:CreateShadow()
+ local x = frame.shadow
+ frame.shadow = nil
+ x:Hide()
+
+ frame.DBHGlow = x
+
+ if frame.Health then
+ dbh:SetParent(frame.Health)
+ frame.DBHGlow:SetParent(frame.Health)
+ end
+
+ dbh.PostUpdate = UF.PostUpdate_DebuffHighlight
+
+ return dbh
+end
+
+function UF:Configure_DebuffHighlight(frame)
+ if E.db.unitframe.debuffHighlighting ~= "NONE" then
+ frame:EnableElement("DebuffHighlight")
+
+ frame.DebuffHighlight:SetBlendMode(UF.db.colors.debuffHighlight.blendMode)
+ frame.DebuffHighlightFilterTable = E.global.unitframe.DebuffHighlightColors
+
+ if E.db.unitframe.debuffHighlighting == "GLOW" then
+ frame.DebuffHighlightBackdrop = true
+ if frame.ThreatIndicator then
+ frame.DBHGlow:SetAllPoints(frame.ThreatIndicator.glow)
+ elseif frame.TargetGlow then
+ frame.DBHGlow:SetAllPoints(frame.TargetGlow)
+ end
+ else
+ frame.DebuffHighlightBackdrop = false
+ end
+ else
+ frame:DisableElement("DebuffHighlight")
+ end
+end
+
+function UF:PostUpdate_DebuffHighlight(object, debuffType, texture, wasFiltered, style)
+ if debuffType and not wasFiltered then
+ local color = UF.db.colors.debuffHighlight[debuffType]
+ if object.DebuffHighlightBackdrop and object.DBHGlow then
+ object.DBHGlow:SetBackdropBorderColor(color.r, color.g, color.b, color.a)
+ else
+ object.DebuffHighlight:SetVertexColor(color.r, color.g, color.b, color.a)
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/FrameGlow.lua b/ElvUI/Modules/UnitFrames/Elements/FrameGlow.lua
new file mode 100644
index 0000000..f2cf8cc
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/FrameGlow.lua
@@ -0,0 +1,431 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local _G = _G
+local pairs = pairs
+local select = select
+local assert = assert
+local tinsert = tinsert
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local UnitClass = UnitClass
+local UnitExists = UnitExists
+local UnitIsPlayer = UnitIsPlayer
+local UnitIsUnit = UnitIsUnit
+local UnitReaction = UnitReaction
+
+function UF:FrameGlow_MouseOnUnit(frame)
+ if frame and frame:IsVisible() and UnitExists("mouseover") then
+ local unit = frame.unit or (frame.isForced and "player")
+ return unit and UnitIsUnit("mouseover", unit)
+ end
+
+ return false
+end
+
+function UF:FrameGlow_ElementHook(frame, glow, which)
+ if not (frame and frame.__elements) then return end
+ tinsert(frame.__elements, function()
+ local unit = frame.unit or (frame.isForced and "player")
+ if unit then
+ UF:FrameGlow_SetGlowColor(glow, unit, which)
+ end
+
+ if which == "mouseoverGlow" then
+ UF:FrameGlow_Position(frame)
+ UF:FrameGlow_CheckMouseover(frame)
+ else
+ UF:FrameGlow_PositionGlow(frame, glow, glow.powerGlow)
+ end
+
+ if which == "targetGlow" then
+ UF:FrameGlow_CheckTarget(frame)
+ end
+ end)
+end
+
+function UF:FrameGlow_HookPowerBar(frame, power, powerName, glow, offset)
+ if (frame and power and powerName and glow and offset) and not glow[powerName.."Hooked"] then
+ glow[powerName.."Hooked"] = true
+ local func = function() UF:FrameGlow_ClassGlowPosition(frame, powerName, glow, offset, true) end
+ power:HookScript("OnShow", func)
+ power:HookScript("OnHide", func)
+ end
+end
+
+function UF:FrameGlow_ClassGlowPosition(frame, powerName, glow, offset, fromScript)
+ if not (frame and glow and offset) then return end
+
+ local power = powerName and frame[powerName]
+ if not power then return end
+
+ if not fromScript then
+ UF:FrameGlow_HookPowerBar(frame, power, powerName, glow, offset)
+ end
+
+ local portrait = (frame.USE_PORTRAIT and not frame.USE_PORTRAIT_OVERLAY) and (frame.Portrait and frame.Portrait.backdrop)
+
+ if powerName == "HappinessIndicator" and (power and power.backdrop and power:IsVisible()) then
+ if frame.ORIENTATION == "RIGHT" then
+ glow:Point("TOPLEFT", power.backdrop, -offset, offset)
+ glow:Point("TOPRIGHT", portrait or frame.Health.backdrop, offset, offset)
+ else
+ glow:Point("TOPLEFT", portrait or frame.Health.backdrop, -offset, offset)
+ glow:Point("TOPRIGHT", power.backdrop, offset, offset)
+ end
+ else
+ if (power and power.backdrop and power:IsVisible()) and (not (frame.CLASSBAR_DETACHED or frame.USE_MINI_CLASSBAR)) then
+ glow:Point("TOPLEFT", (frame.ORIENTATION == "LEFT" and portrait) or power.backdrop, -offset, offset)
+ glow:Point("TOPRIGHT", (frame.ORIENTATION == "RIGHT" and portrait) or power.backdrop, offset, offset)
+ elseif frame.Health and frame.Health.backdrop then
+ glow:Point("TOPLEFT", (frame.ORIENTATION == "LEFT" and portrait) or frame.Health.backdrop, -offset, offset)
+ glow:Point("TOPRIGHT", (frame.ORIENTATION == "RIGHT" and portrait) or frame.Health.backdrop, offset, offset)
+ end
+ end
+end
+
+function UF:FrameGlow_PositionGlow(frame, mainGlow, powerGlow)
+ if not (frame and frame.VARIABLES_SET) then return end
+
+ local additionalPower = frame.AdditionalPower
+ local runes = frame.Runes
+ local comboPoints = frame.ComboPoints
+ local happiness = frame.HappinessIndicator
+ local power = frame.Power and frame.Power.backdrop
+ local health = frame.Health and frame.Health.backdrop
+ local portrait = (frame.USE_PORTRAIT and not frame.USE_PORTRAIT_OVERLAY) and (frame.Portrait and frame.Portrait.backdrop)
+ local offset = (E.PixelMode and 3) or 4 -- edgeSize is 3
+
+ mainGlow:ClearAllPoints()
+ mainGlow:Point("TOPLEFT", (frame.ORIENTATION == "LEFT" and portrait) or health, -offset, offset)
+ mainGlow:Point("TOPRIGHT", (frame.ORIENTATION == "RIGHT" and portrait) or health, offset, offset)
+
+ if frame.USE_POWERBAR_OFFSET or frame.USE_MINI_POWERBAR then
+ mainGlow:Point("BOTTOMLEFT", health, -offset, -offset)
+ mainGlow:Point("BOTTOMRIGHT", health, offset, -offset)
+ else
+ --offset is set because its one pixel off for some reason
+ mainGlow:Point("BOTTOMLEFT", frame, -offset, -(E.PixelMode and offset or offset-1))
+ mainGlow:Point("BOTTOMRIGHT", frame, offset, -(E.PixelMode and offset or offset-1))
+ end
+
+ if powerGlow then
+ powerGlow:ClearAllPoints()
+ powerGlow:Point("TOPLEFT", power, -offset, offset)
+ powerGlow:Point("TOPRIGHT", power, offset, offset)
+ powerGlow:Point("BOTTOMLEFT", power, -offset, -offset)
+ powerGlow:Point("BOTTOMRIGHT", power, offset, -offset)
+ end
+
+ if additionalPower then
+ UF:FrameGlow_ClassGlowPosition(frame, "AdditionalPower", mainGlow, offset)
+ elseif runes then
+ UF:FrameGlow_ClassGlowPosition(frame, "Runes", mainGlow, offset)
+ elseif comboPoints then
+ UF:FrameGlow_ClassGlowPosition(frame, "ComboPoints", mainGlow, offset)
+ elseif happiness then
+ UF:FrameGlow_ClassGlowPosition(frame, "HappinessIndicator", mainGlow, offset)
+ end
+end
+
+function UF:FrameGlow_CreateGlow(frame, mouse)
+ -- Main Glow to wrap the health frame to it's best ability
+ frame:CreateShadow()
+ local mainGlow = frame.shadow
+ mainGlow:SetFrameStrata("BACKGROUND")
+ mainGlow:Hide()
+ frame.shadow = nil
+
+ -- Secondary Glow for power frame when using power offset or mini power
+ frame:CreateShadow()
+ local powerGlow = frame.shadow
+ powerGlow:SetFrameStrata("BACKGROUND")
+ powerGlow:Hide()
+ frame.shadow = nil
+
+ if mouse then
+ mainGlow:SetFrameLevel(4)
+ powerGlow:SetFrameLevel(4)
+ else
+ mainGlow:SetFrameLevel(3)
+ powerGlow:SetFrameLevel(3)
+ end
+
+ -- Eventing Frame
+ if not frame.FrameGlow then
+ frame.FrameGlow = CreateFrame("Frame", nil, frame)
+ frame.FrameGlow:Hide()
+ frame.FrameGlow:HookScript("OnEvent", function(_, event)
+ if event == "UPDATE_MOUSEOVER_UNIT" then
+ UF:FrameGlow_CheckMouseover(frame)
+ elseif event == "PLAYER_TARGET_CHANGED" then
+ UF:FrameGlow_CheckTarget(frame)
+ end
+ end)
+ end
+
+ mainGlow.powerGlow = powerGlow
+ return mainGlow
+end
+
+function UF:FrameGlow_SetGlowColor(glow, unit, which)
+ if not glow then return end
+ local option = E.db.unitframe.colors.frameGlow[which]
+ local r, g, b, a = 1, 1, 1, 1
+
+ if option.color then
+ local color = option.color
+ r, g, b, a = color.r, color.g, color.b, color.a
+ end
+
+ if option.class then
+ local isPlayer = unit and UnitIsPlayer(unit)
+ local reaction = unit and UnitReaction(unit, "player")
+
+ if isPlayer then
+ local _, class = UnitClass(unit)
+ if class then
+ local color = E.media.herocolor
+ if color then
+ r, g, b = color.r, color.g, color.b
+ end
+ end
+ elseif reaction then
+ local color = FACTION_BAR_COLORS[reaction]
+ if color then
+ r, g, b = color.r, color.g, color.b
+ end
+ end
+ end
+
+ if which == "mouseoverGlow" then
+ glow:SetVertexColor(r, g, b, a)
+ else
+ glow:SetBackdropBorderColor(r, g, b, a)
+ if glow.powerGlow then
+ glow.powerGlow:SetBackdropBorderColor(r, g, b, a)
+ end
+ end
+end
+
+function UF:FrameGlow_HideGlow(glow)
+ if not glow then return end
+ if glow:IsShown() then glow:Hide() end
+ if glow.powerGlow and glow.powerGlow:IsShown() then
+ glow.powerGlow:Hide()
+ end
+end
+
+function UF:FrameGlow_ConfigureGlow(frame, unit, dbTexture)
+ if not frame then return end
+
+ if not unit then
+ unit = frame.unit or (frame.isForced and "player")
+ end
+
+ local shouldHide
+ if frame.FrameGlow and frame.FrameGlow.texture then
+ if E.db.unitframe.colors.frameGlow.mouseoverGlow.enable and not (frame.db and frame.db.disableMouseoverGlow) then
+ frame.FrameGlow.texture:SetTexture(dbTexture)
+ UF:FrameGlow_SetGlowColor(frame.FrameGlow.texture, unit, "mouseoverGlow")
+ else
+ shouldHide = "texture"
+ end
+ end
+
+ if frame.MouseGlow then
+ if E.db.unitframe.colors.frameGlow.mainGlow.enable and not (frame.db and frame.db.disableMouseoverGlow) then
+ UF:FrameGlow_SetGlowColor(frame.MouseGlow, unit, "mainGlow")
+ else
+ UF:FrameGlow_HideGlow(frame.MouseGlow)
+ if shouldHide then
+ shouldHide = "both"
+ end
+ end
+ end
+
+ if shouldHide then
+ if shouldHide == "both" and frame.FrameGlow:IsShown() then
+ frame.FrameGlow:Hide()
+ elseif shouldHide == "texture" then
+ frame.FrameGlow.texture:Hide()
+ end
+ end
+
+ if frame.TargetGlow then
+ UF:FrameGlow_CheckTarget(frame, true)
+ end
+end
+
+function UF:FrameGlow_CheckTarget(frame, setColor)
+ if not (frame and frame.TargetGlow and frame:IsVisible()) then return end
+
+ local unit = frame.unit or (frame.isForced and "player")
+ if E.db.unitframe.colors.frameGlow.targetGlow.enable and (unit and UnitIsUnit(unit, "target")) and not (frame.db and frame.db.disableTargetGlow) then
+ if setColor then
+ UF:FrameGlow_SetGlowColor(frame.TargetGlow, unit, "targetGlow")
+ end
+ if frame.TargetGlow.powerGlow then
+ if frame.USE_POWERBAR_OFFSET or frame.USE_MINI_POWERBAR then
+ frame.TargetGlow.powerGlow:Show()
+ elseif frame.TargetGlow.powerGlow:IsShown() then
+ frame.TargetGlow.powerGlow:Hide()
+ end
+ end
+ frame.TargetGlow:Show()
+ else
+ UF:FrameGlow_HideGlow(frame.TargetGlow)
+ end
+end
+
+function UF:FrameGlow_CheckMouseover(frame)
+ if not (frame and frame.MouseGlow and frame:IsVisible()) then return end
+
+ local shouldShow
+ if UF:FrameGlow_MouseOnUnit(frame) then
+ if E.db.unitframe.colors.frameGlow.mainGlow.enable and not (frame.db and frame.db.disableMouseoverGlow) then
+ shouldShow = "frame"
+ end
+ if E.db.unitframe.colors.frameGlow.mouseoverGlow.enable and not (frame.db and frame.db.disableMouseoverGlow) then
+ shouldShow = (shouldShow and "both") or "texture"
+ end
+ end
+
+ if shouldShow then
+ if frame.FrameGlow and not frame.FrameGlow:IsShown() then
+ frame.FrameGlow:Show()
+ end
+ if (shouldShow == "both" or shouldShow == "frame") then
+ if frame.MouseGlow.powerGlow then
+ if frame.USE_POWERBAR_OFFSET or frame.USE_MINI_POWERBAR then
+ frame.MouseGlow.powerGlow:Show()
+ elseif frame.MouseGlow.powerGlow:IsShown() then
+ frame.MouseGlow.powerGlow:Hide()
+ end
+ end
+ frame.MouseGlow:Show()
+
+ if (shouldShow == "frame") and frame.FrameGlow.texture and frame.FrameGlow.texture:IsShown() then
+ frame.FrameGlow.texture:Hide()
+ end
+ end
+ if (shouldShow == "both" or shouldShow == "texture") and frame.FrameGlow.texture and not frame.FrameGlow.texture:IsShown() then
+ frame.FrameGlow.texture:Show()
+ end
+ elseif frame.FrameGlow and frame.FrameGlow:IsShown() then
+ frame.FrameGlow:Hide()
+ end
+end
+
+function UF:FrameGlow_Position(frame)
+ if frame.FrameGlow and frame.FrameGlow.texture then
+ frame.FrameGlow.texture:ClearAllPoints()
+ frame.FrameGlow.texture:Point("TOPLEFT", frame.Health, "TOPLEFT")
+ frame.FrameGlow.texture:Point("BOTTOMRIGHT", frame.Health:GetStatusBarTexture(), "BOTTOMRIGHT")
+ end
+end
+
+function UF:Configure_FrameGlow(frame)
+ if frame.FrameGlow and frame.FrameGlow.texture then
+ local dbTexture = UF.LSM:Fetch("statusbar", E.db.unitframe.colors.frameGlow.mouseoverGlow.texture)
+ frame.FrameGlow.texture:SetTexture(dbTexture)
+ end
+end
+
+function UF:Construct_FrameGlow(frame, glow)
+ if frame.Health and frame.FrameGlow then
+ frame.FrameGlow:HookScript("OnHide", function(watcher)
+ UF:FrameGlow_HideGlow(glow)
+
+ if watcher.texture and watcher.texture:IsShown() then
+ watcher.texture:Hide()
+ end
+ end)
+
+ frame.FrameGlow:SetScript("OnUpdate", function(watcher, elapsed)
+ if watcher.elapsed and watcher.elapsed > 0.1 then
+ if not UF:FrameGlow_MouseOnUnit(frame) then
+ watcher:Hide()
+ end
+ watcher.elapsed = 0
+ else
+ watcher.elapsed = (watcher.elapsed or 0) + elapsed
+ end
+ end)
+
+ frame.FrameGlow.texture = frame.Health:CreateTexture("$parentHighlight", "OVERLAY")
+ frame.FrameGlow.texture:Hide()
+
+ UF:FrameGlow_ElementHook(frame, frame.FrameGlow.texture, "mouseoverGlow")
+ end
+end
+
+function UF:Construct_MouseGlow(frame)
+ local mainGlow = UF:FrameGlow_CreateGlow(frame, true)
+ UF:FrameGlow_ElementHook(frame, mainGlow, "mainGlow")
+ UF:Construct_FrameGlow(frame, mainGlow)
+ frame.FrameGlow:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
+
+ return mainGlow
+end
+
+function UF:Construct_TargetGlow(frame)
+ local targetGlow = UF:FrameGlow_CreateGlow(frame)
+ UF:FrameGlow_ElementHook(frame, targetGlow, "targetGlow")
+ frame.FrameGlow:RegisterEvent("PLAYER_TARGET_CHANGED")
+
+ return targetGlow
+end
+
+function UF:FrameGlow_CheckChildren(frame, dbTexture)
+ if frame.GetName then
+ local pet = _G[frame:GetName().."Pet"]
+ if pet then
+ UF:FrameGlow_ConfigureGlow(pet, pet.unit, dbTexture)
+ end
+
+ local target = _G[frame:GetName().."Target"]
+ if target then
+ UF:FrameGlow_ConfigureGlow(target, target.unit, dbTexture)
+ end
+ end
+end
+
+function UF:FrameGlow_UpdateFrames()
+ local dbTexture = UF.LSM:Fetch("statusbar", E.db.unitframe.colors.frameGlow.mouseoverGlow.texture)
+
+ -- focus, focustarget, pet, pettarget, player, target, targettarget, targettargettarget
+ for unit in pairs(self.units) do
+ UF:FrameGlow_ConfigureGlow(self[unit], unit, dbTexture)
+ end
+
+ -- arena{1-5}, boss{1-5}
+ for unit in pairs(self.groupunits) do
+ UF:FrameGlow_ConfigureGlow(self[unit], unit, dbTexture)
+ end
+
+ -- assist, tank, party, raid, raid40, raidpet
+ for groupName in pairs(self.headers) do
+ assert(self[groupName], "UF FrameGlow: Invalid group specified.")
+ local group = self[groupName]
+
+ if group.GetNumChildren then
+ for i = 1, group:GetNumChildren() do
+ local frame = select(i, group:GetChildren())
+ if frame and frame.Health then
+ UF:FrameGlow_ConfigureGlow(frame, frame.unit, dbTexture)
+ UF:FrameGlow_CheckChildren(frame, dbTexture)
+ elseif frame then
+ for n = 1, frame:GetNumChildren() do
+ local child = select(n, frame:GetChildren())
+ if child and child.Health then
+ UF:FrameGlow_ConfigureGlow(child, child.unit, dbTexture)
+ UF:FrameGlow_CheckChildren(child, dbTexture)
+ end
+ end
+ end
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/GPS.lua b/ElvUI/Modules/UnitFrames/Elements/GPS.lua
new file mode 100644
index 0000000..578df1f
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/GPS.lua
@@ -0,0 +1,42 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+function UF:Construct_GPS(frame)
+ local gps = CreateFrame("Frame", nil, frame)
+ gps:SetFrameLevel(frame:GetFrameLevel() + 50)
+ gps:Hide()
+
+ gps.Texture = gps:CreateTexture("OVERLAY")
+ gps.Texture:SetTexture(E.Media.Textures.Arrow)
+ gps.Texture:SetBlendMode("BLEND")
+ gps.Texture:SetVertexColor(214/255, 41/255, 41/255)
+ gps.Texture:SetAllPoints()
+
+ return gps
+end
+
+function UF:Configure_GPS(frame)
+ local GPS = frame.GPS
+
+ if frame.db.GPSArrow.enable then
+ if not frame:IsElementEnabled("GPS") then
+ frame:EnableElement("GPS")
+ end
+
+ GPS:Size(frame.db.GPSArrow.size)
+ GPS.onMouseOver = frame.db.GPSArrow.onMouseOver
+ GPS.outOfRange = frame.db.GPSArrow.outOfRange
+
+ GPS:Point("CENTER", frame, "CENTER", frame.db.GPSArrow.xOffset, frame.db.GPSArrow.yOffset)
+
+ GPS.UpdateState(frame)
+ else
+ if frame:IsElementEnabled("GPS") then
+ frame:DisableElement("GPS")
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/Happiness.lua b/ElvUI/Modules/UnitFrames/Elements/Happiness.lua
new file mode 100644
index 0000000..4cc5ce1
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/Happiness.lua
@@ -0,0 +1,127 @@
+local E, L, V, P, G = unpack(ElvUI)
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+
+function UF:Construct_Happiness(frame)
+ local HappinessIndicator = CreateFrame("Statusbar", nil, frame)
+
+ HappinessIndicator.backdrop = CreateFrame("Frame", nil, HappinessIndicator)
+ UF.statusbars[HappinessIndicator] = true
+ HappinessIndicator.backdrop:SetTemplate("Default", nil, nil, self.thinBorders, true)
+ HappinessIndicator.backdrop:SetFrameLevel(HappinessIndicator:GetFrameLevel() - 1)
+ HappinessIndicator:SetInside(HappinessIndicator.backdrop)
+ HappinessIndicator:SetOrientation("VERTICAL")
+ HappinessIndicator:SetMinMaxValues(0, 100)
+ HappinessIndicator:SetFrameLevel(50)
+
+ HappinessIndicator.bg = HappinessIndicator:CreateTexture(nil, "BORDER")
+ HappinessIndicator.bg:SetAllPoints(HappinessIndicator)
+ HappinessIndicator.bg:SetTexture(E.media.blankTex)
+ HappinessIndicator.bg.multiplier = 0.3
+
+ HappinessIndicator.Override = UF.HappinessOverride
+
+ return HappinessIndicator
+end
+
+function UF:Configure_Happiness(frame)
+ if not frame.VARIABLES_SET then return end
+
+ local HappinessIndicator = frame.HappinessIndicator
+ local db = frame.db
+
+ frame.HAPPINESS_WIDTH = HappinessIndicator and frame.HAPPINESS_SHOWN and (db.happiness.width + (frame.BORDER*3)) or 0
+
+ if db.happiness.enable then
+ if not frame:IsElementEnabled("HappinessIndicator") then
+ frame:EnableElement("HappinessIndicator")
+ end
+
+ HappinessIndicator.backdrop:ClearAllPoints()
+ if db.power.enable and not frame.USE_MINI_POWERBAR and not frame.USE_INSET_POWERBAR and not frame.POWERBAR_DETACHED and not frame.USE_POWERBAR_OFFSET then
+ if frame.ORIENTATION == "RIGHT" then
+ HappinessIndicator.backdrop:Point("BOTTOMRIGHT", frame.Power, "BOTTOMLEFT", -frame.BORDER + (frame.BORDER - frame.SPACING*3), -frame.BORDER)
+ HappinessIndicator.backdrop:Point("TOPLEFT", frame.Health, "TOPLEFT", -frame.HAPPINESS_WIDTH, frame.BORDER)
+ else
+ HappinessIndicator.backdrop:Point("BOTTOMLEFT", frame.Power, "BOTTOMRIGHT", frame.BORDER + (-frame.BORDER + frame.SPACING*3), -frame.BORDER)
+ HappinessIndicator.backdrop:Point("TOPRIGHT", frame.Health, "TOPRIGHT", frame.HAPPINESS_WIDTH, frame.BORDER)
+ end
+ else
+ if frame.ORIENTATION == "RIGHT" then
+ HappinessIndicator.backdrop:Point("BOTTOMRIGHT", frame.Health, "BOTTOMLEFT", -frame.BORDER + (frame.BORDER - frame.SPACING*3), -frame.BORDER)
+ HappinessIndicator.backdrop:Point("TOPLEFT", frame.Health, "TOPLEFT", -frame.HAPPINESS_WIDTH, frame.BORDER)
+ else
+ HappinessIndicator.backdrop:Point("BOTTOMLEFT", frame.Health, "BOTTOMRIGHT", frame.BORDER + (-frame.BORDER + frame.SPACING*3), -frame.BORDER)
+ HappinessIndicator.backdrop:Point("TOPRIGHT", frame.Health, "TOPRIGHT", frame.HAPPINESS_WIDTH, frame.BORDER)
+ end
+ end
+ else
+ if frame:IsElementEnabled("HappinessIndicator") then
+ frame:DisableElement("HappinessIndicator")
+ end
+ end
+end
+
+function UF:HappinessOverride(event, unit)
+ if not unit or self.unit ~= unit then return end
+
+ local db = self.db
+ if not db then return end
+
+ local element = self.HappinessIndicator
+
+ if element.PreUpdate then
+ element:PreUpdate()
+ end
+
+ local _, hunterPet = HasPetUI()
+ local happiness, damagePercentage = GetPetHappiness()
+ local value, r, g, b
+
+ if hunterPet and happiness then
+ if damagePercentage == 75 then
+ value = 33
+ r, g, b = 0.8, 0.2, 0.1
+ elseif damagePercentage == 100 then
+ value = 66
+ r, g, b = 1, 1, 0
+ elseif damagePercentage == 125 then
+ value = 100
+ r, g, b = 0, 0.8, 0
+ end
+
+ element:SetValue(value)
+ element:SetStatusBarColor(r, g, b)
+ element.bg:SetVertexColor(r, g, b, 0.15)
+
+ if damagePercentage == 125 and db.happiness.autoHide then
+ element:Hide()
+ else
+ element:Show()
+ end
+ else
+ return element:Hide()
+ end
+
+ local isShown = element:IsShown()
+ local stateChanged
+
+ if (self.HAPPINESS_SHOWN and not isShown) or (not self.HAPPINESS_SHOWN and isShown) then
+ stateChanged = true
+ end
+
+ self.HAPPINESS_SHOWN = isShown
+
+ if stateChanged then
+ UF:Configure_Happiness(self)
+ UF:Configure_HealthBar(self)
+ UF:Configure_Power(self)
+ UF:Configure_InfoPanel(self, true)
+ end
+
+ if element.PostUpdate then
+ return element:PostUpdate(unit, happiness, damagePercentage)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/HealComm.lua b/ElvUI/Modules/UnitFrames/Elements/HealComm.lua
new file mode 100644
index 0000000..db18a22
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/HealComm.lua
@@ -0,0 +1,167 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+function UF.HealthClipFrame_HealComm(frame)
+ local pred = frame.HealCommBar
+ if pred then
+ UF:SetAlpha_HealComm(pred, true)
+ UF:SetVisibility_HealComm(pred)
+ end
+end
+
+function UF:SetAlpha_HealComm(obj, show)
+ obj.myBar:SetAlpha(show and 1 or 0)
+ obj.otherBar:SetAlpha(show and 1 or 0)
+end
+
+function UF:SetVisibility_HealComm(obj)
+ -- the first update is from `HealthClipFrame_HealComm`
+ -- we set this variable to allow `Configure_HealComm` to
+ -- update the elements overflow lock later on by option
+ if not obj.allowClippingUpdate then
+ obj.allowClippingUpdate = true
+ end
+
+ if obj.maxOverflow > 1 then
+ obj.myBar:SetParent(obj.health)
+ obj.otherBar:SetParent(obj.health)
+ else
+ obj.myBar:SetParent(obj.parent)
+ obj.otherBar:SetParent(obj.parent)
+ end
+end
+
+function UF:Construct_HealComm(frame)
+ local health = frame.Health
+ local parent = health.ClipFrame
+
+ local myBar = CreateFrame("StatusBar", nil, parent)
+ local otherBar = CreateFrame("StatusBar", nil, parent)
+
+ myBar:SetFrameLevel(11)
+ otherBar:SetFrameLevel(11)
+
+ UF.statusbars[myBar] = true
+ UF.statusbars[otherBar] = true
+
+ local texture = (not health.isTransparent and health:GetStatusBarTexture()) or E.media.blankTex
+ UF:Update_StatusBar(myBar, texture)
+ UF:Update_StatusBar(otherBar, texture)
+
+ local healPrediction = {
+ myBar = myBar,
+ otherBar = otherBar,
+ PostUpdate = UF.UpdateHealComm,
+ maxOverflow = 1,
+ health = health,
+ parent = parent,
+ frame = frame
+ }
+
+ UF:SetAlpha_HealComm(healPrediction)
+
+ return healPrediction
+end
+
+function UF:Configure_HealComm(frame)
+ if frame.db.healPrediction and frame.db.healPrediction.enable then
+ local healPrediction = frame.HealCommBar
+ local myBar = healPrediction.myBar
+ local otherBar = healPrediction.otherBar
+ local c = self.db.colors.healPrediction
+ healPrediction.maxOverflow = 1 + (c.maxOverflow or 0)
+
+ if healPrediction.allowClippingUpdate then
+ UF:SetVisibility_HealComm(healPrediction)
+ end
+
+ if not frame:IsElementEnabled("HealComm4") then
+ frame:EnableElement("HealComm4")
+ end
+
+ if frame.db.health then
+ local health = frame.Health
+ local orientation = frame.db.health.orientation or health:GetOrientation()
+
+ myBar:SetOrientation(orientation)
+ otherBar:SetOrientation(orientation)
+
+ if orientation == "HORIZONTAL" then
+ local width = health:GetWidth()
+ width = (width > 0 and width) or health.WIDTH
+ local healthTexture = health:GetStatusBarTexture()
+
+ myBar:Size(width, 0)
+ myBar:ClearAllPoints()
+ myBar:Point("TOP", health, "TOP")
+ myBar:Point("BOTTOM", health, "BOTTOM")
+ myBar:Point("LEFT", healthTexture, "RIGHT")
+
+ otherBar:Size(width, 0)
+ otherBar:ClearAllPoints()
+ otherBar:Point("TOP", health, "TOP")
+ otherBar:Point("BOTTOM", health, "BOTTOM")
+ otherBar:Point("LEFT", myBar:GetStatusBarTexture(), "RIGHT")
+ else
+ local height = health:GetHeight()
+ height = (height > 0 and height) or health.HEIGHT
+ local healthTexture = health:GetStatusBarTexture()
+
+ myBar:Size(0, height)
+ myBar:ClearAllPoints()
+ myBar:Point("LEFT", health, "LEFT")
+ myBar:Point("RIGHT", health, "RIGHT")
+ myBar:Point("BOTTOM", healthTexture, "TOP")
+
+ otherBar:Size(0, height)
+ otherBar:ClearAllPoints()
+ otherBar:Point("LEFT", health, "LEFT")
+ otherBar:Point("RIGHT", health, "RIGHT")
+ otherBar:Point("BOTTOM", myBar:GetStatusBarTexture(), "TOP")
+ end
+ end
+
+ myBar:SetStatusBarColor(c.personal.r, c.personal.g, c.personal.b, c.personal.a)
+ otherBar:SetStatusBarColor(c.others.r, c.others.g, c.others.b, c.others.a)
+ elseif frame:IsElementEnabled("HealComm4") then
+ frame:DisableElement("HealComm4")
+ end
+end
+
+local function UpdateFillBar(frame, previousTexture, bar, amount)
+ if amount == 0 then
+ bar:Hide()
+ return previousTexture
+ end
+
+ local orientation = frame:GetOrientation()
+ bar:ClearAllPoints()
+ if orientation == "HORIZONTAL" then
+ bar:SetPoint("TOPLEFT", previousTexture, "TOPRIGHT")
+ bar:SetPoint("BOTTOMLEFT", previousTexture, "BOTTOMRIGHT")
+ else
+ bar:SetPoint("BOTTOMRIGHT", previousTexture, "TOPRIGHT")
+ bar:SetPoint("BOTTOMLEFT", previousTexture, "TOPLEFT")
+ end
+
+ local totalWidth, totalHeight = frame:GetSize()
+ if orientation == "HORIZONTAL" then
+ bar:Width(totalWidth)
+ else
+ bar:Height(totalHeight)
+ end
+
+ return bar:GetStatusBarTexture()
+end
+
+function UF:UpdateHealComm(_, myIncomingHeal, allIncomingHeal)
+ local health = self.health
+ local previousTexture = health:GetStatusBarTexture()
+
+ previousTexture = UpdateFillBar(health, previousTexture, self.myBar, myIncomingHeal)
+ UpdateFillBar(health, previousTexture, self.otherBar, allIncomingHeal)
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/Health.lua b/ElvUI/Modules/UnitFrames/Elements/Health.lua
new file mode 100644
index 0000000..d8bc7df
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/Health.lua
@@ -0,0 +1,419 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local random = random
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local UnitIsTapped = UnitIsTapped
+local UnitIsTappedByPlayer = UnitIsTappedByPlayer
+local UnitReaction = UnitReaction
+local UnitIsPlayer = UnitIsPlayer
+local UnitClass = UnitClass
+local UnitIsDeadOrGhost = UnitIsDeadOrGhost
+
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+function UF.HealthClipFrame_OnUpdate(clipFrame)
+ UF.HealthClipFrame_HealComm(clipFrame.__frame)
+
+ clipFrame:SetScript("OnUpdate", nil)
+end
+
+function UF:Construct_HealthBar(frame, bg, text, textPos)
+ local health = CreateFrame("StatusBar", nil, frame)
+ UF.statusbars[health] = true
+
+ health:SetFrameLevel(10) --Make room for Portrait and Power which should be lower by default
+ health.PostUpdate = self.PostUpdateHealth
+ health.PostUpdateColor = self.PostUpdateHealthColor
+
+ if bg then
+ health.bg = health:CreateTexture(nil, "BORDER")
+ health.bg:SetAllPoints()
+ health.bg:SetTexture(E.media.blankTex)
+ health.bg.multiplier = 0.25
+ end
+
+ if text then
+ health.value = frame.RaisedElementParent:CreateFontString(nil, "OVERLAY")
+ UF:Configure_FontString(health.value)
+
+ local x = -2
+ if textPos == "LEFT" then
+ x = 2
+ end
+
+ health.value:Point(textPos, health, textPos, x, 0)
+ end
+
+ health.colorTapping = true
+ health.colorDisconnected = true
+ health:CreateBackdrop(nil, nil, nil, self.thinBorders, true)
+
+ local clipFrame = CreateFrame("Frame", nil, health)
+ clipFrame:SetScript("OnUpdate", UF.HealthClipFrame_OnUpdate)
+ clipFrame:SetAllPoints()
+ clipFrame:EnableMouse(false)
+ clipFrame.__frame = frame
+ health.ClipFrame = clipFrame
+
+ return health
+end
+
+function UF:Configure_HealthBar(frame)
+ if not frame.VARIABLES_SET then return end
+ local db = frame.db
+ local health = frame.Health
+
+ E:SetSmoothing(health, self.db.smoothbars)
+
+ --Text
+ if db.health and health.value then
+ local attachPoint = self:GetObjectAnchorPoint(frame, db.health.attachTextTo)
+ health.value:ClearAllPoints()
+ health.value:Point(db.health.position, attachPoint, db.health.position, db.health.xOffset, db.health.yOffset)
+ frame:Tag(health.value, db.health.text_format)
+ end
+
+ --Colors
+ health.colorSmooth = nil
+ health.colorHealth = nil
+ health.colorClass = nil
+ health.colorReaction = nil
+
+ if db.colorOverride and db.colorOverride == "FORCE_ON" then
+ health.colorClass = true
+ health.colorReaction = true
+ elseif db.colorOverride and db.colorOverride == "FORCE_OFF" then
+ if self.db.colors.colorhealthbyvalue then
+ health.colorSmooth = true
+ else
+ health.colorHealth = true
+ end
+ else
+ if self.db.colors.healthclass ~= true then
+ if self.db.colors.colorhealthbyvalue then
+ health.colorSmooth = true
+ else
+ health.colorHealth = true
+ end
+ else
+ health.colorClass = (not self.db.colors.forcehealthreaction)
+ health.colorReaction = true
+ end
+ end
+
+ --Position
+ health:ClearAllPoints()
+ health.WIDTH = db.width
+ health.HEIGHT = db.height
+
+ if frame.ORIENTATION == "LEFT" then
+ health:Point("TOPRIGHT", frame, "TOPRIGHT",
+ -frame.BORDER - frame.SPACING - (frame.HAPPINESS_WIDTH or 0),
+ -frame.BORDER - frame.SPACING - frame.CLASSBAR_YOFFSET
+ )
+
+ if frame.USE_POWERBAR_OFFSET or frame.USE_ENERGYBAR_OFFSET or frame.USE_RAGEBAR_OFFSET then
+ local totalOffset = 0
+ if frame.USE_POWERBAR and frame.USE_POWERBAR_OFFSET then
+ totalOffset = totalOffset + frame.POWERBAR_OFFSET
+ end
+ if frame.USE_ENERGYBAR and frame.USE_ENERGYBAR_OFFSET then
+ totalOffset = totalOffset + frame.ENERGYBAR_OFFSET
+ end
+ if frame.USE_RAGEBAR and frame.USE_RAGEBAR_OFFSET then
+ totalOffset = totalOffset + frame.RAGEBAR_OFFSET
+ end
+
+ health:Point("TOPRIGHT", frame, "TOPRIGHT",
+ -frame.BORDER - frame.SPACING - totalOffset - (frame.HAPPINESS_WIDTH or 0),
+ -frame.BORDER - frame.SPACING - frame.CLASSBAR_YOFFSET
+ )
+ health:Point("BOTTOMLEFT", frame, "BOTTOMLEFT",
+ frame.PORTRAIT_WIDTH + frame.BORDER + frame.SPACING,
+ frame.BORDER + frame.SPACING + totalOffset
+ )
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + totalOffset + (frame.HAPPINESS_WIDTH or 0)) - (frame.BORDER + frame.SPACING + frame.PORTRAIT_WIDTH)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.BORDER + frame.SPACING + totalOffset)
+ elseif frame.POWERBAR_DETACHED or not frame.USE_POWERBAR or frame.USE_INSET_POWERBAR then
+ health:Point("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.PORTRAIT_WIDTH + frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + (frame.HAPPINESS_WIDTH or 0)) - (frame.BORDER + frame.SPACING + frame.PORTRAIT_WIDTH)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
+ elseif frame.USE_MINI_POWERBAR or frame.USE_MINI_ENERGYBAR or frame.USE_MINI_RAGEBAR then
+ local totalHeight = 0
+ if frame.USE_POWERBAR and frame.USE_MINI_POWERBAR then
+ totalHeight = totalHeight + (frame.POWERBAR_HEIGHT - frame.BORDER)
+ end
+ if frame.USE_ENERGYBAR and frame.USE_MINI_ENERGYBAR then
+ totalHeight = totalHeight + (frame.ENERGYBAR_HEIGHT - frame.BORDER)
+ end
+ if frame.USE_RAGEBAR and frame.USE_MINI_RAGEBAR then
+ totalHeight = totalHeight + (frame.RAGEBAR_HEIGHT - frame.BORDER)
+ end
+ health:Point("BOTTOMLEFT", frame, "BOTTOMLEFT",
+ frame.PORTRAIT_WIDTH + frame.BORDER + frame.SPACING,
+ frame.SPACING + (totalHeight / 2)
+ )
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + (frame.HAPPINESS_WIDTH or 0)) - (frame.BORDER + frame.SPACING + frame.PORTRAIT_WIDTH)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.SPACING + totalHeight / 2)
+ else
+ health:Point("BOTTOMLEFT", frame, "BOTTOMLEFT",
+ frame.PORTRAIT_WIDTH + frame.BORDER + frame.SPACING,
+ frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET
+ )
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + (frame.HAPPINESS_WIDTH or 0)) - (frame.BORDER + frame.SPACING + frame.PORTRAIT_WIDTH)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
+ end
+ elseif frame.ORIENTATION == "RIGHT" then
+ health:Point("TOPLEFT", frame, "TOPLEFT", frame.BORDER + frame.SPACING + (frame.HAPPINESS_WIDTH or 0), -frame.BORDER - frame.SPACING - frame.CLASSBAR_YOFFSET)
+
+ if frame.USE_POWERBAR_OFFSET or frame.USE_ENERGYBAR_OFFSET or frame.USE_RAGEBAR_OFFSET then
+ local totalOffset = 0
+ if frame.USE_POWERBAR and frame.USE_POWERBAR_OFFSET then
+ totalOffset = totalOffset + frame.POWERBAR_OFFSET
+ end
+ if frame.USE_ENERGYBAR and frame.USE_ENERGYBAR_OFFSET then
+ totalOffset = totalOffset + frame.ENERGYBAR_OFFSET
+ end
+ if frame.USE_RAGEBAR and frame.USE_RAGEBAR_OFFSET then
+ totalOffset = totalOffset + frame.RAGEBAR_OFFSET
+ end
+
+ health:Point("TOPLEFT", frame, "TOPLEFT",
+ frame.BORDER + frame.SPACING + totalOffset + (frame.HAPPINESS_WIDTH or 0),
+ -frame.BORDER - frame.SPACING - frame.CLASSBAR_YOFFSET
+ )
+ health:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT",
+ -frame.PORTRAIT_WIDTH - frame.BORDER - frame.SPACING,
+ frame.BORDER + frame.SPACING + totalOffset
+ )
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + totalOffset + (frame.HAPPINESS_WIDTH or 0)) - (frame.BORDER + frame.SPACING + frame.PORTRAIT_WIDTH)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.BORDER + frame.SPACING + totalOffset)
+ elseif frame.POWERBAR_DETACHED or not frame.USE_POWERBAR or frame.USE_INSET_POWERBAR then
+ health:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -frame.PORTRAIT_WIDTH - frame.BORDER - frame.SPACING, frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + (frame.HAPPINESS_WIDTH or 0)) - (frame.BORDER + frame.SPACING + frame.PORTRAIT_WIDTH)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
+ elseif frame.USE_MINI_POWERBAR or frame.USE_MINI_ENERGYBAR or frame.USE_MINI_RAGEBAR then
+ local totalHeight = 0
+ if frame.USE_POWERBAR and frame.USE_MINI_POWERBAR then
+ totalHeight = totalHeight + (frame.POWERBAR_HEIGHT - frame.BORDER)
+ end
+ if frame.USE_ENERGYBAR and frame.USE_MINI_ENERGYBAR then
+ totalHeight = totalHeight + (frame.ENERGYBAR_HEIGHT - frame.BORDER)
+ end
+ if frame.USE_RAGEBAR and frame.USE_MINI_RAGEBAR then
+ totalHeight = totalHeight + (frame.RAGEBAR_HEIGHT - frame.BORDER)
+ end
+ health:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT",
+ -frame.PORTRAIT_WIDTH - frame.BORDER - frame.SPACING,
+ frame.SPACING + (totalHeight / 2)
+ )
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + (frame.HAPPINESS_WIDTH or 0)) - (frame.BORDER + frame.SPACING + frame.PORTRAIT_WIDTH)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.SPACING + totalHeight / 2)
+ else
+ health:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -frame.PORTRAIT_WIDTH - frame.BORDER - frame.SPACING, frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + (frame.HAPPINESS_WIDTH or 0)) - (frame.BORDER + frame.SPACING + frame.PORTRAIT_WIDTH)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
+ end
+ elseif frame.ORIENTATION == "MIDDLE" then
+ health:Point("TOPRIGHT", frame, "TOPRIGHT", -frame.BORDER - frame.SPACING - (frame.HAPPINESS_WIDTH or 0), -frame.BORDER - frame.SPACING - frame.CLASSBAR_YOFFSET)
+
+ if frame.USE_POWERBAR_OFFSET or frame.USE_ENERGYBAR_OFFSET or frame.USE_RAGEBAR_OFFSET then
+ local totalOffset = 0
+ if frame.USE_POWERBAR and frame.USE_POWERBAR_OFFSET then
+ totalOffset = totalOffset + frame.POWERBAR_OFFSET
+ end
+ if frame.USE_ENERGYBAR and frame.USE_ENERGYBAR_OFFSET then
+ totalOffset = totalOffset + frame.ENERGYBAR_OFFSET
+ end
+ if frame.USE_RAGEBAR and frame.USE_RAGEBAR_OFFSET then
+ totalOffset = totalOffset + frame.RAGEBAR_OFFSET
+ end
+
+ health:Point("TOPRIGHT", frame, "TOPRIGHT",
+ -frame.BORDER - frame.SPACING - totalOffset,
+ -frame.BORDER - frame.SPACING - frame.CLASSBAR_YOFFSET
+ )
+ health:Point("BOTTOMLEFT", frame, "BOTTOMLEFT",
+ frame.BORDER + frame.SPACING + totalOffset,
+ frame.BORDER + frame.SPACING + totalOffset
+ )
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + totalOffset) - (frame.BORDER + frame.SPACING + totalOffset)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.BORDER + frame.SPACING + totalOffset)
+ elseif frame.POWERBAR_DETACHED or not frame.USE_POWERBAR or frame.USE_INSET_POWERBAR then
+ health:Point("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + (frame.HAPPINESS_WIDTH or 0)) - (frame.BORDER + frame.SPACING)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
+ elseif frame.USE_MINI_POWERBAR then
+ local totalHeight = 0
+ if frame.USE_POWERBAR and frame.USE_MINI_POWERBAR then
+ totalHeight = totalHeight + (frame.POWERBAR_HEIGHT - frame.BORDER)
+ end
+ if frame.USE_ENERGYBAR and frame.USE_MINI_ENERGYBAR then
+ totalHeight = totalHeight + (frame.ENERGYBAR_HEIGHT - frame.BORDER)
+ end
+ if frame.USE_RAGEBAR and frame.USE_MINI_RAGEBAR then
+ totalHeight = totalHeight + (frame.RAGEBAR_HEIGHT - frame.BORDER)
+ end
+ health:Point("BOTTOMLEFT", frame, "BOTTOMLEFT",
+ frame.BORDER + frame.SPACING,
+ frame.SPACING + (totalHeight / 2)
+ )
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + (frame.HAPPINESS_WIDTH or 0)) - (frame.BORDER + frame.SPACING)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.SPACING + totalHeight / 2)
+ else
+ health:Point("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.PORTRAIT_WIDTH + frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
+
+ health.WIDTH = health.WIDTH - (frame.BORDER + frame.SPACING + (frame.HAPPINESS_WIDTH or 0)) - (frame.BORDER + frame.SPACING + frame.PORTRAIT_WIDTH)
+ health.HEIGHT = health.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
+ end
+ end
+
+ if db.health then
+ --Party/Raid Frames allow to change statusbar orientation
+ if db.health.orientation then
+ health:SetOrientation(db.health.orientation)
+ end
+
+ --Party/Raid Frames can toggle frequent updates
+ if db.health.frequentUpdates == nil then
+ db.health.frequentUpdates = true
+ end
+
+ --health:SetFrequentUpdates(db.health.frequentUpdates)
+ end
+
+ --Transparency Settings
+ UF:ToggleTransparentStatusBar(UF.db.colors.transparentHealth, frame.Health, frame.Health.bg, true, nil)
+
+ --Prediction Texture; keep under ToggleTransparentStatusBar
+ UF:UpdatePredictionStatusBar(frame.HealthPrediction, frame.Health)
+
+ --Highlight Texture
+ UF:Configure_FrameGlow(frame)
+
+ if frame:IsElementEnabled("Health") then
+ frame.Health:ForceUpdate()
+ end
+end
+
+function UF:GetHealthBottomOffset(frame)
+ local bottomOffset = 0
+ if frame.USE_POWERBAR and not frame.POWERBAR_DETACHED and not frame.USE_INSET_POWERBAR then
+ bottomOffset = bottomOffset + frame.POWERBAR_HEIGHT - (frame.BORDER-frame.SPACING)
+ end
+ if frame.USE_ENERGYBAR and not frame.ENERGYBAR_DETACHED and not frame.USE_INSET_ENERGYBAR then
+ bottomOffset = bottomOffset + frame.ENERGYBAR_HEIGHT - (frame.BORDER-frame.SPACING)
+ end
+ if frame.USE_RAGEBAR and not frame.RAGEBAR_DETACHED and not frame.USE_INSET_RAGEBAR then
+ bottomOffset = bottomOffset + frame.RAGEBAR_HEIGHT - (frame.BORDER-frame.SPACING)
+ end
+ if frame.USE_INFO_PANEL then
+ bottomOffset = bottomOffset + frame.INFO_PANEL_HEIGHT - (frame.BORDER - frame.SPACING)
+ end
+
+ return bottomOffset
+end
+
+function UF:PostUpdateHealthColor(unit, r, g, b)
+ local parent = self:GetParent()
+ local colors = E.db.unitframe.colors
+
+ local newr, newg, newb -- fallback for bg if custom settings arent used
+ if not b then r, g, b = colors.health.r, colors.health.g, colors.health.b end
+ if (((colors.healthclass and colors.colorhealthbyvalue) or (colors.colorhealthbyvalue and parent.isForced) or colors.colorhealthbyvalue_threshold) and not (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit))) then
+ local cur, max = self.cur or 1, self.max or 100
+ if parent.isForced then
+ cur = parent.forcedHealth or cur
+ max = (cur > max and cur * 2) or max
+ end
+ if colors.colorhealthbyvalue then
+ newr, newg, newb = ElvUF:ColorGradient(cur, max, 1, 0, 0, 1, 1, 0, r, g, b)
+ elseif colors.colorhealthbyvalue_threshold then
+ local perc = cur / max
+ if perc > 0.75 then
+ if colors.colorhealthbyvalue_thresholdgradient then
+ newr, newg, newb = ElvUF:ColorGradient(perc, 1, r, g, b, colors.threshold_75.r, colors.threshold_75.g, colors.threshold_75.b, r, g, b)
+ else
+ newr, newg, newb = r, g, b
+ end
+ elseif perc > 0.5 then
+ if colors.colorhealthbyvalue_thresholdgradient then
+ newr, newg, newb = ElvUF:ColorGradient(((perc / .5) + 1), 2.5, r, g, b, colors.threshold_50.r, colors.threshold_50.g, colors.threshold_50.b, colors.threshold_75.r, colors.threshold_75.g, colors.threshold_75.b)
+ else
+ newr, newg, newb = colors.threshold_75.r, colors.threshold_75.g, colors.threshold_75.b
+ end
+ elseif perc > 0.35 then
+ if colors.colorhealthbyvalue_thresholdgradient then
+ newr, newg, newb = ElvUF:ColorGradient(((perc / .35) + 1), 2.43, r, g, b, colors.threshold_35.r, colors.threshold_35.g, colors.threshold_35.b, colors.threshold_50.r, colors.threshold_50.g, colors.threshold_50.b)
+ else
+ newr, newg, newb = colors.threshold_50.r, colors.threshold_50.g, colors.threshold_50.b
+ end
+ elseif perc > 0.2 then
+ if colors.colorhealthbyvalue_thresholdgradient then
+ newr, newg, newb = ElvUF:ColorGradient(((perc / .2) + 1), 2.75, r, g, b, colors.threshold_20.r, colors.threshold_20.g, colors.threshold_20.b, colors.threshold_35.r, colors.threshold_35.g, colors.threshold_35.b)
+ else
+ newr, newg, newb = colors.threshold_35.r, colors.threshold_35.g, colors.threshold_35.b
+ end
+ else
+ newr, newg, newb = colors.threshold_20.r, colors.threshold_20.g, colors.threshold_20.b
+ end
+ end
+ self:SetStatusBarColor(newr, newg, newb)
+ end
+
+ if self.bg then
+ self.bg.multiplier = (colors.healthMultiplier > 0 and colors.healthMultiplier) or 0.35
+
+ if colors.useDeadBackdrop and UnitIsDeadOrGhost(unit) then
+ self.bg:SetVertexColor(colors.health_backdrop_dead.r, colors.health_backdrop_dead.g, colors.health_backdrop_dead.b)
+ elseif colors.customhealthbackdrop then
+ self.bg:SetVertexColor(colors.health_backdrop.r, colors.health_backdrop.g, colors.health_backdrop.b)
+ elseif colors.classbackdrop then
+ local reaction, color = (UnitReaction(unit, "player"))
+
+ if UnitIsPlayer(unit) then
+ local _, Class = UnitClass(unit)
+ color = parent.colors.class[Class]
+ elseif reaction then
+ color = parent.colors.reaction[reaction]
+ end
+
+ if color then
+ self.bg:SetVertexColor(color[1] * self.bg.multiplier, color[2] * self.bg.multiplier, color[3] * self.bg.multiplier)
+ end
+ elseif newb then
+ self.bg:SetVertexColor(newr * self.bg.multiplier, newg * self.bg.multiplier, newb * self.bg.multiplier)
+ else
+ self.bg:SetVertexColor(r * self.bg.multiplier, g * self.bg.multiplier, b * self.bg.multiplier)
+ end
+ end
+end
+
+function UF:PostUpdateHealth(_, _, max)
+ local parent = self:GetParent()
+ if parent.isForced then
+ local cur = random(1, max or 100)
+ parent.forcedHealth = cur
+ self:SetValue(cur)
+ else
+ if parent.forcedHealth then
+ parent.forcedHealth = nil
+ end
+ end
+end
diff --git a/ElvUI/Modules/UnitFrames/Elements/InfoPanel.lua b/ElvUI/Modules/UnitFrames/Elements/InfoPanel.lua
new file mode 100644
index 0000000..467a5a5
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/InfoPanel.lua
@@ -0,0 +1,61 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+function UF:Construct_InfoPanel(frame)
+ local infoPanel = CreateFrame("Frame", nil, frame)
+
+ infoPanel:SetFrameLevel(7) --Health is 10 and filled power is 5 by default
+ local thinBorders = self.thinBorders
+ infoPanel:CreateBackdrop(nil, true, nil, thinBorders, true)
+
+ return infoPanel
+end
+
+function UF:Configure_InfoPanel(frame, noTemplateChange)
+ if not frame.VARIABLES_SET then return end
+ local db = frame.db
+
+ if frame.USE_INFO_PANEL then
+ frame.InfoPanel:Show()
+ frame.InfoPanel:ClearAllPoints()
+
+ if frame.ORIENTATION == "RIGHT" and frame.unitframeType ~= "arena" then
+ frame.InfoPanel:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -frame.BORDER - frame.SPACING, frame.BORDER + frame.SPACING)
+ if frame.USE_RAGEBAR and not frame.USE_INSET_RAGEBAR and not frame.RAGEBAR_DETACHED then
+ frame.InfoPanel:Point("TOPLEFT", frame.Rage.backdrop, "BOTTOMLEFT", frame.BORDER, -(frame.SPACING*3))
+ elseif frame.USE_ENERGYBAR and not frame.USE_INSET_ENERGYBAR and not frame.ENERGYBAR_DETACHED then
+ frame.InfoPanel:Point("TOPLEFT", frame.Energy.backdrop, "BOTTOMLEFT", frame.BORDER, -(frame.SPACING*3))
+ elseif frame.USE_POWERBAR and not frame.USE_INSET_POWERBAR and not frame.POWERBAR_DETACHED then
+ frame.InfoPanel:Point("TOPLEFT", frame.Power.backdrop, "BOTTOMLEFT", frame.BORDER, -(frame.SPACING*3))
+ else
+ frame.InfoPanel:Point("TOPLEFT", frame.Health.backdrop, "BOTTOMLEFT", frame.BORDER, -(frame.SPACING*3))
+ end
+ else
+ frame.InfoPanel:Point("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING)
+ if frame.USE_RAGEBAR and not frame.USE_INSET_RAGEBAR and not frame.RAGEBAR_DETACHED then
+ frame.InfoPanel:Point("TOPRIGHT", frame.Rage.backdrop, "BOTTOMRIGHT", -frame.BORDER, -(frame.SPACING*3))
+ elseif frame.USE_ENERGYBAR and not frame.USE_INSET_ENERGYBAR and not frame.ENERGYBAR_DETACHED then
+ frame.InfoPanel:Point("TOPRIGHT", frame.Energy.backdrop, "BOTTOMRIGHT", -frame.BORDER, -(frame.SPACING*3))
+ elseif frame.USE_POWERBAR and not frame.USE_INSET_POWERBAR and not frame.POWERBAR_DETACHED then
+ frame.InfoPanel:Point("TOPRIGHT", frame.Power.backdrop, "BOTTOMRIGHT", -frame.BORDER, -(frame.SPACING*3))
+ else
+ frame.InfoPanel:Point("TOPRIGHT", frame.Health.backdrop, "BOTTOMRIGHT", -frame.BORDER, -(frame.SPACING*3))
+ end
+ end
+
+ if (not noTemplateChange) then
+ local thinBorders = self.thinBorders
+ if db.infoPanel.transparent then
+ frame.InfoPanel.backdrop:SetTemplate("Transparent", nil, nil, thinBorders, true)
+ else
+ frame.InfoPanel.backdrop:SetTemplate(nil, true, nil, thinBorders, true)
+ end
+ end
+ else
+ frame.InfoPanel:Hide()
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/Load_Elements.xml b/ElvUI/Modules/UnitFrames/Elements/Load_Elements.xml
new file mode 100644
index 0000000..ebe1e96
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/Load_Elements.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/Name.lua b/ElvUI/Modules/UnitFrames/Elements/Name.lua
new file mode 100644
index 0000000..602a8bf
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/Name.lua
@@ -0,0 +1,50 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+local UnitIsPlayer = UnitIsPlayer
+
+function UF:Construct_NameText(frame)
+ local name = frame.RaisedElementParent:CreateFontString(nil, "OVERLAY")
+ UF:Configure_FontString(name)
+ name:Point("CENTER", frame.Health)
+
+ return name
+end
+
+function UF:UpdateNameSettings(frame, childType)
+ local db = frame.db
+ if childType == "pet" then
+ db = frame.db.petsGroup
+ elseif childType == "target" then
+ db = frame.db.targetsGroup
+ end
+
+ local name = frame.Name
+ if not db.power or not db.power.enable or not db.power.hideonnpc then
+ local attachPoint = self:GetObjectAnchorPoint(frame, db.name.attachTextTo)
+ name:ClearAllPoints()
+ name:Point(db.name.position, attachPoint, db.name.position, db.name.xOffset, db.name.yOffset)
+ end
+
+ frame:Tag(name, db.name.text_format)
+end
+
+function UF:PostNamePosition(frame, unit)
+ if not frame.Power.value:IsShown() then return end
+ local db = frame.db
+ if UnitIsPlayer(unit) or (db.power and not db.power.enable) then
+ local position = db.name.position
+ local attachPoint = self:GetObjectAnchorPoint(frame, db.name.attachTextTo)
+ frame.Power.value:SetAlpha(1)
+
+ frame.Name:ClearAllPoints()
+ frame.Name:Point(position, attachPoint, position, db.name.xOffset, db.name.yOffset)
+ else
+ frame.Power.value:SetAlpha(db.power.hideonnpc and 0 or 1)
+
+ frame.Name:ClearAllPoints()
+ frame.Name:Point(frame.Power.value:GetPoint())
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/Portrait.lua b/ElvUI/Modules/UnitFrames/Elements/Portrait.lua
new file mode 100644
index 0000000..7635da6
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/Portrait.lua
@@ -0,0 +1,139 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+function UF:Construct_Portrait(frame, type)
+ local portrait
+
+ if type == "texture" then
+ local backdrop = CreateFrame("Frame", nil, frame)
+ portrait = frame:CreateTexture(nil, "OVERLAY")
+ portrait:SetTexCoord(0.15, 0.85, 0.15, 0.85)
+ backdrop:SetOutside(portrait)
+ backdrop:SetFrameLevel(frame:GetFrameLevel())
+ backdrop:SetTemplate("Default")
+ portrait.backdrop = backdrop
+ else
+ portrait = CreateFrame("PlayerModel", nil, frame)
+ portrait:CreateBackdrop("Default", nil, nil, self.thinBorders, true)
+ end
+
+ portrait.PostUpdate = self.PortraitUpdate
+
+ return portrait
+end
+
+function UF:Configure_Portrait(frame, dontHide)
+ if not frame.VARIABLES_SET then return end
+ local db = frame.db
+
+ if frame.Portrait and not dontHide then
+ frame.Portrait:Hide()
+ frame.Portrait:ClearAllPoints()
+ frame.Portrait.backdrop:Hide()
+ end
+ frame.Portrait = db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D
+
+ local portrait = frame.Portrait
+ if frame.USE_PORTRAIT then
+ if not frame:IsElementEnabled("Portrait") then
+ frame:EnableElement("Portrait")
+ end
+
+ local color = E.db.unitframe.colors.borderColor
+ portrait.backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
+
+ portrait:ClearAllPoints()
+ portrait.backdrop:ClearAllPoints()
+ if frame.USE_PORTRAIT_OVERLAY then
+ if db.portrait.style == "3D" then
+ portrait:SetFrameLevel(frame.Health:GetFrameLevel() + 1)
+ else
+ portrait:SetParent(frame.Health)
+ end
+
+ portrait:SetAlpha(db.portrait.overlayAlpha)
+ if not dontHide then
+ portrait:Show()
+ end
+ portrait.backdrop:Hide()
+
+ portrait:ClearAllPoints()
+ if db.portrait.fullOverlay then
+ portrait:SetAllPoints(frame.Health)
+ else
+ local statusBarTex = frame.Health:GetStatusBarTexture()
+ if frame.Health:GetOrientation() == "VERTICAL" then
+ portrait:SetPoint("BOTTOMLEFT", frame.Health)
+ portrait:SetPoint("TOPRIGHT", statusBarTex, "TOPRIGHT")
+ else
+ portrait:SetPoint("TOPLEFT", frame.Health)
+ portrait:SetPoint("BOTTOMRIGHT", statusBarTex, "BOTTOMRIGHT")
+ end
+ end
+ else
+ portrait:ClearAllPoints()
+ portrait:SetAllPoints()
+ portrait:SetAlpha(1)
+ if not dontHide then
+ portrait:Show()
+ end
+ portrait.backdrop:Show()
+ if db.portrait.style == "3D" then
+ portrait:SetFrameLevel(frame.Health:GetFrameLevel() -4) --Make sure portrait is behind Health and Power
+ else
+ portrait:SetParent(frame)
+ end
+
+ if frame.ORIENTATION == "LEFT" then
+ portrait.backdrop:Point("TOPLEFT", frame, "TOPLEFT", frame.SPACING, frame.USE_MINI_CLASSBAR and -(frame.CLASSBAR_YOFFSET+frame.SPACING) or -frame.SPACING)
+
+ if frame.USE_RAGEBAR and not frame.USE_INSET_RAGEBAR and not frame.RAGEBAR_DETACHED and not frame.USE_MINI_RAGEBAR and not frame.USE_RAGEBAR_OFFSET then
+ portrait.backdrop:Point("BOTTOMRIGHT", frame.Rage.backdrop, "BOTTOMLEFT", frame.BORDER - frame.SPACING*3, 0)
+ elseif frame.USE_ENERGYBAR and not frame.USE_INSET_ENERGYBAR and not frame.ENERGYBAR_DETACHED and not frame.USE_MINI_ENERGYBAR and not frame.USE_ENERGYBAR_OFFSET then
+ portrait.backdrop:Point("BOTTOMRIGHT", frame.Energy.backdrop, "BOTTOMLEFT", frame.BORDER - frame.SPACING*3, 0)
+ elseif frame.USE_POWERBAR and not frame.USE_INSET_POWERBAR and not frame.POWERBAR_DETACHED and not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET then
+ portrait.backdrop:Point("BOTTOMRIGHT", frame.Power.backdrop, "BOTTOMLEFT", frame.BORDER - frame.SPACING*3, 0)
+ else
+ portrait.backdrop:Point("BOTTOMRIGHT", frame.Health.backdrop, "BOTTOMLEFT", frame.BORDER - frame.SPACING*3, 0)
+ end
+ elseif frame.ORIENTATION == "RIGHT" then
+ portrait.backdrop:Point("TOPRIGHT", frame, "TOPRIGHT", -frame.SPACING, frame.USE_MINI_CLASSBAR and -(frame.CLASSBAR_YOFFSET+frame.SPACING) or -frame.SPACING)
+
+ if frame.USE_RAGEBAR and not frame.USE_INSET_RAGEBAR and not frame.RAGEBAR_DETACHED and not frame.USE_MINI_RAGEBAR and not frame.USE_RAGEBAR_OFFSET then
+ portrait.backdrop:Point("BOTTOMLEFT", frame.Rage.backdrop, "BOTTOMRIGHT", -frame.BORDER + frame.SPACING*3, 0)
+ elseif frame.USE_ENERGYBAR and not frame.USE_INSET_ENERGYBAR and not frame.ENERGYBAR_DETACHED and not frame.USE_MINI_ENERGYBAR and not frame.USE_ENERGYBAR_OFFSET then
+ portrait.backdrop:Point("BOTTOMLEFT", frame.Energy.backdrop, "BOTTOMRIGHT", -frame.BORDER + frame.SPACING*3, 0)
+ elseif frame.USE_POWERBAR and not frame.USE_INSET_POWERBAR and not frame.POWERBAR_DETACHED and not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET then
+ portrait.backdrop:Point("BOTTOMLEFT", frame.Power.backdrop, "BOTTOMRIGHT", -frame.BORDER + frame.SPACING*3, 0)
+ else
+ portrait.backdrop:Point("BOTTOMLEFT", frame.Health.backdrop, "BOTTOMRIGHT", -frame.BORDER + frame.SPACING*3, 0)
+ end
+ end
+
+ portrait:SetInside(portrait.backdrop, frame.BORDER)
+ end
+ else
+ if frame:IsElementEnabled("Portrait") then
+ frame:DisableElement("Portrait")
+ portrait:Hide()
+ portrait.backdrop:Hide()
+ end
+ end
+end
+
+function UF:PortraitUpdate()
+ local db = self:GetParent().db
+ if not db then return end
+
+ local portrait = db.portrait
+ if portrait.enable and self:GetParent().USE_PORTRAIT_OVERLAY then
+ self:SetAlpha(0)
+ self:SetAlpha(db.portrait.overlayAlpha)
+ else
+ self:SetAlpha(1)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/Power.lua b/ElvUI/Modules/UnitFrames/Elements/Power.lua
new file mode 100644
index 0000000..e76ff5a
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/Power.lua
@@ -0,0 +1,345 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local random = random
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+function UF:Construct_PowerBar(frame, bg, text, textPos)
+ local power = CreateFrame("StatusBar", nil, frame)
+ UF.statusbars[power] = true
+
+ power.RaisedElementParent = CreateFrame("Frame", nil, power)
+ power.RaisedElementParent:SetFrameLevel(power:GetFrameLevel() + 100)
+ power.RaisedElementParent:SetAllPoints()
+
+ power.PostUpdate = self.PostUpdatePower
+ power.PostUpdateColor = self.PostUpdatePowerColor
+
+ if bg then
+ power.BG = power:CreateTexture(nil, "BORDER")
+ power.BG:SetAllPoints()
+ power.BG:SetTexture(E.media.blankTex)
+ end
+
+ if text then
+ power.value = frame.RaisedElementParent:CreateFontString(nil, "OVERLAY")
+ UF:Configure_FontString(power.value)
+
+ local x = -2
+ if textPos == "LEFT" then
+ x = 2
+ end
+
+ power.value:Point(textPos, frame.Health, textPos, x, 0)
+
+ power.value.frequentUpdates = true
+ end
+
+ power.colorDisconnected = false
+ power.colorTapping = false
+ power:CreateBackdrop("Default", nil, nil, self.thinBorders, true)
+
+ local clipFrame = CreateFrame('Frame', nil, power)
+ clipFrame:SetAllPoints()
+ clipFrame:EnableMouse(false)
+ clipFrame.__frame = frame
+ power.ClipFrame = clipFrame
+
+ return power
+end
+
+function UF:Configure_Power(frame)
+ if not frame.VARIABLES_SET then return end
+ local db = frame.db
+ local power = frame.Power
+ power.origParent = frame
+
+ if frame.USE_POWERBAR then
+ if not frame:IsElementEnabled("Power") then
+ frame:EnableElement("Power")
+ power:Show()
+ end
+
+ E:SetSmoothing(power, self.db.smoothbars)
+
+ --Text
+ local attachPoint = self:GetObjectAnchorPoint(frame, db.power.attachTextTo)
+ power.value:ClearAllPoints()
+ power.value:Point(db.power.position, attachPoint, db.power.position, db.power.xOffset, db.power.yOffset)
+ frame:Tag(power.value, db.power.text_format)
+
+ if db.power.attachTextTo == "Power" then
+ power.value:SetParent(power.RaisedElementParent)
+ else
+ power.value:SetParent(frame.RaisedElementParent)
+ end
+
+ --Colors
+ power.colorClass = nil
+ power.colorReaction = nil
+ power.colorPower = nil
+
+ if self.db.colors.powerclass then
+ power.colorClass = true
+ power.colorReaction = true
+ else
+ power.colorPower = true
+ end
+
+ --Fix height in case it is lower than the theme allows
+ local heightChanged = false
+ if (not self.thinBorders and not E.PixelMode) and frame.POWERBAR_HEIGHT < 7 then --A height of 7 means 6px for borders and just 1px for the actual power statusbar
+ frame.POWERBAR_HEIGHT = 7
+ if db.power then db.power.height = 7 end
+ heightChanged = true
+ elseif (self.thinBorders or E.PixelMode) and frame.POWERBAR_HEIGHT < 3 then --A height of 3 means 2px for borders and just 1px for the actual power statusbar
+ frame.POWERBAR_HEIGHT = 3
+ if db.power then db.power.height = 3 end
+ heightChanged = true
+ end
+ if heightChanged then
+ --Update health size
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+ UF:Configure_HealthBar(frame)
+ end
+
+ --Position
+ power:ClearAllPoints()
+ if frame.POWERBAR_DETACHED then
+ power:Width(frame.POWERBAR_WIDTH - ((frame.BORDER + frame.SPACING)*2))
+ power:Height(frame.POWERBAR_HEIGHT - ((frame.BORDER + frame.SPACING)*2))
+ if not power.Holder or (power.Holder and not power.Holder.mover) then
+ power.Holder = CreateFrame("Frame", nil, power)
+ power.Holder:Size(frame.POWERBAR_WIDTH, frame.POWERBAR_HEIGHT)
+ power.Holder:Point("BOTTOM", frame, "BOTTOM", 0, -20)
+ power:ClearAllPoints()
+ power:Point("BOTTOMLEFT", power.Holder, "BOTTOMLEFT", frame.BORDER+frame.SPACING, frame.BORDER+frame.SPACING)
+ --Currently only Player and Target can detach power bars, so doing it this way is okay for now
+ if frame.unitframeType and frame.unitframeType == "player" then
+ E:CreateMover(power.Holder, "PlayerPowerBarMover", L["Player Powerbar"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,player,power")
+ elseif frame.unitframeType and frame.unitframeType == "target" then
+ E:CreateMover(power.Holder, "TargetPowerBarMover", L["Target Powerbar"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,target,power")
+ end
+ else
+ power.Holder:Size(frame.POWERBAR_WIDTH, frame.POWERBAR_HEIGHT)
+ power:ClearAllPoints()
+ power:Point("BOTTOMLEFT", power.Holder, "BOTTOMLEFT", frame.BORDER+frame.SPACING, frame.BORDER+frame.SPACING)
+ power.Holder.mover:SetScale(1)
+ power.Holder.mover:SetAlpha(1)
+ end
+
+ power:SetFrameLevel(50) --RaisedElementParent uses 100, we want lower value to allow certain icons and texts to appear above power
+ elseif frame.USE_POWERBAR_OFFSET then
+ if frame.ORIENTATION == "LEFT" then
+ power:Point("TOPRIGHT", frame.Health, "TOPRIGHT",
+ frame.POWERBAR_OFFSET + (frame.HAPPINESS_WIDTH or 0),
+ -frame.POWERBAR_OFFSET
+ )
+ power:Point("BOTTOMLEFT", frame.Health, "BOTTOMLEFT",
+ frame.POWERBAR_OFFSET,
+ -frame.POWERBAR_OFFSET
+ )
+ elseif frame.ORIENTATION == "MIDDLE" then
+ local totalOffset = 0
+ if frame.USE_ENERGYBAR and frame.USE_ENERGYBAR_OFFSET then
+ totalOffset = totalOffset + frame.ENERGYBAR_OFFSET
+ end
+ if frame.USE_RAGEBAR and frame.USE_RAGEBAR_OFFSET then
+ totalOffset = totalOffset + frame.RAGEBAR_OFFSET
+ end
+
+ power:Point("TOPLEFT", frame, "TOPLEFT",
+ frame.BORDER + frame.SPACING + totalOffset,
+ -(frame.POWERBAR_OFFSET + frame.CLASSBAR_YOFFSET) --+ frame.BORDER - frame.SPACING)
+ )
+ power:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT",
+ -(frame.BORDER + frame.SPACING + totalOffset),
+ frame.BORDER + frame.SPACING + totalOffset
+ )
+
+ --power.WIDTH = power.WIDTH - (frame.BORDER + frame.SPACING + totalOffset) - (frame.BORDER + frame.SPACING + totalOffset)
+ --power.HEIGHT = power.HEIGHT - (frame.BORDER + frame.SPACING + frame.CLASSBAR_YOFFSET) - (frame.BORDER + frame.SPACING + totalOffset)
+
+ --[[local totalOffset = 0
+ if frame.USE_ENERGYBAR_OFFSET then
+ totalOffset = totalOffset + frame.ENERGYBAR_OFFSET
+ end
+ if frame.USE_RAGEBAR_OFFSET then
+ totalOffset = totalOffset + frame.RAGEBAR_OFFSET
+ end
+ power:Point("TOPLEFT", frame, "TOPLEFT",
+ frame.BORDER + frame.SPACING,
+ -frame.POWERBAR_OFFSET - frame.CLASSBAR_YOFFSET
+ )
+ power:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT",
+ -frame.BORDER - frame.SPACING,
+ frame.BORDER
+ )]]
+ else
+ power:Point("TOPLEFT", frame.Health, "TOPLEFT",
+ -frame.POWERBAR_OFFSET - (frame.HAPPINESS_WIDTH or 0),
+ -frame.POWERBAR_OFFSET
+ )
+ power:Point("BOTTOMRIGHT", frame.Health, "BOTTOMRIGHT",
+ -frame.POWERBAR_OFFSET,
+ -frame.POWERBAR_OFFSET
+ )
+ end
+ power:SetFrameLevel(frame.Health:GetFrameLevel() - 5) --Health uses 10
+ elseif frame.USE_INSET_POWERBAR then
+ if frame.USE_INSET_ENERGYBAR and frame.USE_ENERGYBAR then
+ power:Point("BOTTOMLEFT", frame.Energy, "TOPLEFT",
+ 0,
+ frame.BORDER * 2
+ )
+ power:Point("BOTTOMRIGHT", frame.Energy, "TOPRIGHT",
+ 0,
+ frame.BORDER * 2
+ )
+ else
+ if frame.USE_INSET_RAGEBAR and frame.USE_RAGEBAR then
+ power:Point("BOTTOMLEFT", frame.Rage, "TOPLEFT",
+ 0,
+ frame.BORDER * 2
+ )
+ power:Point("BOTTOMRIGHT", frame.Rage, "TOPRIGHT",
+ 0,
+ frame.BORDER * 2
+ )
+ else
+ power:Point("BOTTOMLEFT", frame.Health, "BOTTOMLEFT",
+ frame.BORDER + frame.BORDER * 2,
+ frame.BORDER + frame.BORDER * 2
+ )
+ power:Point("BOTTOMRIGHT", frame.Health, "BOTTOMRIGHT",
+ -(frame.BORDER + frame.BORDER * 2),
+ frame.BORDER + frame.BORDER * 2
+ )
+ end
+ end
+
+ power:Height(frame.POWERBAR_HEIGHT - (frame.BORDER + frame.SPACING) * 2)
+ power:SetFrameLevel(50)
+ elseif frame.USE_MINI_POWERBAR then
+ local totalHeight = frame.POWERBAR_HEIGHT - frame.BORDER
+ if frame.USE_ENERGYBAR and frame.USE_MINI_ENERGYBAR then
+ totalHeight = totalHeight + (frame.ENERGYBAR_HEIGHT - frame.BORDER)
+ end
+ if frame.USE_RAGEBAR and frame.USE_MINI_RAGEBAR then
+ totalHeight = totalHeight + (frame.RAGEBAR_HEIGHT - frame.BORDER)
+ end
+ local yPos = totalHeight / 2
+
+ if frame.ORIENTATION == "LEFT" then
+ power:Width(frame.POWERBAR_WIDTH - frame.BORDER * 2)
+ power:Point("TOPRIGHT", frame.Health, "BOTTOMRIGHT",
+ -(frame.BORDER * 2 + 4) - (frame.HAPPINESS_WIDTH or 0),
+ yPos
+ )
+ elseif frame.ORIENTATION == "RIGHT" then
+ power:Width(frame.POWERBAR_WIDTH - frame.BORDER * 2)
+ power:Point("TOPLEFT", frame.Health, "BOTTOMLEFT",
+ frame.BORDER * 2 + 4 + (frame.HAPPINESS_WIDTH or 0),
+ yPos
+ )
+ else
+ power:Point("TOPLEFT", frame.Health, "BOTTOMLEFT",
+ frame.BORDER * 2 + 4,
+ yPos
+ )
+ power:Point("TOPRIGHT", frame.Health, "BOTTOMRIGHT",
+ -(frame.BORDER * 2 + 4) - (frame.HAPPINESS_WIDTH or 0),
+ yPos
+ )
+ end
+
+ power:Height(frame.POWERBAR_HEIGHT - (frame.BORDER + frame.SPACING) * 2)
+ power:SetFrameLevel(50)
+ else -- Filled
+ power:Point("TOPRIGHT", frame.Health.backdrop, "BOTTOMRIGHT",
+ -frame.BORDER,
+ -frame.SPACING * 3
+ )
+ power:Point("TOPLEFT", frame.Health.backdrop, "BOTTOMLEFT",
+ frame.BORDER,
+ -frame.SPACING * 3
+ )
+ power:Height(frame.POWERBAR_HEIGHT - (frame.BORDER + frame.SPACING) * 2)
+
+ power:SetFrameLevel(frame.Health:GetFrameLevel() - 5)
+ end
+
+ --Hide mover until we detach again
+ if not frame.POWERBAR_DETACHED then
+ if power.Holder and power.Holder.mover then
+ power.Holder.mover:SetScale(0.0001)
+ power.Holder.mover:SetAlpha(0)
+ end
+ end
+
+ if db.power.strataAndLevel and db.power.strataAndLevel.useCustomStrata then
+ power:SetFrameStrata(db.power.strataAndLevel.frameStrata)
+ else
+ power:SetFrameStrata("LOW")
+ end
+ if db.power.strataAndLevel and db.power.strataAndLevel.useCustomLevel then
+ power:SetFrameLevel(db.power.strataAndLevel.frameLevel)
+ power.backdrop:SetFrameLevel(power:GetFrameLevel() - 1)
+ end
+
+ if frame.POWERBAR_DETACHED and db.power.parent == "UIPARENT" then
+ power:SetParent(E.UIParent)
+ else
+ power:SetParent(frame)
+ end
+ elseif frame:IsElementEnabled("Power") then
+ frame:DisableElement("Power")
+ power:Hide()
+ frame:Tag(power.value, "")
+ end
+
+ power.custom_backdrop = UF.db.colors.custompowerbackdrop and UF.db.colors.power_backdrop
+
+ --Transparency Settings
+ UF:ToggleTransparentStatusBar(UF.db.colors.transparentPower, power, power.BG, nil, UF.db.colors.invertPower)
+end
+
+local tokens = {[0] = "MANA", "RAGE", "FOCUS", "ENERGY", "RUNIC_POWER"}
+function UF:PostUpdatePowerColor()
+ local parent = self.origParent or self:GetParent()
+
+ if parent.isForced then
+ local color = ElvUF.colors.power[tokens[random(0, 4)]]
+ self:SetValue(random(1, self.max))
+
+ if not self.colorClass then
+ self:SetStatusBarColor(color[1], color[2], color[3])
+
+ if self.BG then
+ UF:UpdateBackdropTextureColor(self.BG, color[1], color[2], color[3])
+ end
+ end
+ end
+end
+
+function UF:PostUpdatePower(unit)
+ local parent = self.origParent or self:GetParent()
+ if parent.isForced then
+ self:SetValue(random(1, self.max))
+ end
+
+ if parent.db and parent.db.power and parent.db.power.hideonnpc then
+ UF:PostNamePosition(parent, unit)
+ end
+
+ --Force update to AdditionalPower in order to reposition text if necessary
+ if parent:IsElementEnabled("AdditionalPower") then
+ E:Delay(0.01, parent.AdditionalPower.ForceUpdate, parent.AdditionalPower) --Delay it slightly so Power text has a chance to clear itself first
+ end
+end
diff --git a/ElvUI/Modules/UnitFrames/Elements/PowerEnergy.lua b/ElvUI/Modules/UnitFrames/Elements/PowerEnergy.lua
new file mode 100644
index 0000000..351a19d
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/PowerEnergy.lua
@@ -0,0 +1,311 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local random = random
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+function UF:Construct_EnergyBar(frame, bg, text, textPos)
+ local energy = CreateFrame("StatusBar", nil, frame)
+ UF.statusbars[energy] = true
+
+ energy.RaisedElementParent = CreateFrame("Frame", nil, energy)
+ energy.RaisedElementParent:SetFrameLevel(energy:GetFrameLevel() + 100)
+ energy.RaisedElementParent:SetAllPoints()
+
+ energy.PostUpdate = self.PostUpdateEnergy
+ energy.PostUpdateColor = self.PostUpdateEnergyColor
+
+ if bg then
+ energy.BG = energy:CreateTexture(nil, "BORDER")
+ energy.BG:SetAllPoints()
+ energy.BG:SetTexture(E.media.blankTex)
+ end
+
+ if text then
+ energy.value = frame.RaisedElementParent:CreateFontString(nil, "OVERLAY")
+ UF:Configure_FontString(energy.value)
+
+ local x = -2
+ if textPos == "LEFT" then
+ x = 2
+ end
+
+ energy.value:Point(textPos, frame.Health, textPos, x, 0)
+
+ energy.value.frequentUpdates = true
+ end
+
+ energy.colorDisconnected = false
+ energy.colorTapping = false
+ energy:CreateBackdrop("Default", nil, nil, self.thinBorders, true)
+
+ local clipFrame = CreateFrame('Frame', nil, energy)
+ clipFrame:SetAllPoints()
+ clipFrame:EnableMouse(false)
+ clipFrame.__frame = frame
+ energy.ClipFrame = clipFrame
+
+ return energy
+end
+
+function UF:Configure_Energy(frame)
+ if not frame.VARIABLES_SET then return end
+ local db = frame.db
+ local energy = frame.Energy
+ energy.origParent = frame
+
+ if frame.USE_ENERGYBAR then
+ if not frame:IsElementEnabled("Energy") then
+ frame:EnableElement("Energy")
+ energy:Show()
+ end
+
+ E:SetSmoothing(energy, self.db.smoothbars)
+
+ --Text
+ local attachPoint = self:GetObjectAnchorPoint(frame, db.energy.attachTextTo)
+ energy.value:ClearAllPoints()
+ energy.value:Point(db.energy.position, attachPoint, db.energy.position, db.energy.xOffset, db.energy.yOffset)
+ frame:Tag(energy.value, db.energy.text_format)
+
+ if db.energy.attachTextTo == "Energy" then
+ energy.value:SetParent(energy.RaisedElementParent)
+ else
+ energy.value:SetParent(frame.RaisedElementParent)
+ end
+
+ --Colors
+ energy.colorClass = nil
+ energy.colorReaction = nil
+ energy.colorEnergy = nil
+
+ if self.db.colors.energyclass then
+ energy.colorClass = true
+ energy.colorReaction = true
+ else
+ energy.colorEnergy = true
+ end
+
+ --Fix height in case it is lower than the theme allows
+ local heightChanged = false
+ if (not self.thinBorders and not E.PixelMode) and frame.ENERGYBAR_HEIGHT < 7 then --A height of 7 means 6px for borders and just 1px for the actual energy statusbar
+ frame.ENERGYBAR_HEIGHT = 7
+ if db.energy then db.energy.height = 7 end
+ heightChanged = true
+ elseif (self.thinBorders or E.PixelMode) and frame.ENERGYBAR_HEIGHT < 3 then --A height of 3 means 2px for borders and just 1px for the actual energy statusbar
+ frame.ENERGYBAR_HEIGHT = 3
+ if db.energy then db.energy.height = 3 end
+ heightChanged = true
+ end
+ if heightChanged then
+ --Update health size
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+ UF:Configure_HealthBar(frame)
+ end
+
+ --Position
+ energy:ClearAllPoints()
+ if frame.ENERGYBAR_DETACHED then
+ energy:Width(frame.ENERGYBAR_WIDTH - ((frame.BORDER + frame.SPACING)*2))
+ energy:Height(frame.ENERGYBAR_HEIGHT - ((frame.BORDER + frame.SPACING)*2))
+ if not energy.Holder or (energy.Holder and not energy.Holder.mover) then
+ energy.Holder = CreateFrame("Frame", nil, energy)
+ energy.Holder:Size(frame.ENERGYBAR_WIDTH, frame.ENERGYBAR_HEIGHT)
+ energy.Holder:Point("BOTTOM", frame, "BOTTOM", 0, -20)
+ energy:ClearAllPoints()
+ energy:Point("BOTTOMLEFT", energy.Holder, "BOTTOMLEFT", frame.BORDER+frame.SPACING, frame.BORDER+frame.SPACING)
+ --Currently only Player and Target can detach energy bars, so doing it this way is okay for now
+ if frame.unitframeType and frame.unitframeType == "player" then
+ E:CreateMover(energy.Holder, "PlayerEnergyBarMover", L["Player Energybar"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,player,energy")
+ elseif frame.unitframeType and frame.unitframeType == "target" then
+ E:CreateMover(energy.Holder, "TargetEnergyBarMover", L["Target Energybar"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,target,energy")
+ end
+ else
+ energy.Holder:Size(frame.ENERGYBAR_WIDTH, frame.ENERGYBAR_HEIGHT)
+ energy:ClearAllPoints()
+ energy:Point("BOTTOMLEFT", energy.Holder, "BOTTOMLEFT", frame.BORDER+frame.SPACING, frame.BORDER+frame.SPACING)
+ energy.Holder.mover:SetScale(1)
+ energy.Holder.mover:SetAlpha(1)
+ end
+
+ energy:SetFrameLevel(50) --RaisedElementParent uses 100, we want lower value to allow certain icons and texts to appear above energy
+ elseif frame.USE_ENERGYBAR_OFFSET then
+ local anchor = frame.Health
+ if frame.USE_POWERBAR and frame.USE_POWERBAR_OFFSET then
+ anchor = frame.Power
+ end
+ if frame.ORIENTATION == "LEFT" then
+ energy:Point("TOPRIGHT", anchor, "TOPRIGHT", frame.ENERGYBAR_OFFSET + (frame.HAPPINESS_WIDTH or 0), -frame.ENERGYBAR_OFFSET)
+ energy:Point("BOTTOMLEFT", anchor, "BOTTOMLEFT", frame.ENERGYBAR_OFFSET, -frame.ENERGYBAR_OFFSET)
+ elseif frame.ORIENTATION == "MIDDLE" then
+ local preOffset = 0
+ if frame.USE_POWERBAR and frame.USE_POWERBAR_OFFSET then
+ preOffset = preOffset + frame.POWERBAR_OFFSET
+ end
+ local postOffset = 0
+ if frame.USE_RAGEBAR and frame.USE_RAGEBAR_OFFSET then
+ postOffset = postOffset + frame.RAGEBAR_OFFSET
+ end
+
+ energy:Point("TOPLEFT", frame, "TOPLEFT",
+ frame.BORDER + frame.SPACING + postOffset,
+ -(preOffset + frame.ENERGYBAR_OFFSET + frame.CLASSBAR_YOFFSET) --+ frame.BORDER - frame.SPACING)
+ )
+ energy:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT",
+ -(frame.BORDER + frame.SPACING + postOffset),
+ frame.BORDER + frame.SPACING + postOffset
+ )
+ else
+ energy:Point("TOPLEFT", anchor, "TOPLEFT", -frame.ENERGYBAR_OFFSET - (frame.HAPPINESS_WIDTH or 0), -frame.ENERGYBAR_OFFSET)
+ energy:Point("BOTTOMRIGHT", anchor, "BOTTOMRIGHT", -frame.ENERGYBAR_OFFSET, -frame.ENERGYBAR_OFFSET)
+ end
+ energy:SetFrameLevel(frame.Health:GetFrameLevel() - 6) --Health uses 10
+ elseif frame.USE_INSET_ENERGYBAR then
+ if frame.USE_INSET_RAGEBAR and frame.USE_RAGEBAR then
+ energy:Point("BOTTOMLEFT", frame.Rage, "TOPLEFT",
+ 0,
+ frame.BORDER * 2
+ )
+ energy:Point("BOTTOMRIGHT", frame.Rage, "TOPRIGHT",
+ 0,
+ frame.BORDER * 2
+ )
+ else
+ energy:Point("BOTTOMLEFT", frame.Health, "BOTTOMLEFT",
+ frame.BORDER + frame.BORDER * 2,
+ frame.BORDER + frame.BORDER * 2
+ )
+ energy:Point("BOTTOMRIGHT", frame.Health, "BOTTOMRIGHT",
+ -(frame.BORDER + frame.BORDER * 2),
+ frame.BORDER + frame.BORDER * 2
+ )
+ end
+
+ energy:Height(frame.ENERGYBAR_HEIGHT - (frame.BORDER + frame.SPACING) * 2)
+ energy:SetFrameLevel(50)
+ elseif frame.USE_MINI_ENERGYBAR then
+ local totalHeight = frame.ENERGYBAR_HEIGHT - frame.BORDER
+ if frame.USE_POWERBAR and frame.USE_MINI_POWERBAR then
+ totalHeight = totalHeight + (frame.POWERBAR_HEIGHT - frame.BORDER)
+ end
+ if frame.USE_RAGEBAR and frame.USE_MINI_RAGEBAR then
+ totalHeight = totalHeight + (frame.RAGEBAR_HEIGHT - frame.BORDER)
+ end
+ local yPos = (totalHeight / 2) - (frame.POWERBAR_HEIGHT - frame.BORDER)
+
+ if frame.ORIENTATION == "LEFT" then
+ energy:Width(frame.ENERGYBAR_WIDTH - frame.BORDER * 2)
+ energy:Point("TOPRIGHT", frame.Health, "BOTTOMRIGHT",
+ -(frame.BORDER * 2 + 4) - (frame.HAPPINESS_WIDTH or 0),
+ yPos
+ )
+ elseif frame.ORIENTATION == "RIGHT" then
+ energy:Width(frame.ENERGYBAR_WIDTH - frame.BORDER*2)
+ energy:Point("TOPLEFT", frame.Health, "BOTTOMLEFT",
+ frame.BORDER * 2 + 4 + (frame.HAPPINESS_WIDTH or 0),
+ yPos
+ )
+ else
+ energy:Point("TOPLEFT", frame.Health, "BOTTOMLEFT",
+ frame.BORDER * 2 + 4,
+ yPos
+ )
+ energy:Point("TOPRIGHT", frame.Health, "BOTTOMRIGHT",
+ -(frame.BORDER * 2 + 4) - (frame.HAPPINESS_WIDTH or 0),
+ yPos
+ )
+ end
+
+ energy:Height(frame.ENERGYBAR_HEIGHT - (frame.BORDER + frame.SPACING) * 2)
+ energy:SetFrameLevel(50)
+ else -- Filled
+ local anchor = frame.Power.backdrop
+ if not frame.USE_POWERBAR or frame.USE_POWERBAR_DETACHED or frame.USE_INSET_POWERBAR or frame.USE_MINI_POWERBAR then
+ anchor = frame.Health.backdrop
+ end
+ energy:Point("TOPLEFT", anchor, "BOTTOMLEFT",
+ frame.BORDER,
+ -frame.SPACING * 3
+ )
+ energy:Point("TOPRIGHT", anchor, "BOTTOMRIGHT",
+ -frame.BORDER,
+ -frame.SPACING * 3
+ )
+ energy:Height(frame.ENERGYBAR_HEIGHT - (frame.BORDER + frame.SPACING) * 2)
+ energy:SetFrameLevel(frame.Health:GetFrameLevel() - 5)
+ end
+
+ --Hide mover until we detach again
+ if not frame.ENERGYBAR_DETACHED then
+ if energy.Holder and energy.Holder.mover then
+ energy.Holder.mover:SetScale(0.0001)
+ energy.Holder.mover:SetAlpha(0)
+ end
+ end
+
+ if db.energy.strataAndLevel and db.energy.strataAndLevel.useCustomStrata then
+ energy:SetFrameStrata(db.energy.strataAndLevel.frameStrata)
+ else
+ energy:SetFrameStrata("LOW")
+ end
+ if db.energy.strataAndLevel and db.energy.strataAndLevel.useCustomLevel then
+ energy:SetFrameLevel(db.energy.strataAndLevel.frameLevel)
+ energy.backdrop:SetFrameLevel(energy:GetFrameLevel() - 1)
+ end
+
+ if frame.ENERGYBAR_DETACHED and db.energy.parent == "UIPARENT" then
+ energy:SetParent(E.UIParent)
+ else
+ energy:SetParent(frame)
+ end
+ elseif frame:IsElementEnabled("Energy") then
+ frame:DisableElement("Energy")
+ energy:Hide()
+ frame:Tag(energy.value, "")
+ end
+
+ energy.custom_backdrop = UF.db.colors.customenergybackdrop and UF.db.colors.energy_backdrop
+
+ --Transparency Settings
+ UF:ToggleTransparentStatusBar(UF.db.colors.transparentEnergy, energy, energy.BG, nil, UF.db.colors.invertEnergy)
+end
+
+local tokens = {[0] = "MANA", "RAGE", "FOCUS", "ENERGY", "RUNIC_POWER"}
+function UF:PostUpdateEnergyColor()
+ local parent = self.origParent or self:GetParent()
+
+ if parent.isForced then
+ local color = ElvUF.colors.energy[tokens[random(0, 4)]]
+ self:SetValue(random(1, self.max))
+
+ if not self.colorClass then
+ self:SetStatusBarColor(color[1], color[2], color[3])
+
+ if self.BG then
+ UF:UpdateBackdropTextureColor(self.BG, color[1], color[2], color[3])
+ end
+ end
+ end
+end
+
+function UF:PostUpdateEnergy(unit)
+ local parent = self.origParent or self:GetParent()
+ if parent.isForced then
+ self:SetValue(random(1, self.max))
+ end
+
+ if parent.db and parent.db.energy and parent.db.energy.hideonnpc then
+ UF:PostNamePosition(parent, unit)
+ end
+
+ --Force update to AdditionalPower in order to reposition text if necessary
+ if parent:IsElementEnabled("AdditionalPower") then
+ E:Delay(0.01, parent.AdditionalPower.ForceUpdate, parent.AdditionalPower) --Delay it slightly so Power text has a chance to clear itself first
+ end
+end
diff --git a/ElvUI/Modules/UnitFrames/Elements/PowerRage.lua b/ElvUI/Modules/UnitFrames/Elements/PowerRage.lua
new file mode 100644
index 0000000..0f07458
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/PowerRage.lua
@@ -0,0 +1,298 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local random = random
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+function UF:Construct_RageBar(frame, bg, text, textPos)
+ local rage = CreateFrame("StatusBar", nil, frame)
+ UF.statusbars[rage] = true
+
+ rage.RaisedElementParent = CreateFrame("Frame", nil, rage)
+ rage.RaisedElementParent:SetFrameLevel(rage:GetFrameLevel() + 100)
+ rage.RaisedElementParent:SetAllPoints()
+
+ rage.PostUpdate = self.PostUpdateRage
+ rage.PostUpdateColor = self.PostUpdateRageColor
+
+ if bg then
+ rage.BG = rage:CreateTexture(nil, "BORDER")
+ rage.BG:SetAllPoints()
+ rage.BG:SetTexture(E.media.blankTex)
+ end
+
+ if text then
+ rage.value = frame.RaisedElementParent:CreateFontString(nil, "OVERLAY")
+ UF:Configure_FontString(rage.value)
+
+ local x = -2
+ if textPos == "LEFT" then
+ x = 2
+ end
+
+ rage.value:Point(textPos, frame.Health, textPos, x, 0)
+
+ rage.value.frequentUpdates = true
+ end
+
+ rage.colorDisconnected = false
+ rage.colorTapping = false
+ rage:CreateBackdrop("Default", nil, nil, self.thinBorders, true)
+
+ local clipFrame = CreateFrame('Frame', nil, rage)
+ clipFrame:SetAllPoints()
+ clipFrame:EnableMouse(false)
+ clipFrame.__frame = frame
+ rage.ClipFrame = clipFrame
+
+ return rage
+end
+
+function UF:Configure_Rage(frame)
+ if not frame.VARIABLES_SET then return end
+ local db = frame.db
+ local rage = frame.Rage
+ rage.origParent = frame
+
+ if frame.USE_RAGEBAR then
+ if not frame:IsElementEnabled("Rage") then
+ frame:EnableElement("Rage")
+ rage:Show()
+ end
+
+ E:SetSmoothing(rage, self.db.smoothbars)
+
+ --Text
+ local attachPoint = self:GetObjectAnchorPoint(frame, db.rage.attachTextTo)
+ rage.value:ClearAllPoints()
+ rage.value:Point(db.rage.position, attachPoint, db.rage.position, db.rage.xOffset, db.rage.yOffset)
+ frame:Tag(rage.value, db.rage.text_format)
+
+ if db.rage.attachTextTo == "Rage" then
+ rage.value:SetParent(rage.RaisedElementParent)
+ else
+ rage.value:SetParent(frame.RaisedElementParent)
+ end
+
+ --Colors
+ rage.colorClass = nil
+ rage.colorReaction = nil
+ rage.colorRage = nil
+
+ if self.db.colors.rageclass then
+ rage.colorClass = true
+ rage.colorReaction = true
+ else
+ rage.colorRage = true
+ end
+
+ --Fix height in case it is lower than the theme allows
+ local heightChanged = false
+ if (not self.thinBorders and not E.PixelMode) and frame.RAGEBAR_HEIGHT < 7 then --A height of 7 means 6px for borders and just 1px for the actual rage statusbar
+ frame.RAGEBAR_HEIGHT = 7
+ if db.rage then db.rage.height = 7 end
+ heightChanged = true
+ elseif (self.thinBorders or E.PixelMode) and frame.RAGEBAR_HEIGHT < 3 then --A height of 3 means 2px for borders and just 1px for the actual rage statusbar
+ frame.RAGEBAR_HEIGHT = 3
+ if db.rage then db.rage.height = 3 end
+ heightChanged = true
+ end
+ if heightChanged then
+ --Update health size
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+ UF:Configure_HealthBar(frame)
+ end
+
+ --Position
+ rage:ClearAllPoints()
+ if frame.RAGEBAR_DETACHED then
+ rage:Width(frame.RAGEBAR_WIDTH - ((frame.BORDER + frame.SPACING)*2))
+ rage:Height(frame.RAGEBAR_HEIGHT - ((frame.BORDER + frame.SPACING)*2))
+ if not rage.Holder or (rage.Holder and not rage.Holder.mover) then
+ rage.Holder = CreateFrame("Frame", nil, rage)
+ rage.Holder:Size(frame.RAGEBAR_WIDTH, frame.RAGEBAR_HEIGHT)
+ rage.Holder:Point("BOTTOM", frame, "BOTTOM", 0, -20)
+ rage:ClearAllPoints()
+ rage:Point("BOTTOMLEFT", rage.Holder, "BOTTOMLEFT", frame.BORDER+frame.SPACING, frame.BORDER+frame.SPACING)
+ --Currently only Player and Target can detach rage bars, so doing it this way is okay for now
+ if frame.unitframeType and frame.unitframeType == "player" then
+ E:CreateMover(rage.Holder, "PlayerRageBarMover", L["Player Ragebar"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,player,rage")
+ elseif frame.unitframeType and frame.unitframeType == "target" then
+ E:CreateMover(rage.Holder, "TargetRageBarMover", L["Target Ragebar"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,target,rage")
+ end
+ else
+ rage.Holder:Size(frame.RAGEBAR_WIDTH, frame.RAGEBAR_HEIGHT)
+ rage:ClearAllPoints()
+ rage:Point("BOTTOMLEFT", rage.Holder, "BOTTOMLEFT", frame.BORDER+frame.SPACING, frame.BORDER+frame.SPACING)
+ rage.Holder.mover:SetScale(1)
+ rage.Holder.mover:SetAlpha(1)
+ end
+
+ rage:SetFrameLevel(50) --RaisedElementParent uses 100, we want lower value to allow certain icons and texts to appear above rage
+ elseif frame.USE_RAGEBAR_OFFSET then
+ local anchor = frame.Health
+ if frame.USE_POWERBAR and frame.USE_POWERBAR_OFFSET then
+ anchor = frame.Power
+ end
+ if frame.USE_ENERGYBAR and frame.USE_ENERGYBAR_OFFSET then
+ anchor = frame.Energy
+ end
+ if frame.ORIENTATION == "LEFT" then
+ rage:Point("TOPRIGHT", anchor, "TOPRIGHT", frame.RAGEBAR_OFFSET + (frame.HAPPINESS_WIDTH or 0), -frame.RAGEBAR_OFFSET)
+ rage:Point("BOTTOMLEFT", anchor, "BOTTOMLEFT", frame.RAGEBAR_OFFSET, -frame.RAGEBAR_OFFSET)
+ elseif frame.ORIENTATION == "MIDDLE" then
+ local preOffset = 0
+ if frame.USE_POWERBAR and frame.USE_POWERBAR_OFFSET then
+ preOffset = preOffset + frame.POWERBAR_OFFSET
+ end
+ if frame.USE_ENERGYBAR and frame.USE_ENERGYBAR_OFFSET then
+ preOffset = preOffset + frame.ENERGYBAR_OFFSET
+ end
+
+ rage:Point("TOPLEFT", frame, "TOPLEFT",
+ frame.BORDER + frame.SPACING,
+ -(preOffset + frame.RAGEBAR_OFFSET + frame.CLASSBAR_YOFFSET) --+ frame.BORDER - frame.SPACING)
+ )
+ rage:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT",
+ -(frame.BORDER + frame.SPACING),
+ frame.BORDER + frame.SPACING
+ )
+ else
+ rage:Point("TOPLEFT", anchor, "TOPLEFT", -frame.RAGEBAR_OFFSET - (frame.HAPPINESS_WIDTH or 0), -frame.RAGEBAR_OFFSET)
+ rage:Point("BOTTOMRIGHT", anchor, "BOTTOMRIGHT", -frame.RAGEBAR_OFFSET, -frame.RAGEBAR_OFFSET)
+ end
+ rage:SetFrameLevel(frame.Health:GetFrameLevel() - 7) --Health uses 10
+ elseif frame.USE_INSET_RAGEBAR then
+ rage:Height(frame.RAGEBAR_HEIGHT - (frame.BORDER + frame.SPACING) * 2)
+ rage:Point("BOTTOMLEFT", frame.Health, "BOTTOMLEFT", frame.BORDER + frame.BORDER * 2, frame.BORDER + frame.BORDER * 2)
+ rage:Point("BOTTOMRIGHT", frame.Health, "BOTTOMRIGHT", -(frame.BORDER + frame.BORDER * 2), frame.BORDER + frame.BORDER * 2)
+ rage:SetFrameLevel(50)
+ elseif frame.USE_MINI_RAGEBAR then
+ local totalHeight = frame.RAGEBAR_HEIGHT - frame.BORDER
+ if frame.USE_POWERBAR and frame.USE_MINI_POWERBAR then
+ totalHeight = totalHeight + (frame.POWERBAR_HEIGHT - frame.BORDER)
+ end
+ if frame.USE_ENERGYBAR and frame.USE_MINI_ENERGYBAR then
+ totalHeight = totalHeight + (frame.ENERGYBAR_HEIGHT - frame.BORDER)
+ end
+ local yPos = -(totalHeight / 2) + (frame.RAGEBAR_HEIGHT - frame.BORDER)
+
+ if frame.ORIENTATION == "LEFT" then
+ rage:Width(frame.RAGEBAR_WIDTH - frame.BORDER * 2)
+ rage:Point("TOPRIGHT", frame.Health, "BOTTOMRIGHT",
+ -(frame.BORDER * 2 + 4) - (frame.HAPPINESS_WIDTH or 0),
+ yPos
+ )
+ elseif frame.ORIENTATION == "RIGHT" then
+ rage:Width(frame.RAGEBAR_WIDTH - frame.BORDER*2)
+ rage:Point("TOPLEFT", frame.Health, "BOTTOMLEFT",
+ frame.BORDER * 2 + 4 + (frame.HAPPINESS_WIDTH or 0),
+ yPos
+ )
+ else
+ rage:Point("TOPLEFT", frame.Health, "BOTTOMLEFT",
+ frame.BORDER * 2 + 4,
+ yPos
+ )
+ rage:Point("TOPRIGHT", frame.Health, "BOTTOMRIGHT",
+ -(frame.BORDER * 2 + 4) - (frame.HAPPINESS_WIDTH or 0),
+ yPos
+ )
+ end
+
+ rage:Height(frame.RAGEBAR_HEIGHT - (frame.BORDER + frame.SPACING) * 2)
+ rage:SetFrameLevel(50)
+ else -- Filled
+ local anchor = frame.Energy.backdrop
+ if not frame.USE_ENERGYBAR or frame.USE_ENERGYBAR_DETACHED or frame.USE_INSET_ENERGYBAR or frame.USE_MINI_ENERGYBAR then
+ if not frame.USE_POWERBAR or frame.USE_POWERBAR_DETACHED or frame.USE_INSET_POWERBAR or frame.USE_MINI_POWERBAR then
+ anchor = frame.Health.backdrop
+ else anchor = frame.Power.backdrop end
+ end
+ rage:Point("TOPRIGHT", anchor, "BOTTOMRIGHT",
+ -frame.BORDER,
+ -frame.SPACING * 3
+ )
+ rage:Point("TOPLEFT", anchor, "BOTTOMLEFT",
+ frame.BORDER,
+ -frame.SPACING * 3
+ )
+ rage:Height(frame.RAGEBAR_HEIGHT - (frame.BORDER + frame.SPACING) * 2)
+
+ rage:SetFrameLevel(frame.Health:GetFrameLevel() - 5)
+ end
+
+ --Hide mover until we detach again
+ if not frame.RAGEBAR_DETACHED then
+ if rage.Holder and rage.Holder.mover then
+ rage.Holder.mover:SetScale(0.0001)
+ rage.Holder.mover:SetAlpha(0)
+ end
+ end
+
+ if db.rage.strataAndLevel and db.rage.strataAndLevel.useCustomStrata then
+ rage:SetFrameStrata(db.rage.strataAndLevel.frameStrata)
+ else
+ rage:SetFrameStrata("LOW")
+ end
+ if db.rage.strataAndLevel and db.rage.strataAndLevel.useCustomLevel then
+ rage:SetFrameLevel(db.rage.strataAndLevel.frameLevel)
+ rage.backdrop:SetFrameLevel(rage:GetFrameLevel() - 1)
+ end
+
+ if frame.RAGEBAR_DETACHED and db.rage.parent == "UIPARENT" then
+ rage:SetParent(E.UIParent)
+ else
+ rage:SetParent(frame)
+ end
+ elseif frame:IsElementEnabled("Rage") then
+ frame:DisableElement("Rage")
+ rage:Hide()
+ frame:Tag(rage.value, "")
+ end
+
+ rage.custom_backdrop = UF.db.colors.customragebackdrop and UF.db.colors.rage_backdrop
+
+ --Transparency Settings
+ UF:ToggleTransparentStatusBar(UF.db.colors.transparentRage, rage, rage.BG, nil, UF.db.colors.invertRage)
+end
+
+local tokens = {[0] = "MANA", "RAGE", "FOCUS", "ENERGY", "RUNIC_POWER"}
+function UF:PostUpdateRageColor()
+ local parent = self.origParent or self:GetParent()
+
+ if parent.isForced then
+ local color = ElvUF.colors.rage[tokens[random(0, 4)]]
+ self:SetValue(random(1, self.max))
+
+ if not self.colorClass then
+ self:SetStatusBarColor(color[1], color[2], color[3])
+
+ if self.BG then
+ UF:UpdateBackdropTextureColor(self.BG, color[1], color[2], color[3])
+ end
+ end
+ end
+end
+
+function UF:PostUpdateRage(unit)
+ local parent = self.origParent or self:GetParent()
+ if parent.isForced then
+ self:SetValue(random(1, self.max))
+ end
+
+ if parent.db and parent.db.rage and parent.db.rage.hideonnpc then
+ UF:PostNamePosition(parent, unit)
+ end
+
+ --Force update to AdditionalPower in order to reposition text if necessary
+ if parent:IsElementEnabled("AdditionalPower") then
+ E:Delay(0.01, parent.AdditionalPower.ForceUpdate, parent.AdditionalPower) --Delay it slightly so Power text has a chance to clear itself first
+ end
+end
diff --git a/ElvUI/Modules/UnitFrames/Elements/PvPIcon.lua b/ElvUI/Modules/UnitFrames/Elements/PvPIcon.lua
new file mode 100644
index 0000000..9c04cac
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/PvPIcon.lua
@@ -0,0 +1,70 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+
+function UF:Construct_PvPIcon(frame)
+ local PvPIndicator = frame.RaisedElementParent.TextureParent:CreateTexture(nil, "ARTWORK")
+ PvPIndicator:Size(30, 30)
+ PvPIndicator:Point("CENTER", frame, "CENTER")
+
+ PvPIndicator.Override = UF.UpdateOverridePvP
+
+ return PvPIndicator
+end
+
+function UF:Configure_PVPIcon(frame)
+ local PvPIndicator = frame.PvPIndicator
+ PvPIndicator:ClearAllPoints()
+ PvPIndicator:Point(frame.db.pvpIcon.anchorPoint, frame.Health, frame.db.pvpIcon.anchorPoint, frame.db.pvpIcon.xOffset, frame.db.pvpIcon.yOffset)
+
+ local scale = frame.db.pvpIcon.scale or 1
+ PvPIndicator:Size(30 * scale)
+
+ if frame.db.pvpIcon.enable and not frame:IsElementEnabled("PvPIndicator") then
+ frame:EnableElement("PvPIndicator")
+ elseif not frame.db.pvpIcon.enable and frame:IsElementEnabled("PvPIndicator") then
+ frame:DisableElement("PvPIndicator")
+ end
+end
+
+function UF:UpdateOverridePvP(event, unit)
+ if not unit or self.unit ~= unit then return end
+
+ local element = self.PvPIndicator
+
+ if element.PreUpdate then
+ element:PreUpdate()
+ end
+
+ local status
+ local factionGroup = UnitFactionGroup(unit)
+
+ if UnitIsPVPFreeForAll(unit) then
+ element:SetTexture("Interface\\TargetingFrame\\UI-PVP-FFA")
+ element:SetTexCoord(0, 0.65625, 0, 0.65625)
+
+ status = "ffa"
+ elseif factionGroup and UnitIsPVP(unit) then
+ element:SetTexture(E.Media.Textures.PvPIcons)
+
+ if factionGroup == "Alliance" then
+ element:SetTexCoord(0.545, 0.935, 0.070, 0.940)
+ else
+ element:SetTexCoord(0.100, 0.475, 0.070, 0.940)
+ end
+
+ status = factionGroup
+ end
+
+ if status then
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ if element.PostUpdate then
+ return element:PostUpdate(unit, status)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/PvPIndicator.lua b/ElvUI/Modules/UnitFrames/Elements/PvPIndicator.lua
new file mode 100644
index 0000000..2c1a560
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/PvPIndicator.lua
@@ -0,0 +1,21 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+
+function UF:Construct_PvPIndicator(frame)
+ local pvp = frame.RaisedElementParent:CreateFontString(nil, "OVERLAY")
+ UF:Configure_FontString(pvp)
+
+ return pvp
+end
+
+function UF:Configure_PVPIndicator(frame)
+ local pvp = frame.PvPText
+ local x, y = self:GetPositionOffset(frame.db.pvp.position)
+ pvp:ClearAllPoints()
+ pvp:Point(frame.db.pvp.position, frame.Health, frame.db.pvp.position, x, y)
+
+ frame:Tag(pvp, frame.db.pvp.text_format)
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/RaidDebuffs.lua b/ElvUI/Modules/UnitFrames/Elements/RaidDebuffs.lua
new file mode 100644
index 0000000..081f79a
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/RaidDebuffs.lua
@@ -0,0 +1,65 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local unpack = unpack
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+function UF:Construct_RaidDebuffs(frame)
+ local rdebuff = CreateFrame("Frame", nil, frame.RaisedElementParent)
+ rdebuff:SetTemplate(nil, nil, nil, UF.thinBorders, true)
+ rdebuff:SetFrameLevel(frame.RaisedElementParent:GetFrameLevel() + 20) --Make them appear above regular buffs or debuffs
+
+ local offset = UF.thinBorders and E.mult or E.Border
+ rdebuff.icon = rdebuff:CreateTexture(nil, "OVERLAY")
+ rdebuff.icon:SetInside(rdebuff, offset, offset)
+
+ rdebuff.count = rdebuff:CreateFontString(nil, "OVERLAY")
+ rdebuff.count:FontTemplate(nil, 10, "OUTLINE")
+ rdebuff.count:Point("BOTTOMRIGHT", 0, 2)
+ rdebuff.count:SetTextColor(1, .9, 0)
+
+ rdebuff.time = rdebuff:CreateFontString(nil, "OVERLAY")
+ rdebuff.time:FontTemplate(nil, 10, "OUTLINE")
+ rdebuff.time:Point("CENTER")
+ rdebuff.time:SetTextColor(1, .9, 0)
+
+ return rdebuff
+end
+
+function UF:Configure_RaidDebuffs(frame)
+ if not frame.VARIABLES_SET then return end
+ local db = frame.db
+ local rdebuffs = frame.RaidDebuffs
+
+ if db.rdebuffs.enable then
+ local stackColor = db.rdebuffs.stack.color
+ local durationColor = db.rdebuffs.duration.color
+ local rdebuffsFont = UF.LSM:Fetch("font", db.rdebuffs.font)
+ if not frame:IsElementEnabled("RaidDebuffs") then
+ frame:EnableElement("RaidDebuffs")
+ end
+
+ rdebuffs.showDispellableDebuff = db.rdebuffs.showDispellableDebuff
+ rdebuffs.onlyMatchSpellID = db.rdebuffs.onlyMatchSpellID
+ rdebuffs.forceShow = frame.forceShowAuras
+ rdebuffs:Size(db.rdebuffs.size)
+ rdebuffs:Point("BOTTOM", frame, "BOTTOM", db.rdebuffs.xOffset, db.rdebuffs.yOffset + frame.SPACING)
+
+ rdebuffs.icon:SetTexCoord(unpack(E.TexCoords))
+
+ rdebuffs.count:FontTemplate(rdebuffsFont, db.rdebuffs.fontSize, db.rdebuffs.fontOutline)
+ rdebuffs.count:ClearAllPoints()
+ rdebuffs.count:Point(db.rdebuffs.stack.position, db.rdebuffs.stack.xOffset, db.rdebuffs.stack.yOffset)
+ rdebuffs.count:SetTextColor(stackColor.r, stackColor.g, stackColor.b, stackColor.a)
+
+ rdebuffs.time:FontTemplate(rdebuffsFont, db.rdebuffs.fontSize, db.rdebuffs.fontOutline)
+ rdebuffs.time:ClearAllPoints()
+ rdebuffs.time:Point(db.rdebuffs.duration.position, db.rdebuffs.duration.xOffset, db.rdebuffs.duration.yOffset)
+ rdebuffs.time:SetTextColor(durationColor.r, durationColor.g, durationColor.b, durationColor.a)
+ elseif frame:IsElementEnabled("RaidDebuffs") then
+ frame:DisableElement("RaidDebuffs")
+ rdebuffs:Hide()
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/RaidIcon.lua b/ElvUI/Modules/UnitFrames/Elements/RaidIcon.lua
new file mode 100644
index 0000000..70e01f3
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/RaidIcon.lua
@@ -0,0 +1,33 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+
+function UF:Construct_RaidIcon(frame)
+ local tex = frame.RaisedElementParent.TextureParent:CreateTexture(nil, "OVERLAY")
+ tex:SetTexture(E.Media.Textures.RaidIcons)
+ tex:Size(18)
+ tex:Point("CENTER", frame.Health, "TOP", 0, 2)
+ tex.SetTexture = E.noop
+
+ return tex
+end
+
+function UF:Configure_RaidIcon(frame)
+ local RI = frame.RaidTargetIndicator
+ local db = frame.db
+
+ if db.raidicon.enable then
+ frame:EnableElement("RaidTargetIndicator")
+ RI:Show()
+ RI:Size(db.raidicon.size)
+
+ local attachPoint = self:GetObjectAnchorPoint(frame, db.raidicon.attachToObject)
+ RI:ClearAllPoints()
+ RI:Point(db.raidicon.attachTo, attachPoint, db.raidicon.attachTo, db.raidicon.xOffset, db.raidicon.yOffset)
+ else
+ frame:DisableElement("RaidTargetIndicator")
+ RI:Hide()
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/RaidRoleIcons.lua b/ElvUI/Modules/UnitFrames/Elements/RaidRoleIcons.lua
new file mode 100644
index 0000000..24e13be
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/RaidRoleIcons.lua
@@ -0,0 +1,131 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local match = string.match
+local select, tonumber = select, tonumber
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetNumRaidMembers = GetNumRaidMembers
+local GetRaidRosterInfo = GetRaidRosterInfo
+local IsPartyLeader = IsPartyLeader
+local UnitInParty = UnitInParty
+local UnitInRaid = UnitInRaid
+
+local function CheckLeader(unit)
+ if unit == "player" then
+ return IsPartyLeader()
+ elseif unit ~= "player" and (UnitInParty(unit) or UnitInRaid(unit)) then
+ local gtype, index = match(unit, "(%D+)(%d+)")
+ index = tonumber(index)
+ if gtype == "party" and GetNumRaidMembers() == 0 then
+ return GetPartyLeaderIndex() == index
+ elseif gtype == "raid" and GetNumRaidMembers() > 0 then
+ return select(2, GetRaidRosterInfo(index)) == 2
+ end
+ end
+end
+
+local function UpdateOverride(self)
+ local element = self.LeaderIndicator
+
+ if element.PreUpdate then
+ element:PreUpdate()
+ end
+
+ local isLeader = CheckLeader(self.unit)
+
+ if isLeader then
+ element:Show()
+ else
+ element:Hide()
+ end
+
+ if element.PostUpdate then
+ return element:PostUpdate(isLeader)
+ end
+end
+
+function UF:Construct_RaidRoleFrames(frame)
+ local anchor = CreateFrame("Frame", nil, frame.RaisedElementParent)
+ frame.LeaderIndicator = anchor:CreateTexture(nil, "OVERLAY")
+ frame.AssistantIndicator = anchor:CreateTexture(nil, "OVERLAY")
+ frame.MasterLooterIndicator = anchor:CreateTexture(nil, "OVERLAY")
+
+ anchor:Size(24, 12)
+ frame.LeaderIndicator:Size(12)
+ frame.AssistantIndicator:Size(12)
+ frame.MasterLooterIndicator:Size(11)
+
+ frame.LeaderIndicator.Override = UpdateOverride
+
+ frame.LeaderIndicator.PostUpdate = UF.RaidRoleUpdate
+ frame.AssistantIndicator.PostUpdate = UF.RaidRoleUpdate
+ frame.MasterLooterIndicator.PostUpdate = UF.RaidRoleUpdate
+
+ return anchor
+end
+
+function UF:Configure_RaidRoleIcons(frame)
+ local raidRoleFrameAnchor = frame.RaidRoleFramesAnchor
+
+ if frame.db.raidRoleIcons.enable then
+ raidRoleFrameAnchor:Show()
+ if not frame:IsElementEnabled("LeaderIndicator") then
+ frame:EnableElement("LeaderIndicator")
+ frame:EnableElement("MasterLooterIndicator")
+ frame:EnableElement("AssistantIndicator")
+ end
+
+ raidRoleFrameAnchor:ClearAllPoints()
+ if frame.db.raidRoleIcons.position == "TOPLEFT" then
+ raidRoleFrameAnchor:Point("LEFT", frame.Health, "TOPLEFT", 2, 0)
+ else
+ raidRoleFrameAnchor:Point("RIGHT", frame, "TOPRIGHT", -2, 0)
+ end
+ elseif frame:IsElementEnabled("LeaderIndicator") then
+ raidRoleFrameAnchor:Hide()
+ frame:DisableElement("LeaderIndicator")
+ frame:DisableElement("MasterLooterIndicator")
+ frame:DisableElement("AssistantIndicator")
+ end
+end
+
+function UF:RaidRoleUpdate()
+ local anchor = self:GetParent()
+ local frame = anchor:GetParent():GetParent()
+ local leader = frame.LeaderIndicator
+ local assistant = frame.AssistantIndicator
+ local masterLooter = frame.MasterLooterIndicator
+
+ if not leader or not masterLooter or not assistant then return; end
+
+ local db = frame.db
+ local isLeader = leader:IsShown()
+ local isMasterLooter = masterLooter:IsShown()
+ local isAssist = assistant:IsShown()
+
+ leader:ClearAllPoints()
+ assistant:ClearAllPoints()
+ masterLooter:ClearAllPoints()
+
+ if db and db.raidRoleIcons then
+ if isLeader and db.raidRoleIcons.position == "TOPLEFT" then
+ leader:Point("LEFT", anchor, "LEFT")
+ masterLooter:Point("RIGHT", anchor, "RIGHT")
+ elseif isLeader and db.raidRoleIcons.position == "TOPRIGHT" then
+ leader:Point("RIGHT", anchor, "RIGHT")
+ masterLooter:Point("LEFT", anchor, "LEFT")
+ elseif isAssist and db.raidRoleIcons.position == "TOPLEFT" then
+ assistant:Point("LEFT", anchor, "LEFT")
+ masterLooter:Point("RIGHT", anchor, "RIGHT")
+ elseif isAssist and db.raidRoleIcons.position == "TOPRIGHT" then
+ assistant:Point("RIGHT", anchor, "RIGHT")
+ masterLooter:Point("LEFT", anchor, "LEFT")
+ elseif isMasterLooter and db.raidRoleIcons.position == "TOPLEFT" then
+ masterLooter:Point("LEFT", anchor, "LEFT")
+ else
+ masterLooter:Point("RIGHT", anchor, "RIGHT")
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/Range.lua b/ElvUI/Modules/UnitFrames/Elements/Range.lua
new file mode 100644
index 0000000..895af7d
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/Range.lua
@@ -0,0 +1,177 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local SpellRange = E.Libs.SpellRange
+
+--Lua functions
+local pairs, ipairs = pairs, ipairs
+local find = string.find
+--WoW API / Variables
+local CheckInteractDistance = CheckInteractDistance
+local UnitCanAttack = UnitCanAttack
+local UnitInParty = UnitInParty
+local UnitInRaid = UnitInRaid
+local UnitInRange = UnitInRange
+local UnitIsConnected = UnitIsConnected
+local UnitIsDeadOrGhost = UnitIsDeadOrGhost
+local UnitIsUnit = UnitIsUnit
+
+local SRT = {}
+local function AddTable(tbl)
+ SRT[E.myclass][tbl] = {}
+end
+
+local function AddSpell(tbl, spellID)
+ SRT[E.myclass][tbl][#SRT[E.myclass][tbl] + 1] = spellID
+end
+
+function UF:UpdateRangeCheckSpells()
+ if not SRT[E.myclass] then SRT[E.myclass] = {} end
+
+ for tbl, spells in pairs(E.global.unitframe.spellRangeCheck[E.myclass]) do
+ AddTable(tbl) --Create the table holding spells, even if it ends up being an empty table
+ for spellID in pairs(spells) do
+ local enabled = spells[spellID]
+ if enabled then --We will allow value to be false to disable this spell from being used
+ AddSpell(tbl, spellID, enabled)
+ end
+ end
+ end
+end
+
+local function getUnit(unit)
+ if not find(unit, "party") or not find(unit, "raid") then
+ for i = 1, 4 do
+ if UnitIsUnit(unit, "party"..i) then
+ return "party"..i
+ end
+ end
+
+ for i = 1, 40 do
+ if UnitIsUnit(unit, "raid"..i) then
+ return "raid"..i
+ end
+ end
+ else
+ return unit
+ end
+end
+
+local function friendlyIsInRange(unit)
+ if (not UnitIsUnit(unit, "player")) and (UnitInParty(unit) or UnitInRaid(unit)) then
+ unit = getUnit(unit) -- swap the unit with `raid#` or `party#` when its NOT `player`, UnitIsUnit is true, and its not using `raid#` or `party#` already
+ end
+
+ local inRange, checkedRange = UnitInRange(unit)
+ if checkedRange and not inRange then
+ return false -- blizz checked and said the unit is out of range
+ end
+
+ if CheckInteractDistance(unit, 1) then
+ return true -- within 28 yards (arg2 as 1 is Compare Achievements distance)
+ end
+
+ if SRT[E.myclass] then
+ if SRT[E.myclass].resSpells and UnitIsDeadOrGhost(unit) and (#SRT[E.myclass].resSpells > 0) then -- dead with rez spells
+ for _, spellID in ipairs(SRT[E.myclass].resSpells) do
+ if SpellRange.IsSpellInRange(spellID, unit) == 1 then
+ return true -- within rez range
+ end
+ end
+
+ return false -- dead but no spells are in range
+ end
+
+ if SRT[E.myclass].friendlySpells and (#SRT[E.myclass].friendlySpells > 0) then -- you have some healy spell
+ for _, spellID in ipairs(SRT[E.myclass].friendlySpells) do
+ if SpellRange.IsSpellInRange(spellID, unit) == 1 then
+ return true -- within healy spell range
+ end
+ end
+ end
+ end
+
+ return false -- not within 28 yards and no spells in range
+end
+
+local function petIsInRange(unit)
+ if CheckInteractDistance(unit, 2) then
+ return true -- within 8 yards (arg2 as 2 is Trade distance)
+ end
+
+ if SRT[E.myclass] then
+ if SRT[E.myclass].friendlySpells and (#SRT[E.myclass].friendlySpells > 0) then -- you have some healy spell
+ for _, spellID in ipairs(SRT[E.myclass].friendlySpells) do
+ if SpellRange.IsSpellInRange(spellID, unit) == 1 then
+ return true
+ end
+ end
+ end
+
+ if SRT[E.myclass].petSpells and (#SRT[E.myclass].petSpells > 0) then -- you have some pet spell
+ for _, spellID in ipairs(SRT[E.myclass].petSpells) do
+ if SpellRange.IsSpellInRange(spellID, unit) == 1 then
+ return true
+ end
+ end
+ end
+ end
+
+ return false -- not within 8 yards and no spells in range
+end
+
+local function enemyIsInRange(unit)
+ if CheckInteractDistance(unit, 2) then
+ return true -- within 8 yards (arg2 as 2 is Trade distance)
+ end
+
+ if SRT[E.myclass] then
+ if SRT[E.myclass].enemySpells and (#SRT[E.myclass].enemySpells > 0) then -- you have some damage spell
+ for _, spellID in ipairs(SRT[E.myclass].enemySpells) do
+ if SpellRange.IsSpellInRange(spellID, unit) == 1 then
+ return true
+ end
+ end
+ end
+ end
+
+ return false -- not within 8 yards and no spells in range
+end
+
+local function enemyIsInLongRange(unit)
+ if SRT[E.myclass] then
+ if SRT[E.myclass].longEnemySpells and (#SRT[E.myclass].longEnemySpells > 0) then -- you have some 30+ range damage spell
+ for _, spellID in ipairs(SRT[E.myclass].longEnemySpells) do
+ if SpellRange.IsSpellInRange(spellID, unit) == 1 then
+ return true
+ end
+ end
+ end
+ end
+
+ return false
+end
+
+function UF:UpdateRange(unit)
+ if not self.Fader then return end
+ local alpha
+
+ unit = unit or self.unit
+
+ if self.forceInRange or unit == "player" then
+ alpha = self.Fader.MaxAlpha
+ elseif self.forceNotInRange then
+ alpha = self.Fader.MinAlpha
+ elseif unit then
+ if UnitCanAttack("player", unit) then
+ alpha = ((enemyIsInRange(unit) or enemyIsInLongRange(unit)) and self.Fader.MaxAlpha) or self.Fader.MinAlpha
+ elseif UnitIsUnit(unit, "pet") then
+ alpha = (petIsInRange(unit) and self.Fader.MaxAlpha) or self.Fader.MinAlpha
+ else
+ alpha = (UnitIsConnected(unit) and friendlyIsInRange(unit) and self.Fader.MaxAlpha) or self.Fader.MinAlpha
+ end
+ else
+ alpha = self.Fader.MaxAlpha
+ end
+
+ self.Fader.RangeAlpha = alpha
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/ReadyCheckIcon.lua b/ElvUI/Modules/UnitFrames/Elements/ReadyCheckIcon.lua
new file mode 100644
index 0000000..b70dd89
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/ReadyCheckIcon.lua
@@ -0,0 +1,31 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+
+function UF:Construct_ReadyCheckIcon(frame)
+ local tex = frame.RaisedElementParent.TextureParent:CreateTexture(nil, "OVERLAY")
+ tex:Size(12)
+ tex:Point("BOTTOM", frame.Health, "BOTTOM", 0, 2)
+
+ return tex
+end
+
+function UF:Configure_ReadyCheckIcon(frame)
+ local ReadyCheckIndicator = frame.ReadyCheckIndicator
+ local db = frame.db
+
+ if (db.readycheckIcon.enable) then
+ if not frame:IsElementEnabled("ReadyCheckIndicator") then
+ frame:EnableElement("ReadyCheckIndicator")
+ end
+
+ local attachPoint = self:GetObjectAnchorPoint(frame, db.readycheckIcon.attachTo)
+ ReadyCheckIndicator:ClearAllPoints()
+ ReadyCheckIndicator:Point(db.readycheckIcon.position, attachPoint, db.readycheckIcon.position, db.readycheckIcon.xOffset, db.readycheckIcon.yOffset)
+ ReadyCheckIndicator:Size(db.readycheckIcon.size)
+ else
+ frame:DisableElement("ReadyCheckIndicator")
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/RestingIndicator.lua b/ElvUI/Modules/UnitFrames/Elements/RestingIndicator.lua
new file mode 100644
index 0000000..321aff1
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/RestingIndicator.lua
@@ -0,0 +1,57 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+
+local RestingTextures = {
+ ["DEFAULT"] = [[Interface\CharacterFrame\UI-StateIcon]],
+ ["RESTING"] = E.Media.Textures.Resting,
+ ["RESTING1"] = E.Media.Textures.Resting1
+}
+
+function UF:Construct_RestingIndicator(frame)
+ return frame.RaisedElementParent.TextureParent:CreateTexture(nil, "OVERLAY")
+end
+
+function UF:Configure_RestingIndicator(frame)
+ if not frame.VARIABLES_SET then return end
+
+ local Icon = frame.RestingIndicator
+ local db = frame.db.RestIcon
+
+ if db.enable then
+ if not frame:IsElementEnabled("RestingIndicator") then
+ frame:EnableElement("RestingIndicator")
+ end
+
+ if db.defaultColor then
+ Icon:SetVertexColor(1, 1, 1, 1)
+ Icon:SetDesaturated(false)
+ else
+ Icon:SetVertexColor(db.color.r, db.color.g, db.color.b, db.color.a)
+ Icon:SetDesaturated(true)
+ end
+
+ if db.texture == "CUSTOM" and db.customTexture then
+ Icon:SetTexture(db.customTexture)
+ Icon:SetTexCoord(0, 1, 0, 1)
+ elseif db.texture ~= "DEFAULT" and RestingTextures[db.texture] then
+ Icon:SetTexture(RestingTextures[db.texture])
+ Icon:SetTexCoord(0, 1, 0, 1)
+ else
+ Icon:SetTexture(RestingTextures.DEFAULT)
+ Icon:SetTexCoord(0, .5, 0, .421875)
+ end
+
+ Icon:Size(db.size)
+ Icon:ClearAllPoints()
+ if frame.ORIENTATION ~= "RIGHT" and (frame.USE_PORTRAIT and not frame.USE_PORTRAIT_OVERLAY) then
+ Icon:Point("CENTER", frame.Portrait, db.anchorPoint, db.xOffset, db.yOffset)
+ else
+ Icon:Point("CENTER", frame.Health, db.anchorPoint, db.xOffset, db.yOffset)
+ end
+ elseif frame:IsElementEnabled("RestingIndicator") then
+ frame:DisableElement("RestingIndicator")
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/ResurrectionIcon.lua b/ElvUI/Modules/UnitFrames/Elements/ResurrectionIcon.lua
new file mode 100644
index 0000000..544d76d
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/ResurrectionIcon.lua
@@ -0,0 +1,35 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+
+function UF:Construct_ResurrectionIcon(frame)
+ local tex = frame.RaisedElementParent.TextureParent:CreateTexture(nil, "OVERLAY")
+ tex:SetTexture([[Interface\AddOns\ElvUI\media\textures\Raid-Icon-Rez]])
+ tex:Point("CENTER", frame.Health, "CENTER")
+ tex:Size(30)
+ tex:Hide()
+
+ return tex
+end
+
+function UF:Configure_ResurrectionIcon(frame)
+ local RI = frame.ResurrectIndicator
+ local db = frame.db
+
+ if db.resurrectIcon.enable then
+ if not frame:IsElementEnabled("ResurrectIndicator") then
+ frame:EnableElement("ResurrectIndicator")
+ end
+ RI:Size(db.resurrectIcon.size)
+
+ local attachPoint = self:GetObjectAnchorPoint(frame, db.resurrectIcon.attachToObject)
+ RI:ClearAllPoints()
+ RI:Point(db.resurrectIcon.attachTo, attachPoint, db.resurrectIcon.attachTo, db.resurrectIcon.xOffset, db.resurrectIcon.yOffset)
+ else
+ if frame:IsElementEnabled("ResurrectIndicator") then
+ frame:DisableElement("ResurrectIndicator")
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/RoleIcons.lua b/ElvUI/Modules/UnitFrames/Elements/RoleIcons.lua
new file mode 100644
index 0000000..02c5111
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/RoleIcons.lua
@@ -0,0 +1,83 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local random = math.random
+--WoW API / Variables
+local UnitGroupRolesAssigned = UnitGroupRolesAssigned
+local UnitIsConnected = UnitIsConnected
+
+function UF:Construct_RoleIcon(frame)
+ local tex = frame.RaisedElementParent.TextureParent:CreateTexture(nil, "ARTWORK")
+ tex:Size(17)
+ tex:Point("BOTTOM", frame.Health, "BOTTOM", 0, 2)
+ tex.Override = UF.UpdateRoleIcon
+ frame:RegisterEvent("UNIT_CONNECTION", UF.UpdateRoleIcon)
+
+ return tex
+end
+
+local roleIconTextures = {
+ TANK = E.Media.Textures.Tank,
+ HEALER = E.Media.Textures.Healer,
+ DAMAGER = E.Media.Textures.DPS
+}
+
+function UF:UpdateRoleIcon(event)
+ local lfdrole = self.GroupRoleIndicator
+ if not self.db then return end
+ local db = self.db.roleIcon
+
+ if (not db) or (db and not db.enable) then
+ lfdrole:Hide()
+ return
+ end
+
+ local isTank, isHealer, isDamage = UnitGroupRolesAssigned(self.unit)
+ local role = isTank and "TANK" or isHealer and "HEALER" or isDamage and "DAMAGER" or "NONE"
+ if self.isForced and role == "NONE" then
+ local rnd = random(1, 3)
+ role = rnd == 1 and "TANK" or (rnd == 2 and "HEALER" or (rnd == 3 and "DAMAGER"))
+ end
+
+-- local shouldHide = ((event == "PLAYER_REGEN_DISABLED" and db.combatHide and true) or false)
+
+ if (self.isForced or UnitIsConnected(self.unit)) and ((role == "DAMAGER" and db.damager) or (role == "HEALER" and db.healer) or (role == "TANK" and db.tank)) then
+ lfdrole:SetTexture(roleIconTextures[role])
+-- if not shouldHide then
+ lfdrole:Show()
+-- else
+-- lfdrole:Hide()
+-- end
+ else
+ lfdrole:Hide()
+ end
+end
+
+function UF:Configure_RoleIcon(frame)
+ local role = frame.GroupRoleIndicator
+ local db = frame.db
+
+ if db.roleIcon.enable then
+ frame:EnableElement("GroupRoleIndicator")
+ local attachPoint = self:GetObjectAnchorPoint(frame, db.roleIcon.attachTo)
+
+ role:ClearAllPoints()
+ role:Point(db.roleIcon.position, attachPoint, db.roleIcon.position, db.roleIcon.xOffset, db.roleIcon.yOffset)
+ role:Size(db.roleIcon.size)
+
+ -- if db.roleIcon.combatHide then
+ -- E:RegisterEventForObject("PLAYER_REGEN_ENABLED", frame, UF.UpdateRoleIcon)
+ -- E:RegisterEventForObject("PLAYER_REGEN_DISABLED", frame, UF.UpdateRoleIcon)
+ -- else
+ -- E:UnregisterEventForObject("PLAYER_REGEN_ENABLED", frame, UF.UpdateRoleIcon)
+ -- E:UnregisterEventForObject("PLAYER_REGEN_DISABLED", frame, UF.UpdateRoleIcon)
+ -- end
+ else
+ frame:DisableElement("GroupRoleIndicator")
+ role:Hide()
+ --Unregister combat hide events
+ -- E:UnregisterEventForObject("PLAYER_REGEN_ENABLED", frame, UF.UpdateRoleIcon)
+ -- E:UnregisterEventForObject("PLAYER_REGEN_DISABLED", frame, UF.UpdateRoleIcon)
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/Threat.lua b/ElvUI/Modules/UnitFrames/Elements/Threat.lua
new file mode 100644
index 0000000..8187d52
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/Threat.lua
@@ -0,0 +1,162 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+local unpack = unpack
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+function UF:Construct_Threat(frame)
+ local threat = CreateFrame("Frame", nil, frame)
+
+ --Main ThreatGlow
+ frame:CreateShadow()
+ threat.glow = frame.shadow
+ threat.glow:SetParent(frame)
+ threat.glow:Hide()
+ frame.shadow = nil
+
+ --Secondary ThreatGlow, for power frame when using power offset
+ frame:CreateShadow()
+ threat.powerGlow = frame.shadow
+ threat.powerGlow:SetParent(frame)
+ threat.powerGlow:SetFrameStrata("BACKGROUND")
+ threat.powerGlow:Hide()
+ frame.shadow = nil
+
+ threat.texIcon = threat:CreateTexture(nil, "OVERLAY")
+ threat.texIcon:Size(8)
+ threat.texIcon:SetTexture(E.media.blankTex)
+ threat.texIcon:Hide()
+
+ threat.PostUpdate = self.UpdateThreat
+ return threat
+end
+
+function UF:Configure_Threat(frame)
+ if not (frame.VARIABLES_SET and frame.ThreatIndicator) then return end
+
+ local threat = frame.ThreatIndicator
+ local db = frame.db
+
+ if db.threatStyle ~= "NONE" and db.threatStyle ~= nil then
+ if not frame:IsElementEnabled("ThreatIndicator") then
+ frame:EnableElement("ThreatIndicator")
+ end
+
+ if db.threatStyle == "GLOW" then
+ threat:SetFrameStrata("BACKGROUND")
+ threat.glow:SetFrameStrata("BACKGROUND")
+ threat.glow:ClearAllPoints()
+ if frame.USE_POWERBAR_OFFSET then
+ if frame.ORIENTATION == "RIGHT" then
+ threat.glow:Point("TOPLEFT", frame.Health.backdrop, "TOPLEFT", -frame.SHADOW_SPACING - frame.SPACING - (frame.HAPPINESS_WIDTH or 0), frame.SHADOW_SPACING + frame.SPACING + (frame.USE_CLASSBAR and (frame.USE_MINI_CLASSBAR and 0 or frame.CLASSBAR_HEIGHT) or 0))
+ threat.glow:Point("BOTTOMRIGHT", frame.Health.backdrop, "BOTTOMRIGHT", frame.SHADOW_SPACING + frame.SPACING, -frame.SHADOW_SPACING - frame.SPACING)
+ else
+ threat.glow:Point("TOPLEFT", frame.Health.backdrop, "TOPLEFT", -frame.SHADOW_SPACING - frame.SPACING, frame.SHADOW_SPACING + frame.SPACING + (frame.USE_CLASSBAR and (frame.USE_MINI_CLASSBAR and 0 or frame.CLASSBAR_HEIGHT) or 0))
+ threat.glow:Point("BOTTOMRIGHT", frame.Health.backdrop, "BOTTOMRIGHT", frame.SHADOW_SPACING + frame.SPACING + (frame.HAPPINESS_WIDTH or 0), -frame.SHADOW_SPACING - frame.SPACING)
+ end
+
+ threat.powerGlow:ClearAllPoints()
+ threat.powerGlow:Point("TOPLEFT", frame.Power.backdrop, "TOPLEFT", -frame.SHADOW_SPACING - frame.SPACING, frame.SHADOW_SPACING + frame.SPACING)
+ threat.powerGlow:Point("BOTTOMRIGHT", frame.Power.backdrop, "BOTTOMRIGHT", frame.SHADOW_SPACING + frame.SPACING, -frame.SHADOW_SPACING - frame.SPACING)
+ else
+ threat.glow:Point("TOPLEFT", -frame.SHADOW_SPACING, frame.SHADOW_SPACING-(frame.USE_MINI_CLASSBAR and frame.CLASSBAR_YOFFSET or 0))
+
+ if frame.USE_MINI_POWERBAR then
+ threat.glow:Point("BOTTOMLEFT", -frame.SHADOW_SPACING, -frame.SHADOW_SPACING + (frame.POWERBAR_HEIGHT/2))
+ threat.glow:Point("BOTTOMRIGHT", frame.SHADOW_SPACING, -frame.SHADOW_SPACING + (frame.POWERBAR_HEIGHT/2))
+ else
+ threat.glow:Point("BOTTOMLEFT", -frame.SHADOW_SPACING, -frame.SHADOW_SPACING)
+ threat.glow:Point("BOTTOMRIGHT", frame.SHADOW_SPACING, -frame.SHADOW_SPACING)
+ end
+ end
+ elseif db.threatStyle == "ICONTOPLEFT" or db.threatStyle == "ICONTOPRIGHT" or db.threatStyle == "ICONBOTTOMLEFT" or db.threatStyle == "ICONBOTTOMRIGHT" or db.threatStyle == "ICONTOP" or db.threatStyle == "ICONBOTTOM" or db.threatStyle == "ICONLEFT" or db.threatStyle == "ICONRIGHT" then
+ threat:SetFrameStrata("LOW")
+ threat:SetFrameLevel(75) --Inset power uses 50, we want it to appear above that
+ local point = db.threatStyle
+ point = string.gsub(point, "ICON", "")
+
+ threat.texIcon:ClearAllPoints()
+ threat.texIcon:Point(point, frame.Health, point)
+ elseif db.threatStyle == "HEALTHBORDER" then
+ if frame.InfoPanel then
+ frame.InfoPanel:SetFrameLevel(frame.Health:GetFrameLevel() - 3)
+ end
+ elseif db.threatStyle == "INFOPANELBORDER" then
+ if frame.InfoPanel then
+ frame.InfoPanel:SetFrameLevel(frame.Health:GetFrameLevel() + 3)
+ end
+ end
+ elseif frame:IsElementEnabled("ThreatIndicator") then
+ frame:DisableElement("ThreatIndicator")
+ end
+end
+
+function UF:UpdateThreat(unit, status, r, g, b)
+ local parent = self:GetParent()
+
+ if (parent.unit ~= unit) or not unit then return end
+
+ local db = parent.db
+ if not db then return end
+
+ if status and status > 1 then
+ if db.threatStyle == "GLOW" then
+ self.glow:Show()
+ self.glow:SetBackdropBorderColor(r, g, b)
+
+ if parent.USE_POWERBAR_OFFSET then
+ self.powerGlow:Show()
+ self.powerGlow:SetBackdropBorderColor(r, g, b)
+ end
+ elseif db.threatStyle == "BORDERS" then
+ parent.Health.backdrop:SetBackdropBorderColor(r, g, b)
+
+ if parent.Power and parent.Power.backdrop then
+ parent.Power.backdrop:SetBackdropBorderColor(r, g, b)
+ end
+
+ if parent.ClassBar and parent[parent.ClassBar] and parent[parent.ClassBar].backdrop then
+ parent[parent.ClassBar].backdrop:SetBackdropBorderColor(r, g, b)
+ end
+
+ if parent.InfoPanel and parent.InfoPanel.backdrop then
+ parent.InfoPanel.backdrop:SetBackdropBorderColor(r, g, b)
+ end
+ elseif db.threatStyle == "HEALTHBORDER" then
+ parent.Health.backdrop:SetBackdropBorderColor(r, g, b)
+ elseif db.threatStyle == "INFOPANELBORDER" then
+ parent.InfoPanel.backdrop:SetBackdropBorderColor(r, g, b)
+ elseif db.threatStyle ~= "NONE" and self.texIcon then
+ self.texIcon:Show()
+ self.texIcon:SetVertexColor(r, g, b)
+ end
+ else
+ r, g, b = unpack(E.media.unitframeBorderColor)
+ if db.threatStyle == "GLOW" then
+ self.glow:Hide()
+ self.powerGlow:Hide()
+ elseif db.threatStyle == "BORDERS" then
+ parent.Health.backdrop:SetBackdropBorderColor(r, g, b)
+
+ if parent.Power and parent.Power.backdrop then
+ parent.Power.backdrop:SetBackdropBorderColor(r, g, b)
+ end
+
+ if parent.ClassBar and parent[parent.ClassBar] and parent[parent.ClassBar].backdrop then
+ parent[parent.ClassBar].backdrop:SetBackdropBorderColor(r, g, b)
+ end
+
+ if parent.InfoPanel and parent.InfoPanel.backdrop then
+ parent.InfoPanel.backdrop:SetBackdropBorderColor(r, g, b)
+ end
+ elseif db.threatStyle == "HEALTHBORDER" then
+ parent.Health.backdrop:SetBackdropBorderColor(r, g, b)
+ elseif db.threatStyle == "INFOPANELBORDER" then
+ parent.InfoPanel.backdrop:SetBackdropBorderColor(r, g, b)
+ elseif db.threatStyle ~= "NONE" and self.texIcon then
+ self.texIcon:Hide()
+ end
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Elements/Trinket.lua b/ElvUI/Modules/UnitFrames/Elements/Trinket.lua
new file mode 100644
index 0000000..2c15441
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Elements/Trinket.lua
@@ -0,0 +1,36 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+function UF:Construct_Trinket(frame)
+ local trinket = CreateFrame("Frame", nil, frame)
+ trinket.bg = CreateFrame("Frame", nil, trinket)
+ trinket.bg:SetTemplate(nil, nil, nil, self.thinBorders, true)
+ trinket.bg:SetFrameLevel(trinket:GetFrameLevel() - 1)
+ trinket:SetInside(trinket.bg)
+
+ return trinket
+end
+
+function UF:Configure_Trinket(frame)
+ if not frame.VARIABLES_SET then return end
+ local db = frame.db
+ local trinket = frame.Trinket
+
+ trinket.bg:Size(db.pvpTrinket.size)
+ trinket.bg:ClearAllPoints()
+ if db.pvpTrinket.position == "RIGHT" then
+ trinket.bg:Point("LEFT", frame, "RIGHT", db.pvpTrinket.xOffset, db.pvpTrinket.yOffset)
+ else
+ trinket.bg:Point("RIGHT", frame, "LEFT", db.pvpTrinket.xOffset, db.pvpTrinket.yOffset)
+ end
+
+ if db.pvpTrinket.enable and not frame:IsElementEnabled("Trinket") then
+ frame:EnableElement("Trinket")
+ elseif not db.pvpTrinket.enable and frame:IsElementEnabled("Trinket") then
+ frame:DisableElement("Trinket")
+ end
+end
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Groups/Arena.lua b/ElvUI/Modules/UnitFrames/Groups/Arena.lua
new file mode 100644
index 0000000..34306a9
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Groups/Arena.lua
@@ -0,0 +1,152 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local _G = _G
+--WoW API / Variables
+local CreateFrame = CreateFrame
+
+local ArenaHeader = CreateFrame("Frame", "ArenaHeader", UIParent)
+ArenaHeader:SetFrameStrata("LOW")
+
+function UF:Construct_ArenaFrames(frame)
+ frame.RaisedElementParent = CreateFrame("Frame", nil, frame)
+ frame.RaisedElementParent.TextureParent = CreateFrame("Frame", nil, frame.RaisedElementParent)
+ frame.RaisedElementParent:SetFrameLevel(frame:GetFrameLevel() + 100)
+
+ frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
+ frame.Name = self:Construct_NameText(frame)
+
+ frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
+
+ frame.Portrait3D = self:Construct_Portrait(frame, "model")
+ frame.Portrait2D = self:Construct_Portrait(frame, "texture")
+ frame.Buffs = self:Construct_Buffs(frame)
+ frame.Debuffs = self:Construct_Debuffs(frame)
+ frame.Castbar = self:Construct_Castbar(frame)
+ frame.HealCommBar = self:Construct_HealComm(frame)
+ frame.MouseGlow = self:Construct_MouseGlow(frame)
+ frame.TargetGlow = self:Construct_TargetGlow(frame)
+ frame.Trinket = self:Construct_Trinket(frame)
+ frame.Fader = self:Construct_Fader()
+ frame.Cutaway = self:Construct_Cutaway(frame)
+ frame:SetAttribute("type2", "focus")
+
+ frame.customTexts = {}
+ frame.InfoPanel = self:Construct_InfoPanel(frame)
+ frame.unitframeType = "arena"
+
+ ArenaHeader:Point("BOTTOMRIGHT", E.UIParent, "RIGHT", -105, -165)
+ E:CreateMover(ArenaHeader, ArenaHeader:GetName().."Mover", L["Arena Frames"], nil, nil, nil, "ALL,ARENA", nil, "unitframe,arena,generalGroup")
+ frame.mover = ArenaHeader.mover
+end
+
+function UF:Update_ArenaFrames(frame, db)
+ frame.db = db
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.CLASSBAR_YOFFSET = 0
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ frame.colors = ElvUF.colors
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+
+ UF:Configure_InfoPanel(frame)
+
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+ --Portrait
+ UF:Configure_Portrait(frame)
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+ --Castbar
+ UF:Configure_Castbar(frame)
+ --Trinket
+ UF:Configure_Trinket(frame)
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --Heal Prediction
+ UF:Configure_HealComm(frame)
+
+ --CustomTexts
+ UF:Configure_CustomTexts(frame)
+
+ frame:ClearAllPoints()
+ if frame.index == 1 then
+ local ArenaHeaderMover = ArenaHeaderMover
+ if db.growthDirection == "UP" then
+ frame:Point("BOTTOMRIGHT", ArenaHeaderMover, "BOTTOMRIGHT")
+ elseif db.growthDirection == "RIGHT" then
+ frame:Point("LEFT", ArenaHeaderMover, "LEFT")
+ elseif db.growthDirection == "LEFT" then
+ frame:Point("RIGHT", ArenaHeaderMover, "RIGHT")
+ else --Down
+ frame:Point("TOPRIGHT", ArenaHeaderMover, "TOPRIGHT")
+ end
+ else
+ if db.growthDirection == "UP" then
+ frame:Point("BOTTOMRIGHT", _G["ElvUF_Arena"..frame.index-1], "TOPRIGHT", 0, db.spacing)
+ elseif db.growthDirection == "RIGHT" then
+ frame:Point("LEFT", _G["ElvUF_Arena"..frame.index-1], "RIGHT", db.spacing, 0)
+ elseif db.growthDirection == "LEFT" then
+ frame:Point("RIGHT", _G["ElvUF_Arena"..frame.index-1], "LEFT", -db.spacing, 0)
+ else --Down
+ frame:Point("TOPRIGHT", _G["ElvUF_Arena"..frame.index-1], "BOTTOMRIGHT", 0, -db.spacing)
+ end
+ end
+
+ if db.growthDirection == "UP" or db.growthDirection == "DOWN" then
+ ArenaHeader:Width(frame.UNIT_WIDTH)
+ ArenaHeader:Height(frame.UNIT_HEIGHT + ((frame.UNIT_HEIGHT + db.spacing) * 4))
+ elseif db.growthDirection == "LEFT" or db.growthDirection == "RIGHT" then
+ ArenaHeader:Width(frame.UNIT_WIDTH + ((frame.UNIT_WIDTH + db.spacing) * 4))
+ ArenaHeader:Height(frame.UNIT_HEIGHT)
+ end
+
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+UF.unitgroupstoload.arena = {5}
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Groups/Assist.lua b/ElvUI/Modules/UnitFrames/Groups/Assist.lua
new file mode 100644
index 0000000..8008380
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Groups/Assist.lua
@@ -0,0 +1,189 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local max = math.max
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local InCombatLockdown = InCombatLockdown
+local RegisterStateDriver = RegisterStateDriver
+
+function UF:Construct_AssistFrames()
+ self:SetScript("OnEnter", UnitFrame_OnEnter)
+ self:SetScript("OnLeave", UnitFrame_OnLeave)
+
+ self.RaisedElementParent = CreateFrame("Frame", nil, self)
+ self.RaisedElementParent.TextureParent = CreateFrame("Frame", nil, self.RaisedElementParent)
+ self.RaisedElementParent:SetFrameLevel(self:GetFrameLevel() + 100)
+
+ self.Health = UF:Construct_HealthBar(self, true)
+ self.Name = UF:Construct_NameText(self)
+ self.ThreatIndicator = UF:Construct_Threat(self)
+ self.RaidTargetIndicator = UF:Construct_RaidIcon(self)
+ self.MouseGlow = UF:Construct_MouseGlow(self)
+ self.TargetGlow = UF:Construct_TargetGlow(self)
+ self.Fader = UF:Construct_Fader()
+ self.Cutaway = UF:Construct_Cutaway(self)
+
+ if not self.isChild then
+ self.Buffs = UF:Construct_Buffs(self)
+ self.Debuffs = UF:Construct_Debuffs(self)
+ self.AuraWatch = UF:Construct_AuraWatch(self)
+ self.RaidDebuffs = UF:Construct_RaidDebuffs(self)
+ self.DebuffHighlight = UF:Construct_DebuffHighlight(self)
+
+ self.unitframeType = "assist"
+ else
+ self.unitframeType = "assisttarget"
+ end
+
+ self.originalParent = self:GetParent()
+
+ UF:Update_StatusBars()
+ UF:Update_FontStrings()
+
+ self.db = UF.db.units.assist
+ self.PostCreate = UF.Update_AssistFrames
+
+ return self
+end
+
+function UF:Update_AssistHeader(header, db)
+ header:Hide()
+ header.db = db
+
+ RegisterStateDriver(header, "visibility", "show")
+ RegisterStateDriver(header, "visibility", "[@raid1,exists] show;hide")
+
+ local width, height = header:GetSize()
+ header.dirtyWidth, header.dirtyHeight = width, max(height, db.height)
+
+ if not header.positioned then
+ header:ClearAllPoints()
+ header:Point("TOPLEFT", E.UIParent, "TOPLEFT", 4, -248)
+ E:CreateMover(header, header:GetName().."Mover", L["MA Frames"], nil, nil, nil, "ALL,RAID", nil, "unitframe,assist,generalGroup")
+ header.mover.positionOverride = "TOPLEFT"
+ header:SetAttribute("minHeight", header.dirtyHeight)
+ header:SetAttribute("minWidth", header.dirtyWidth)
+ header.positioned = true
+ end
+end
+
+function UF:Update_AssistFrames(frame, db)
+ if not db then
+ db = frame.db
+ else
+ frame.db = db
+ end
+
+ frame.colors = ElvUF.colors
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ if self.thinBorders then
+ frame.SPACING = 0
+ frame.BORDER = E.mult
+ else
+ frame.BORDER = E.Border
+ frame.SPACING = E.Spacing
+ end
+ frame.SHADOW_SPACING = 3
+
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.height
+
+ frame.USE_POWERBAR = false
+ frame.POWERBAR_DETACHED = false
+ frame.USE_INSET_POWERBAR = false
+ frame.USE_MINI_POWERBAR = false
+ frame.USE_POWERBAR_OFFSET = false
+ frame.POWERBAR_OFFSET = 0
+ frame.POWERBAR_HEIGHT = 0
+ frame.POWERBAR_WIDTH = 0
+
+ frame.USE_PORTRAIT = false
+ frame.USE_PORTRAIT_OVERLAY = false
+ frame.PORTRAIT_WIDTH = 0
+
+ frame.CLASSBAR_YOFFSET = 0
+ frame.BOTTOM_OFFSET = 0
+
+ frame.VARIABLES_SET = true
+ end
+
+ if frame.isChild and frame.originalParent then
+ local childDB = db.targetsGroup
+ frame.db = db.targetsGroup
+ if not frame.originalParent.childList then
+ frame.originalParent.childList = {}
+ end
+ frame.originalParent.childList[frame] = true
+
+ if not InCombatLockdown() then
+ if childDB.enable then
+ frame:SetParent(frame.originalParent)
+ RegisterUnitWatch(frame)
+ frame:Size(childDB.width, childDB.height)
+ frame:ClearAllPoints()
+ frame:Point(E.InversePoints[childDB.anchorPoint], frame.originalParent, childDB.anchorPoint, childDB.xOffset, childDB.yOffset)
+ else
+ UnregisterUnitWatch(frame)
+ frame:SetParent(E.HiddenFrame)
+ end
+ else
+ if childDB.enable then
+ frame:SetAttribute("initial-anchor", format("%s,%s,%d,%d", E.InversePoints[childDB.anchorPoint], childDB.anchorPoint, childDB.xOffset, childDB.yOffset))
+ frame:SetAttribute("initial-width", frame.UNIT_WIDTH)
+ frame:SetAttribute("initial-height", frame.UNIT_HEIGHT)
+ end
+ end
+ else
+ if not InCombatLockdown() then
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ else
+ frame:SetAttribute("initial-width", frame.UNIT_WIDTH)
+ frame:SetAttribute("initial-height", frame.UNIT_HEIGHT)
+ end
+ end
+
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ UF:Configure_RaidIcon(frame)
+
+ if not frame.isChild then
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --RaidDebuffs
+ UF:Configure_RaidDebuffs(frame)
+
+ --Debuff Highlight
+ UF:Configure_DebuffHighlight(frame)
+
+ --Buff Indicator
+ UF:UpdateAuraWatch(frame)
+ end
+
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+UF.headerstoload.assist = {"MAINASSIST", "ELVUI_UNITTARGET"}
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Groups/Boss.lua b/ElvUI/Modules/UnitFrames/Groups/Boss.lua
new file mode 100644
index 0000000..18255c9
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Groups/Boss.lua
@@ -0,0 +1,152 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local _G = _G
+--WoW API / Variables
+local MAX_BOSS_FRAMES = MAX_BOSS_FRAMES
+
+local BossHeader = CreateFrame("Frame", "BossHeader", UIParent)
+BossHeader:SetFrameStrata("LOW")
+
+function UF:Construct_BossFrames(frame)
+ frame.RaisedElementParent = CreateFrame("Frame", nil, frame)
+ frame.RaisedElementParent.TextureParent = CreateFrame("Frame", nil, frame.RaisedElementParent)
+ frame.RaisedElementParent:SetFrameLevel(frame:GetFrameLevel() + 100)
+
+ frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
+
+ frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
+
+ frame.Name = self:Construct_NameText(frame)
+
+ frame.Portrait3D = self:Construct_Portrait(frame, "model")
+ frame.Portrait2D = self:Construct_Portrait(frame, "texture")
+ frame.InfoPanel = self:Construct_InfoPanel(frame)
+ frame.Buffs = self:Construct_Buffs(frame)
+
+ frame.Debuffs = self:Construct_Debuffs(frame)
+ frame.DebuffHighlight = self:Construct_DebuffHighlight(frame)
+
+ frame.Castbar = self:Construct_Castbar(frame)
+ frame.RaidTargetIndicator = self:Construct_RaidIcon(frame)
+ frame.Fader = self:Construct_Fader()
+ frame.Cutaway = self:Construct_Cutaway(frame)
+ frame.MouseGlow = self:Construct_MouseGlow(frame)
+ frame.TargetGlow = self:Construct_TargetGlow(frame)
+ frame:SetAttribute("type2", "focus")
+ frame.customTexts = {}
+
+ BossHeader:Point("BOTTOMRIGHT", E.UIParent, "RIGHT", -105, -165)
+ E:CreateMover(BossHeader, BossHeader:GetName().."Mover", L["Boss Frames"], nil, nil, nil, "ALL,PARTY,RAID", nil, "unitframe,boss,generalGroup")
+ frame.mover = BossHeader.mover
+
+ frame.unitframeType = "boss"
+end
+
+function UF:Update_BossFrames(frame, db)
+ frame.db = db
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ frame.colors = ElvUF.colors
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ UF:Configure_InfoPanel(frame)
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --Castbar
+ UF:Configure_Castbar(frame)
+
+ --Raid Icon
+ UF:Configure_RaidIcon(frame)
+
+ UF:Configure_DebuffHighlight(frame)
+
+ UF:Configure_CustomTexts(frame)
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ frame:ClearAllPoints()
+ if frame.index == 1 then
+ if db.growthDirection == "UP" then
+ frame:Point("BOTTOMRIGHT", BossHeaderMover, "BOTTOMRIGHT")
+ elseif db.growthDirection == "RIGHT" then
+ frame:Point("LEFT", BossHeaderMover, "LEFT")
+ elseif db.growthDirection == "LEFT" then
+ frame:Point("RIGHT", BossHeaderMover, "RIGHT")
+ else --Down
+ frame:Point("TOPRIGHT", BossHeaderMover, "TOPRIGHT")
+ end
+ else
+ if db.growthDirection == "UP" then
+ frame:Point("BOTTOMRIGHT", _G["ElvUF_Boss"..frame.index-1], "TOPRIGHT", 0, db.spacing)
+ elseif db.growthDirection == "RIGHT" then
+ frame:Point("LEFT", _G["ElvUF_Boss"..frame.index-1], "RIGHT", db.spacing, 0)
+ elseif db.growthDirection == "LEFT" then
+ frame:Point("RIGHT", _G["ElvUF_Boss"..frame.index-1], "LEFT", -db.spacing, 0)
+ else --Down
+ frame:Point("TOPRIGHT", _G["ElvUF_Boss"..frame.index-1], "BOTTOMRIGHT", 0, -db.spacing)
+ end
+ end
+
+ if db.growthDirection == "UP" or db.growthDirection == "DOWN" then
+ BossHeader:Width(frame.UNIT_WIDTH)
+ BossHeader:Height(frame.UNIT_HEIGHT + ((frame.UNIT_HEIGHT + db.spacing) * (MAX_BOSS_FRAMES -1)))
+ elseif db.growthDirection == "LEFT" or db.growthDirection == "RIGHT" then
+ BossHeader:Width(frame.UNIT_WIDTH + ((frame.UNIT_WIDTH + db.spacing) * (MAX_BOSS_FRAMES -1)))
+ BossHeader:Height(frame.UNIT_HEIGHT)
+ end
+
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+UF.unitgroupstoload.boss = {MAX_BOSS_FRAMES}
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Groups/Load_Groups.xml b/ElvUI/Modules/UnitFrames/Groups/Load_Groups.xml
new file mode 100644
index 0000000..16584e4
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Groups/Load_Groups.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Groups/Party.lua b/ElvUI/Modules/UnitFrames/Groups/Party.lua
new file mode 100644
index 0000000..ba0dd3c
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Groups/Party.lua
@@ -0,0 +1,290 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local _G = _G
+local format = string.format
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetInstanceInfo = GetInstanceInfo
+local InCombatLockdown = InCombatLockdown
+local RegisterStateDriver = RegisterStateDriver
+local UnregisterStateDriver = UnregisterStateDriver
+
+function UF:Construct_PartyFrames()
+ self:SetScript("OnEnter", UnitFrame_OnEnter)
+ self:SetScript("OnLeave", UnitFrame_OnLeave)
+
+ self.RaisedElementParent = CreateFrame("Frame", nil, self)
+ self.RaisedElementParent.TextureParent = CreateFrame("Frame", nil, self.RaisedElementParent)
+ self.RaisedElementParent:SetFrameLevel(self:GetFrameLevel() + 100)
+ self.BORDER = E.Border
+ self.SPACING = E.Spacing
+ self.SHADOW_SPACING = 3
+ if self.isChild then
+ self.Health = UF:Construct_HealthBar(self, true)
+ self.MouseGlow = UF:Construct_MouseGlow(self)
+ self.TargetGlow = UF:Construct_TargetGlow(self)
+ self.Name = UF:Construct_NameText(self)
+ self.RaidTargetIndicator = UF:Construct_RaidIcon(self)
+
+ self.originalParent = self:GetParent()
+
+ self.childType = "pet"
+ if self == _G[self.originalParent:GetName().."Target"] then
+ self.childType = "target"
+ end
+
+ self.unitframeType = "party"..self.childType
+ else
+ self.Health = UF:Construct_HealthBar(self, true, true, "RIGHT")
+
+ self.Power = UF:Construct_PowerBar(self, true, true, "LEFT")
+ self.Power.frequentUpdates = false
+
+ self.Portrait3D = UF:Construct_Portrait(self, "model")
+ self.Portrait2D = UF:Construct_Portrait(self, "texture")
+ self.InfoPanel = UF:Construct_InfoPanel(self)
+ self.Name = UF:Construct_NameText(self)
+ self.Buffs = UF:Construct_Buffs(self)
+ self.Debuffs = UF:Construct_Debuffs(self)
+ self.AuraWatch = UF:Construct_AuraWatch(self)
+ self.RaidDebuffs = UF:Construct_RaidDebuffs(self)
+ self.DebuffHighlight = UF:Construct_DebuffHighlight(self)
+ self.ResurrectIndicator = UF:Construct_ResurrectionIcon(self)
+ self.GroupRoleIndicator = UF:Construct_RoleIcon(self)
+ self.RaidRoleFramesAnchor = UF:Construct_RaidRoleFrames(self)
+ self.MouseGlow = UF:Construct_MouseGlow(self)
+ self.TargetGlow = UF:Construct_TargetGlow(self)
+ self.ThreatIndicator = UF:Construct_Threat(self)
+ self.RaidTargetIndicator = UF:Construct_RaidIcon(self)
+ self.ReadyCheckIndicator = UF:Construct_ReadyCheckIcon(self)
+ self.HealCommBar = UF:Construct_HealComm(self)
+ self.GPS = UF:Construct_GPS(self)
+ self.customTexts = {}
+
+ self.Castbar = UF:Construct_Castbar(self)
+
+ self.unitframeType = "party"
+ end
+
+ self.Fader = UF:Construct_Fader()
+ self.Cutaway = UF:Construct_Cutaway(self)
+
+ UF:Update_StatusBars()
+ UF:Update_FontStrings()
+
+ self.db = UF.db.units.party
+ self.PostCreate = UF.Update_PartyFrames
+
+ return self
+end
+
+function UF:Update_PartyHeader(header, db)
+ header.db = db
+
+ local headerHolder = header:GetParent()
+ headerHolder.db = db
+
+ if not headerHolder.positioned then
+ headerHolder:ClearAllPoints()
+ headerHolder:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", 4, 195)
+
+ E:CreateMover(headerHolder, headerHolder:GetName().."Mover", L["Party Frames"], nil, nil, nil, "ALL,PARTY,ARENA", nil, "unitframe,party,generalGroup")
+ headerHolder.positioned = true
+
+ headerHolder:RegisterEvent("PLAYER_LOGIN")
+ headerHolder:RegisterEvent("ZONE_CHANGED_NEW_AREA")
+ headerHolder:SetScript("OnEvent", UF.PartySmartVisibility)
+ end
+
+ UF.PartySmartVisibility(headerHolder)
+end
+
+function UF:PartySmartVisibility(event)
+ if not self.db or (self.db and not self.db.enable) or (UF.db and not UF.db.smartRaidFilter) or self.isForced then
+ self.blockVisibilityChanges = false
+ return
+ end
+
+ if event == "PLAYER_REGEN_ENABLED" then
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED")
+ end
+
+ if not InCombatLockdown() then
+ local _, instanceType = GetInstanceInfo()
+ if instanceType == "raid" or instanceType == "pvp" then
+ UnregisterStateDriver(self, "visibility")
+ self.blockVisibilityChanges = true
+ self:Hide()
+ elseif self.db.visibility then
+ RegisterStateDriver(self, "visibility", self.db.visibility)
+ self.blockVisibilityChanges = false
+ end
+ else
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ end
+end
+
+function UF:Update_PartyFrames(frame, db)
+ if not db then
+ db = frame.db
+ else
+ frame.db = db
+ end
+
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame.colors = ElvUF.colors
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+
+ do
+ if self.thinBorders then
+ frame.SPACING = 0
+ frame.BORDER = E.mult
+ else
+ frame.BORDER = E.Border
+ frame.SPACING = E.Spacing
+ end
+
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+ frame.CLASSBAR_YOFFSET = 0
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ if frame.isChild then
+ frame.USE_PORTAIT = false
+ frame.USE_PORTRAIT_OVERLAY = false
+ frame.PORTRAIT_WIDTH = 0
+ frame.USE_POWERBAR = false
+ frame.USE_INSET_POWERBAR = false
+ frame.USE_MINI_POWERBAR = false
+ frame.USE_POWERBAR_OFFSET = false
+ frame.POWERBAR_OFFSET = 0
+
+ frame.POWERBAR_HEIGHT = 0
+ frame.POWERBAR_WIDTH = 0
+
+ frame.BOTTOM_OFFSET = 0
+
+ local childDB = db.petsGroup
+ if frame.childType == "target" then
+ childDB = db.targetsGroup
+ end
+
+ frame.UNIT_WIDTH = childDB.width
+ frame.UNIT_HEIGHT = childDB.height
+
+ if not frame.originalParent.childList then
+ frame.originalParent.childList = {}
+ end
+ frame.originalParent.childList[frame] = true
+
+ if not InCombatLockdown() then
+ if childDB.enable then
+ frame:SetParent(frame.originalParent)
+ RegisterUnitWatch(frame)
+ frame:Size(childDB.width, childDB.height)
+ frame:ClearAllPoints()
+ frame:Point(E.InversePoints[childDB.anchorPoint], frame.originalParent, childDB.anchorPoint, childDB.xOffset, childDB.yOffset)
+ else
+ UnregisterUnitWatch(frame)
+ frame:SetParent(E.HiddenFrame)
+ end
+ else
+ if childDB.enable then
+ frame:SetAttribute("initial-anchor", format("%s,%s,%d,%d", E.InversePoints[childDB.anchorPoint], childDB.anchorPoint, childDB.xOffset, childDB.yOffset))
+ frame:SetAttribute("initial-width", frame.UNIT_WIDTH)
+ frame:SetAttribute("initial-height", frame.UNIT_HEIGHT)
+ end
+ end
+
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ UF:Configure_RaidIcon(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame, frame.childType)
+ else
+ if not InCombatLockdown() then
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ else
+ frame:SetAttribute("initial-width", frame.UNIT_WIDTH)
+ frame:SetAttribute("initial-height", frame.UNIT_HEIGHT)
+ end
+
+ UF:Configure_InfoPanel(frame)
+ UF:Configure_HealthBar(frame)
+
+ UF:UpdateNameSettings(frame)
+
+ UF:Configure_Power(frame)
+
+ UF:Configure_Portrait(frame)
+
+ UF:Configure_Threat(frame)
+
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ UF:Configure_RaidDebuffs(frame)
+
+ UF:Configure_Castbar(frame)
+
+ UF:Configure_RaidIcon(frame)
+
+ UF:Configure_DebuffHighlight(frame)
+
+ UF:Configure_ResurrectionIcon(frame)
+
+ UF:Configure_RoleIcon(frame)
+
+ UF:Configure_HealComm(frame)
+
+ UF:Configure_GPS(frame)
+
+ UF:Configure_RaidRoleIcons(frame)
+
+ UF:UpdateAuraWatch(frame)
+
+ UF:Configure_ReadyCheckIcon(frame)
+
+ UF:Configure_CustomTexts(frame)
+ end
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+UF.headerstoload.party = {nil, "ELVUI_UNITPET, ELVUI_UNITTARGET"}
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Groups/Raid.lua b/ElvUI/Modules/UnitFrames/Groups/Raid.lua
new file mode 100644
index 0000000..743551e
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Groups/Raid.lua
@@ -0,0 +1,243 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetInstanceInfo = GetInstanceInfo
+local InCombatLockdown = InCombatLockdown
+local RegisterStateDriver = RegisterStateDriver
+local UnregisterStateDriver = UnregisterStateDriver
+
+function UF:Construct_RaidFrames()
+ self:SetScript("OnEnter", UnitFrame_OnEnter)
+ self:SetScript("OnLeave", UnitFrame_OnLeave)
+
+ self.RaisedElementParent = CreateFrame("Frame", nil, self)
+ self.RaisedElementParent.TextureParent = CreateFrame("Frame", nil, self.RaisedElementParent)
+ self.RaisedElementParent:SetFrameLevel(self:GetFrameLevel() + 100)
+
+ self.Health = UF:Construct_HealthBar(self, true, true, "RIGHT")
+
+ self.Power = UF:Construct_PowerBar(self, true, true, "LEFT")
+ self.Power.frequentUpdates = false
+
+ self.Portrait3D = UF:Construct_Portrait(self, "model")
+ self.Portrait2D = UF:Construct_Portrait(self, "texture")
+
+ self.Name = UF:Construct_NameText(self)
+ self.Buffs = UF:Construct_Buffs(self)
+ self.Debuffs = UF:Construct_Debuffs(self)
+ self.AuraWatch = UF:Construct_AuraWatch(self)
+ self.RaidDebuffs = UF:Construct_RaidDebuffs(self)
+ self.DebuffHighlight = UF:Construct_DebuffHighlight(self)
+ self.ResurrectIndicator = UF:Construct_ResurrectionIcon(self)
+ self.RaidRoleFramesAnchor = UF:Construct_RaidRoleFrames(self)
+ self.MouseGlow = UF:Construct_MouseGlow(self)
+ self.TargetGlow = UF:Construct_TargetGlow(self)
+
+ self.ThreatIndicator = UF:Construct_Threat(self)
+ self.RaidTargetIndicator = UF:Construct_RaidIcon(self)
+ self.ReadyCheckIndicator = UF:Construct_ReadyCheckIcon(self)
+ self.HealCommBar = UF:Construct_HealComm(self)
+ self.GPS = UF:Construct_GPS(self)
+ self.Fader = UF:Construct_Fader()
+ self.Cutaway = UF:Construct_Cutaway(self)
+
+ self.customTexts = {}
+ self.InfoPanel = UF:Construct_InfoPanel(self)
+
+ self.unitframeType = "raid"
+ UF:Update_StatusBars()
+ UF:Update_FontStrings()
+
+ self.db = UF.db.units.raid
+ self.PostCreate = UF.Update_RaidFrames
+
+ return self
+end
+
+function UF:RaidSmartVisibility(event)
+ if not self.db or (self.db and not self.db.enable) or (UF.db and not UF.db.smartRaidFilter) or self.isForced then
+ self.blockVisibilityChanges = false
+ return
+ end
+
+ if event == "PLAYER_REGEN_ENABLED" then self:UnregisterEvent("PLAYER_REGEN_ENABLED") end
+
+ if not InCombatLockdown() then
+ self.isInstanceForced = nil
+ local _, instanceType, _, _, maxPlayers = GetInstanceInfo()
+ if instanceType == "raid" or instanceType == "pvp" then
+ local mapID = GetCurrentMapAreaID()
+ if UF.instanceMapIDs[mapID] then
+ maxPlayers = UF.instanceMapIDs[mapID]
+ end
+
+ UnregisterStateDriver(self, "visibility")
+
+ if maxPlayers < 40 then
+ self:Show()
+ self.isInstanceForced = true
+ self.blockVisibilityChanges = false
+ if ElvUF_Raid.numGroups ~= E:Round(maxPlayers/5) and event then
+ UF:CreateAndUpdateHeaderGroup("raid")
+ end
+ else
+ self.blockVisibilityChanges = true
+ self:Hide()
+ end
+ elseif self.db.visibility then
+ RegisterStateDriver(self, "visibility", self.db.visibility)
+ self.blockVisibilityChanges = false
+ if ElvUF_Raid.numGroups ~= self.db.numGroups then
+ UF:CreateAndUpdateHeaderGroup("raid")
+ end
+ end
+ else
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ return
+ end
+end
+
+function UF:Update_RaidHeader(header, db)
+ header.db = db
+
+ local headerHolder = header:GetParent()
+ headerHolder.db = db
+
+ if not headerHolder.positioned then
+ headerHolder:ClearAllPoints()
+ headerHolder:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", 4, 195)
+
+ E:CreateMover(headerHolder, headerHolder:GetName().."Mover", L["Raid Frames"], nil, nil, nil, "ALL,RAID", nil, "unitframe,raid,generalGroup")
+
+ headerHolder:RegisterEvent("PLAYER_LOGIN")
+ headerHolder:RegisterEvent("ZONE_CHANGED_NEW_AREA")
+ headerHolder:SetScript("OnEvent", UF.RaidSmartVisibility)
+ headerHolder.positioned = true
+ end
+
+ UF.RaidSmartVisibility(headerHolder)
+end
+
+function UF:Update_RaidFrames(frame, db)
+ if not db then
+ db = frame.db
+ else
+ frame.db = db
+ end
+
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame.colors = ElvUF.colors
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+
+ do
+ if self.thinBorders then
+ frame.SPACING = 0
+ frame.BORDER = E.mult
+ else
+ frame.BORDER = E.Border
+ frame.SPACING = E.Spacing
+ end
+ frame.SHADOW_SPACING = 3
+
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.CLASSBAR_YOFFSET = 0
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ if not InCombatLockdown() then
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ else
+ frame:SetAttribute("initial-width", frame.UNIT_WIDTH)
+ frame:SetAttribute("initial-height", frame.UNIT_HEIGHT)
+ end
+
+ UF:Configure_InfoPanel(frame)
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --RaidDebuffs
+ UF:Configure_RaidDebuffs(frame)
+
+ --Raid Icon
+ UF:Configure_RaidIcon(frame)
+
+ --Resurrect Icon
+ UF:Configure_ResurrectionIcon(frame)
+
+ --Debuff Highlight
+ UF:Configure_DebuffHighlight(frame)
+
+ --OverHealing
+ UF:Configure_HealComm(frame)
+
+ --GPS Arrow
+ UF:Configure_GPS(frame)
+
+ --Raid Roles
+ UF:Configure_RaidRoleIcons(frame)
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --Buff Indicators
+ UF:UpdateAuraWatch(frame)
+
+ --ReadyCheck
+ UF:Configure_ReadyCheckIcon(frame)
+
+ --CustomTexts
+ UF:Configure_CustomTexts(frame)
+
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+UF.headerstoload.raid = true
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Groups/Raid40.lua b/ElvUI/Modules/UnitFrames/Groups/Raid40.lua
new file mode 100644
index 0000000..9cc1b47
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Groups/Raid40.lua
@@ -0,0 +1,247 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetInstanceInfo = GetInstanceInfo
+local InCombatLockdown = InCombatLockdown
+local RegisterStateDriver = RegisterStateDriver
+local UnregisterStateDriver = UnregisterStateDriver
+
+function UF:Construct_Raid40Frames()
+ self:SetScript("OnEnter", UnitFrame_OnEnter)
+ self:SetScript("OnLeave", UnitFrame_OnLeave)
+
+ self.RaisedElementParent = CreateFrame("Frame", nil, self)
+ self.RaisedElementParent.TextureParent = CreateFrame("Frame", nil, self.RaisedElementParent)
+ self.RaisedElementParent:SetFrameLevel(self:GetFrameLevel() + 100)
+
+ self.Health = UF:Construct_HealthBar(self, true, true, "RIGHT")
+
+ self.Power = UF:Construct_PowerBar(self, true, true, "LEFT")
+ self.Power.frequentUpdates = false
+
+ self.Portrait3D = UF:Construct_Portrait(self, "model")
+ self.Portrait2D = UF:Construct_Portrait(self, "texture")
+
+ self.Name = UF:Construct_NameText(self)
+ self.Buffs = UF:Construct_Buffs(self)
+ self.Debuffs = UF:Construct_Debuffs(self)
+ self.AuraWatch = UF:Construct_AuraWatch(self)
+ self.RaidDebuffs = UF:Construct_RaidDebuffs(self)
+ self.DebuffHighlight = UF:Construct_DebuffHighlight(self)
+ self.ResurrectIndicator = UF:Construct_ResurrectionIcon(self)
+ self.RaidRoleFramesAnchor = UF:Construct_RaidRoleFrames(self)
+ self.MouseGlow = UF:Construct_MouseGlow(self)
+ self.TargetGlow = UF:Construct_TargetGlow(self)
+ self.InfoPanel = UF:Construct_InfoPanel(self)
+ self.ThreatIndicator = UF:Construct_Threat(self)
+ self.RaidTargetIndicator = UF:Construct_RaidIcon(self)
+ self.ReadyCheckIndicator = UF:Construct_ReadyCheckIcon(self)
+ self.HealCommBar = UF:Construct_HealComm(self)
+ self.GPS = UF:Construct_GPS(self)
+ self.Fader = UF:Construct_Fader()
+ self.Cutaway = UF:Construct_Cutaway(self)
+ self.customTexts = {}
+
+ self.unitframeType = "raid40"
+
+ UF:Update_StatusBars()
+ UF:Update_FontStrings()
+
+ self.db = UF.db.units.raid40
+ self.PostCreate = UF.Update_Raid40Frames
+
+ return self
+end
+
+function UF:Raid40SmartVisibility(event)
+ if not self.db or (self.db and not self.db.enable) or (UF.db and not UF.db.smartRaidFilter) or self.isForced then
+ self.blockVisibilityChanges = false
+ return
+ end
+
+ if event == "PLAYER_REGEN_ENABLED" then
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED")
+ end
+
+ if not InCombatLockdown() then
+ self.isInstanceForced = nil
+ local _, instanceType, _, _, maxPlayers = GetInstanceInfo()
+ if instanceType == "raid" or instanceType == "pvp" then
+ local mapID = GetCurrentMapAreaID()
+ if UF.instanceMapIDs[mapID] then
+ maxPlayers = UF.instanceMapIDs[mapID]
+ end
+
+ UnregisterStateDriver(self, "visibility")
+
+ if maxPlayers == 40 then
+ self.isInstanceForced = true
+ self.blockVisibilityChanges = false
+ self:Show()
+
+ if ElvUF_Raid40.numGroups ~= E:Round(maxPlayers/5) and event then
+ UF:CreateAndUpdateHeaderGroup("raid40")
+ end
+ else
+ self.blockVisibilityChanges = true
+ self:Hide()
+ end
+ elseif self.db.visibility then
+ RegisterStateDriver(self, "visibility", self.db.visibility)
+ self.blockVisibilityChanges = false
+
+ if ElvUF_Raid40.numGroups ~= self.db.numGroups then
+ UF:CreateAndUpdateHeaderGroup("raid40")
+ end
+ end
+ else
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ return
+ end
+end
+
+function UF:Update_Raid40Header(header, db)
+ header:GetParent().db = db
+
+ local headerHolder = header:GetParent()
+ headerHolder.db = db
+
+ if not headerHolder.positioned then
+ headerHolder:ClearAllPoints()
+ headerHolder:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", 4, 195)
+
+ E:CreateMover(headerHolder, headerHolder:GetName().."Mover", L["Raid-40 Frames"], nil, nil, nil, "ALL,RAID", nil, "unitframe,raid40,generalGroup")
+
+ headerHolder:RegisterEvent("PLAYER_LOGIN")
+ headerHolder:RegisterEvent("ZONE_CHANGED_NEW_AREA")
+ headerHolder:SetScript("OnEvent", UF.Raid40SmartVisibility)
+ headerHolder.positioned = true
+ end
+
+ UF.Raid40SmartVisibility(headerHolder)
+end
+
+function UF:Update_Raid40Frames(frame, db)
+ if not db then
+ db = frame.db
+ else
+ frame.db = db
+ end
+
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame.colors = ElvUF.colors
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+
+ do
+ if self.thinBorders then
+ frame.SPACING = 0
+ frame.BORDER = E.mult
+ else
+ frame.BORDER = E.Border
+ frame.SPACING = E.Spacing
+ end
+ frame.SHADOW_SPACING = 3
+
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.CLASSBAR_YOFFSET = 0
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ if not InCombatLockdown() then
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ else
+ frame:SetAttribute("initial-width", frame.UNIT_WIDTH)
+ frame:SetAttribute("initial-height", frame.UNIT_HEIGHT)
+ end
+
+ UF:Configure_InfoPanel(frame)
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --RaidDebuffs
+ UF:Configure_RaidDebuffs(frame)
+
+ --Raid Icon
+ UF:Configure_RaidIcon(frame)
+
+ --Debuff Highlight
+ UF:Configure_DebuffHighlight(frame)
+
+ --Resurrect Highlight
+ UF:Configure_ResurrectionIcon(frame)
+
+ --OverHealing
+ UF:Configure_HealComm(frame)
+
+ --GPS Arrow
+ UF:Configure_GPS(frame)
+
+ --Raid Roles
+ UF:Configure_RaidRoleIcons(frame)
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --Buff Indicators
+ UF:UpdateAuraWatch(frame)
+
+ --ReadyCheck
+ UF:Configure_ReadyCheckIcon(frame)
+
+ --CustomTexts
+ UF:Configure_CustomTexts(frame)
+
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+UF.headerstoload.raid40 = true
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Groups/RaidPets.lua b/ElvUI/Modules/UnitFrames/Groups/RaidPets.lua
new file mode 100644
index 0000000..e12122f
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Groups/RaidPets.lua
@@ -0,0 +1,189 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local GetInstanceInfo = GetInstanceInfo
+local InCombatLockdown = InCombatLockdown
+local RegisterStateDriver = RegisterStateDriver
+local UnregisterStateDriver = UnregisterStateDriver
+
+function UF:Construct_RaidpetFrames()
+ self:SetScript("OnEnter", UnitFrame_OnEnter)
+ self:SetScript("OnLeave", UnitFrame_OnLeave)
+
+ self.RaisedElementParent = CreateFrame("Frame", nil, self)
+ self.RaisedElementParent.TextureParent = CreateFrame("Frame", nil, self.RaisedElementParent)
+ self.RaisedElementParent:SetFrameLevel(self:GetFrameLevel() + 100)
+
+ self.Health = UF:Construct_HealthBar(self, true, true, "RIGHT")
+ self.Name = UF:Construct_NameText(self)
+ self.Portrait3D = UF:Construct_Portrait(self, "model")
+ self.Portrait2D = UF:Construct_Portrait(self, "texture")
+ self.Buffs = UF:Construct_Buffs(self)
+ self.Debuffs = UF:Construct_Debuffs(self)
+ self.AuraWatch = UF:Construct_AuraWatch(self)
+ self.RaidDebuffs = UF:Construct_RaidDebuffs(self)
+ self.DebuffHighlight = UF:Construct_DebuffHighlight(self)
+ self.TargetGlow = UF:Construct_TargetGlow(self)
+ self.MouseGlow = UF:Construct_MouseGlow(self)
+ self.ThreatIndicator = UF:Construct_Threat(self)
+ self.RaidTargetIndicator = UF:Construct_RaidIcon(self)
+ self.HealCommBar = UF:Construct_HealComm(self)
+ self.Fader = UF:Construct_Fader()
+ self.Cutaway = UF:Construct_Cutaway(self)
+ self.customTexts = {}
+
+ self.unitframeType = "raidpet"
+
+ UF:Update_StatusBars()
+ UF:Update_FontStrings()
+
+ self.db = UF.db.units.raidpet
+ self.PostCreate = UF.Update_RaidpetFrames
+
+ return self
+end
+
+--I don"t know if this function is needed or not? But the error I pm'ed you about was because of the missing OnEvent so I just added it.
+function UF:RaidPetsSmartVisibility(event)
+ if not self.db or (self.db and not self.db.enable) or (UF.db and not UF.db.smartRaidFilter) or self.isForced then return end
+ if event == "PLAYER_REGEN_ENABLED" then self:UnregisterEvent("PLAYER_REGEN_ENABLED") end
+
+ if not InCombatLockdown() then
+ local _, instanceType = GetInstanceInfo()
+ if instanceType == "raid" then
+ UnregisterStateDriver(self, "visibility")
+ self:Show()
+ elseif self.db.visibility then
+ RegisterStateDriver(self, "visibility", self.db.visibility)
+ end
+ else
+ self:RegisterEvent("PLAYER_REGEN_ENABLED")
+ return
+ end
+end
+
+function UF:Update_RaidpetHeader(header, db)
+ header.db = db
+
+ local headerHolder = header:GetParent()
+ headerHolder.db = db
+
+ if not headerHolder.positioned then
+ headerHolder:ClearAllPoints()
+ headerHolder:Point("BOTTOMLEFT", E.UIParent, "BOTTOMLEFT", 4, 574)
+
+ E:CreateMover(headerHolder, headerHolder:GetName().."Mover", L["Raid Pet Frames"], nil, nil, nil, "ALL,RAID10,RAID25,RAID40", nil, "unitframe,raidpet,generalGroup")
+ headerHolder.positioned = true
+
+ headerHolder:RegisterEvent("PLAYER_LOGIN")
+ headerHolder:RegisterEvent("ZONE_CHANGED_NEW_AREA")
+ headerHolder:SetScript("OnEvent", UF.RaidPetsSmartVisibility)
+ end
+
+ UF.RaidPetsSmartVisibility(headerHolder)
+end
+
+function UF:Update_RaidpetFrames(frame, db)
+ if not db then
+ db = frame.db
+ else
+ frame.db = db
+ end
+
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame.colors = ElvUF.colors
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+
+ do
+ if self.thinBorders then
+ frame.SPACING = 0
+ frame.BORDER = E.mult
+ else
+ frame.BORDER = E.Border
+ frame.SPACING = E.Spacing
+ end
+ frame.SHADOW_SPACING = 3
+
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.height
+
+ frame.USE_POWERBAR = false
+ frame.POWERBAR_DETACHED = false
+ frame.USE_INSET_POWERBAR = false
+ frame.USE_MINI_POWERBAR = false
+ frame.USE_POWERBAR_OFFSET = false
+ frame.POWERBAR_OFFSET = 0
+ frame.POWERBAR_HEIGHT = 0
+ frame.POWERBAR_WIDTH = 0
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.CLASSBAR_YOFFSET = 0
+ frame.BOTTOM_OFFSET = 0
+
+ frame.VARIABLES_SET = true
+ end
+
+ if not InCombatLockdown() then
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ else
+ frame:SetAttribute("initial-width", frame.UNIT_WIDTH)
+ frame:SetAttribute("initial-height", frame.UNIT_HEIGHT)
+ end
+
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --RaidDebuffs
+ UF:Configure_RaidDebuffs(frame)
+
+ --Raid Icon
+ UF:Configure_RaidIcon(frame)
+
+ --Debuff Highlight
+ UF:Configure_DebuffHighlight(frame)
+
+ --OverHealing
+ UF:Configure_HealComm(frame)
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --BuffIndicator
+ UF:UpdateAuraWatch(frame, true) --2nd argument is the petOverride
+
+ --CustomTexts
+ UF:Configure_CustomTexts(frame)
+
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+--Added an additional argument at the end, specifying the header Template we want to use
+UF.headerstoload.raidpet = {nil, nil, "SecureGroupPetHeaderTemplate"}
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Groups/Tank.lua b/ElvUI/Modules/UnitFrames/Groups/Tank.lua
new file mode 100644
index 0000000..299833e
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Groups/Tank.lua
@@ -0,0 +1,189 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local max = math.max
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local InCombatLockdown = InCombatLockdown
+local RegisterStateDriver = RegisterStateDriver
+
+function UF:Construct_TankFrames()
+ self:SetScript("OnEnter", UnitFrame_OnEnter)
+ self:SetScript("OnLeave", UnitFrame_OnLeave)
+
+ self.RaisedElementParent = CreateFrame("Frame", nil, self)
+ self.RaisedElementParent.TextureParent = CreateFrame("Frame", nil, self.RaisedElementParent)
+ self.RaisedElementParent:SetFrameLevel(self:GetFrameLevel() + 100)
+
+ self.Health = UF:Construct_HealthBar(self, true)
+ self.Name = UF:Construct_NameText(self)
+ self.ThreatIndicator = UF:Construct_Threat(self)
+ self.RaidTargetIndicator = UF:Construct_RaidIcon(self)
+ self.MouseGlow = UF:Construct_MouseGlow(self)
+ self.TargetGlow = UF:Construct_TargetGlow(self)
+ self.Fader = UF:Construct_Fader()
+ self.Cutaway = UF:Construct_Cutaway(self)
+
+ if not self.isChild then
+ self.Buffs = UF:Construct_Buffs(self)
+ self.Debuffs = UF:Construct_Debuffs(self)
+ self.AuraWatch = UF:Construct_AuraWatch(self)
+ self.RaidDebuffs = UF:Construct_RaidDebuffs(self)
+ self.DebuffHighlight = UF:Construct_DebuffHighlight(self)
+
+ self.unitframeType = "tank"
+ else
+ self.unitframeType = "tanktarget"
+ end
+
+ UF:Update_StatusBars()
+ UF:Update_FontStrings()
+
+ self.originalParent = self:GetParent()
+
+ self.db = UF.db.units.tank
+ self.PostCreate = UF.Update_TankFrames
+
+ return self
+end
+
+function UF:Update_TankHeader(header, db)
+ header:Hide()
+ header.db = db
+
+ RegisterStateDriver(header, "visibility", "show")
+ RegisterStateDriver(header, "visibility", "[@raid1,exists] show;hide")
+
+ local width, height = header:GetSize()
+ header.dirtyWidth, header.dirtyHeight = width, max(height, db.height)
+
+ if not header.positioned then
+ header:ClearAllPoints()
+ header:Point("TOPLEFT", E.UIParent, "TOPLEFT", 4, -186)
+ E:CreateMover(header, header:GetName().."Mover", L["MT Frames"], nil, nil, nil, "ALL,RAID", nil, "unitframe,tank,generalGroup")
+ header.mover.positionOverride = "TOPLEFT"
+ header:SetAttribute("minHeight", header.dirtyHeight)
+ header:SetAttribute("minWidth", header.dirtyWidth)
+ header.positioned = true
+ end
+end
+
+function UF:Update_TankFrames(frame, db)
+ if not db then
+ db = frame.db
+ else
+ frame.db = db
+ end
+
+ frame.colors = ElvUF.colors
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ if self.thinBorders then
+ frame.SPACING = 0
+ frame.BORDER = E.mult
+ else
+ frame.BORDER = E.Border
+ frame.SPACING = E.Spacing
+ end
+ frame.SHADOW_SPACING = 3
+
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.height
+
+ frame.USE_POWERBAR = false
+ frame.POWERBAR_DETACHED = false
+ frame.USE_INSET_POWERBAR = false
+ frame.USE_MINI_POWERBAR = false
+ frame.USE_POWERBAR_OFFSET = false
+ frame.POWERBAR_OFFSET = 0
+ frame.POWERBAR_HEIGHT = 0
+ frame.POWERBAR_WIDTH = 0
+
+ frame.USE_PORTRAIT = false
+ frame.USE_PORTRAIT_OVERLAY = false
+ frame.PORTRAIT_WIDTH = 0
+
+ frame.CLASSBAR_YOFFSET = 0
+ frame.BOTTOM_OFFSET = 0
+
+ frame.VARIABLES_SET = true
+ end
+
+ if frame.isChild and frame.originalParent then
+ local childDB = db.targetsGroup
+ frame.db = db.targetsGroup
+ if not frame.originalParent.childList then
+ frame.originalParent.childList = {}
+ end
+ frame.originalParent.childList[frame] = true
+
+ if not InCombatLockdown() then
+ if childDB.enable then
+ frame:SetParent(frame.originalParent)
+ RegisterUnitWatch(frame)
+ frame:Size(childDB.width, childDB.height)
+ frame:ClearAllPoints()
+ frame:Point(E.InversePoints[childDB.anchorPoint], frame.originalParent, childDB.anchorPoint, childDB.xOffset, childDB.yOffset)
+ else
+ UnregisterUnitWatch(frame)
+ frame:SetParent(E.HiddenFrame)
+ end
+ else
+ if childDB.enable then
+ frame:SetAttribute("initial-anchor", format("%s,%s,%d,%d", E.InversePoints[childDB.anchorPoint], childDB.anchorPoint, childDB.xOffset, childDB.yOffset))
+ frame:SetAttribute("initial-width", frame.UNIT_WIDTH)
+ frame:SetAttribute("initial-height", frame.UNIT_HEIGHT)
+ end
+ end
+ else
+ if not InCombatLockdown() then
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ else
+ frame:SetAttribute("initial-width", frame.UNIT_WIDTH)
+ frame:SetAttribute("initial-height", frame.UNIT_HEIGHT)
+ end
+ end
+
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ UF:Configure_RaidIcon(frame)
+
+ if not frame.isChild then
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --RaidDebuffs
+ UF:Configure_RaidDebuffs(frame)
+
+ --Debuff Highlight
+ UF:Configure_DebuffHighlight(frame)
+
+ --Buff Indicator
+ UF:UpdateAuraWatch(frame)
+ end
+
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+UF.headerstoload.tank = {"MAINTANK", "ELVUI_UNITTARGET"}
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Load_UnitFrames.xml b/ElvUI/Modules/UnitFrames/Load_UnitFrames.xml
new file mode 100644
index 0000000..5e060b4
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Load_UnitFrames.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/UnitFrames.lua b/ElvUI/Modules/UnitFrames/UnitFrames.lua
new file mode 100644
index 0000000..75356b1
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/UnitFrames.lua
@@ -0,0 +1,1419 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local LSM = E.Libs.LSM
+UF.LSM = E.Libs.LSM
+
+--Lua functions
+local _G = _G
+local select, pairs, type, unpack, assert, tostring = select, pairs, type, unpack, assert, tostring
+local tremove, tinsert = table.remove, table.insert
+local find, gsub, format = string.find, string.gsub, string.format
+--WoW API / Variables
+local hooksecurefunc = hooksecurefunc
+local CreateFrame = CreateFrame
+local IsAddOnLoaded = IsAddOnLoaded
+local UnitFrame_OnEnter = UnitFrame_OnEnter
+local UnitFrame_OnLeave = UnitFrame_OnLeave
+local IsInInstance = IsInInstance
+local InCombatLockdown = InCombatLockdown
+local GetInstanceInfo = GetInstanceInfo
+local UnregisterStateDriver = UnregisterStateDriver
+local RegisterStateDriver = RegisterStateDriver
+local MAX_BOSS_FRAMES = MAX_BOSS_FRAMES
+
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+UF.headerstoload = {}
+UF.unitgroupstoload = {}
+UF.unitstoload = {}
+
+UF.groupPrototype = {}
+UF.headerPrototype = {}
+UF.headers = {}
+UF.groupunits = {}
+UF.units = {}
+
+UF.statusbars = {}
+UF.fontstrings = {}
+UF.badHeaderPoints = {
+ ["TOP"] = "BOTTOM",
+ ["LEFT"] = "RIGHT",
+ ["BOTTOM"] = "TOP",
+ ["RIGHT"] = "LEFT"
+}
+
+UF.headerFunctions = {}
+UF.classMaxResourceBar = {
+ ["DRUID"] = 1,
+ ["HERO"] = 1
+}
+
+UF.instanceMapIDs = {
+ [444] = 10,
+ [541] = 40,
+ [513] = 15,
+ [402] = 40,
+ [462] = 15,
+ [483] = 15,
+}
+
+UF.headerGroupBy = {
+ ["CLASS"] = function(header)
+ header:SetAttribute("groupingOrder", "HERO,DEATHKNIGHT,DRUID,HUNTER,MAGE,PALADIN,PRIEST,ROGUE,SHAMAN,WARLOCK,WARRIOR")
+ header:SetAttribute("sortMethod", "NAME")
+ header:SetAttribute("groupBy", "CLASS")
+ end,
+ ["MTMA"] = function(header)
+ header:SetAttribute("groupingOrder", "MAINTANK,MAINASSIST,NONE")
+ header:SetAttribute("sortMethod", "NAME")
+ header:SetAttribute("groupBy", "ROLE")
+ end,
+ ["NAME"] = function(header)
+ header:SetAttribute("groupingOrder", "1,2,3,4,5,6,7,8")
+ header:SetAttribute("sortMethod", "NAME")
+ header:SetAttribute("groupBy", nil)
+ end,
+ ["GROUP"] = function(header)
+ header:SetAttribute("groupingOrder", "1,2,3,4,5,6,7,8")
+ header:SetAttribute("sortMethod", "INDEX")
+ header:SetAttribute("groupBy", "GROUP")
+ end,
+ ["PETNAME"] = function(header)
+ header:SetAttribute("groupingOrder", "1,2,3,4,5,6,7,8")
+ header:SetAttribute("sortMethod", "NAME")
+ header:SetAttribute("groupBy", nil)
+ header:SetAttribute("filterOnPet", true) --This is the line that matters. Without this, it sorts based on the owners name
+ end,
+}
+
+local POINT_COLUMN_ANCHOR_TO_DIRECTION = {
+ ["TOPTOP"] = "UP_RIGHT",
+ ["BOTTOMBOTTOM"] = "TOP_RIGHT",
+ ["LEFTLEFT"] = "RIGHT_UP",
+ ["RIGHTRIGHT"] = "LEFT_UP",
+ ["RIGHTTOP"] = "LEFT_DOWN",
+ ["LEFTTOP"] = "RIGHT_DOWN",
+ ["LEFTBOTTOM"] = "RIGHT_UP",
+ ["RIGHTBOTTOM"] = "LEFT_UP",
+ ["BOTTOMRIGHT"] = "UP_LEFT",
+ ["BOTTOMLEFT"] = "UP_RIGHT",
+ ["TOPRIGHT"] = "DOWN_LEFT",
+ ["TOPLEFT"] = "DOWN_RIGHT"
+}
+
+local DIRECTION_TO_POINT = {
+ DOWN_RIGHT = "TOP",
+ DOWN_LEFT = "TOP",
+ UP_RIGHT = "BOTTOM",
+ UP_LEFT = "BOTTOM",
+ RIGHT_DOWN = "LEFT",
+ RIGHT_UP = "LEFT",
+ LEFT_DOWN = "RIGHT",
+ LEFT_UP = "RIGHT",
+ UP = "BOTTOM",
+ DOWN = "TOP"
+}
+
+local DIRECTION_TO_GROUP_ANCHOR_POINT = {
+ DOWN_RIGHT = "TOPLEFT",
+ DOWN_LEFT = "TOPRIGHT",
+ UP_RIGHT = "BOTTOMLEFT",
+ UP_LEFT = "BOTTOMRIGHT",
+ RIGHT_DOWN = "TOPLEFT",
+ RIGHT_UP = "BOTTOMLEFT",
+ LEFT_DOWN = "TOPRIGHT",
+ LEFT_UP = "BOTTOMRIGHT",
+ OUT_RIGHT_UP = "BOTTOM",
+ OUT_LEFT_UP = "BOTTOM",
+ OUT_RIGHT_DOWN = "TOP",
+ OUT_LEFT_DOWN = "TOP",
+ OUT_UP_RIGHT = "LEFT",
+ OUT_UP_LEFT = "RIGHT",
+ OUT_DOWN_RIGHT = "LEFT",
+ OUT_DOWN_LEFT = "RIGHT"
+}
+
+local INVERTED_DIRECTION_TO_COLUMN_ANCHOR_POINT = {
+ DOWN_RIGHT = "RIGHT",
+ DOWN_LEFT = "LEFT",
+ UP_RIGHT = "RIGHT",
+ UP_LEFT = "LEFT",
+ RIGHT_DOWN = "BOTTOM",
+ RIGHT_UP = "TOP",
+ LEFT_DOWN = "BOTTOM",
+ LEFT_UP = "TOP",
+ UP = "TOP",
+ DOWN = "BOTTOM"
+}
+
+local DIRECTION_TO_COLUMN_ANCHOR_POINT = {
+ DOWN_RIGHT = "LEFT",
+ DOWN_LEFT = "RIGHT",
+ UP_RIGHT = "LEFT",
+ UP_LEFT = "RIGHT",
+ RIGHT_DOWN = "TOP",
+ RIGHT_UP = "BOTTOM",
+ LEFT_DOWN = "TOP",
+ LEFT_UP = "BOTTOM"
+}
+
+local DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER = {
+ DOWN_RIGHT = 1,
+ DOWN_LEFT = -1,
+ UP_RIGHT = 1,
+ UP_LEFT = -1,
+ RIGHT_DOWN = 1,
+ RIGHT_UP = 1,
+ LEFT_DOWN = -1,
+ LEFT_UP = -1
+}
+
+local DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER = {
+ DOWN_RIGHT = -1,
+ DOWN_LEFT = -1,
+ UP_RIGHT = 1,
+ UP_LEFT = 1,
+ RIGHT_DOWN = -1,
+ RIGHT_UP = 1,
+ LEFT_DOWN = -1,
+ LEFT_UP = 1
+}
+
+function UF:ConvertGroupDB(group)
+ local db = self.db.units[group.groupName]
+ if db.point and db.columnAnchorPoint then
+ db.growthDirection = POINT_COLUMN_ANCHOR_TO_DIRECTION[db.point..db.columnAnchorPoint]
+ db.point = nil
+ db.columnAnchorPoint = nil
+ end
+
+ if db.growthDirection == "UP" then
+ db.growthDirection = "UP_RIGHT"
+ end
+
+ if db.growthDirection == "DOWN" then
+ db.growthDirection = "DOWN_RIGHT"
+ end
+end
+
+function UF:Construct_UF(frame, unit)
+ frame:SetScript("OnEnter", UnitFrame_OnEnter)
+ frame:SetScript("OnLeave", UnitFrame_OnLeave)
+
+ if self.thinBorders then
+ frame.SPACING = 0
+ frame.BORDER = E.mult
+ else
+ frame.BORDER = E.Border
+ frame.SPACING = E.Spacing
+ end
+
+ frame.SHADOW_SPACING = 3
+ frame.CLASSBAR_YOFFSET = 0 --placeholder
+ frame.BOTTOM_OFFSET = 0 --placeholder
+
+ frame.RaisedElementParent = CreateFrame("Frame", nil, frame)
+ frame.RaisedElementParent.TextureParent = CreateFrame("Frame", nil, frame.RaisedElementParent)
+ frame.RaisedElementParent:SetFrameLevel(frame:GetFrameLevel() + 125)
+
+ if not self.groupunits[unit] then
+ local stringTitle = E:StringTitle(unit)
+ if find(stringTitle, "target") then
+ stringTitle = gsub(stringTitle, "target", "Target")
+ end
+ self["Construct_"..stringTitle.."Frame"](self, frame, unit)
+ else
+ UF["Construct_"..E:StringTitle(self.groupunits[unit]).."Frames"](self, frame, unit)
+ end
+
+ self:Update_StatusBars()
+ self:Update_FontStrings()
+
+ return frame
+end
+
+function UF:GetObjectAnchorPoint(frame, point)
+ if not frame[point] or point == "Frame" then
+ return frame
+ elseif frame[point] and not frame[point]:IsShown() then
+ return frame.Health
+ else
+ return frame[point]
+ end
+end
+
+function UF:GetPositionOffset(position, offset)
+ if not offset then offset = 2 end
+ local x, y = 0, 0
+ if find(position, "LEFT") then
+ x = offset
+ elseif find(position, "RIGHT") then
+ x = -offset
+ end
+
+ if find(position, "TOP") then
+ y = -offset
+ elseif find(position, "BOTTOM") then
+ y = offset
+ end
+
+ return x, y
+end
+
+function UF:GetAuraOffset(p1, p2)
+ local x, y = 0, 0
+ if p1 == "RIGHT" and p2 == "LEFT" then
+ x = -3
+ elseif p1 == "LEFT" and p2 == "RIGHT" then
+ x = 3
+ end
+
+ if find(p1, "TOP") and find(p2, "BOTTOM") then
+ y = -1
+ elseif find(p1, "BOTTOM") and find(p2, "TOP") then
+ y = 1
+ end
+
+ return E:Scale(x), E:Scale(y)
+end
+
+function UF:GetAuraAnchorFrame(frame, attachTo, isConflict)
+ if isConflict then
+ E:Print(format(L["%s frame(s) has a conflicting anchor point, please change either the buff or debuff anchor point so they are not attached to each other. Forcing the debuffs to be attached to the main unitframe until fixed."], E:StringTitle(frame:GetName())))
+ end
+
+ if isConflict or attachTo == "FRAME" then
+ return frame
+ elseif attachTo == "TRINKET" then
+ if select(2, IsInInstance()) == "arena" then
+ return frame.Trinket
+ end
+ elseif attachTo == "BUFFS" then
+ return frame.Buffs
+ elseif attachTo == "DEBUFFS" then
+ return frame.Debuffs
+ elseif attachTo == "HEALTH" then
+ return frame.Health
+ elseif attachTo == "POWER" and frame.Power then
+ return frame.Power
+ elseif attachTo == "ENERGY" and frame.Energy then
+ return frame.Energy
+ elseif attachTo == "RAGE" and frame.Rage then
+ return frame.Rage
+ else
+ return frame
+ end
+end
+
+function UF:ClearChildPoints(...)
+ for i = 1, select("#", ...) do
+ local child = select(i, ...)
+ child:ClearAllPoints()
+ end
+end
+
+function UF:UpdateColors()
+ local db = self.db.colors
+
+ ElvUF.colors.tapped = E:SetColorTable(ElvUF.colors.tapped, db.tapped)
+ ElvUF.colors.disconnected = E:SetColorTable(ElvUF.colors.disconnected, db.disconnected)
+ ElvUF.colors.health = E:SetColorTable(ElvUF.colors.health, db.health)
+ ElvUF.colors.power.MANA = E:SetColorTable(ElvUF.colors.power.MANA, db.power.MANA)
+ ElvUF.colors.power.RAGE = E:SetColorTable(ElvUF.colors.power.RAGE, db.power.RAGE)
+ ElvUF.colors.power.FOCUS = E:SetColorTable(ElvUF.colors.power.FOCUS, db.power.FOCUS)
+ ElvUF.colors.power.ENERGY = E:SetColorTable(ElvUF.colors.power.ENERGY, db.power.ENERGY)
+ ElvUF.colors.power.RUNIC_POWER = E:SetColorTable(ElvUF.colors.power.RUNIC_POWER, db.power.RUNIC_POWER)
+
+ ElvUF.colors.threat[0] = E:SetColorTable(ElvUF.colors.threat[0], db.threat[0])
+ ElvUF.colors.threat[1] = E:SetColorTable(ElvUF.colors.threat[1], db.threat[1])
+ ElvUF.colors.threat[2] = E:SetColorTable(ElvUF.colors.threat[2], db.threat[2])
+ ElvUF.colors.threat[3] = E:SetColorTable(ElvUF.colors.threat[3], db.threat[3])
+
+ if not ElvUF.colors.ComboPoints then ElvUF.colors.ComboPoints = {} end
+ ElvUF.colors.ComboPoints[1] = E:SetColorTable(ElvUF.colors.ComboPoints[1], db.classResources.comboPoints[1])
+ ElvUF.colors.ComboPoints[2] = E:SetColorTable(ElvUF.colors.ComboPoints[2], db.classResources.comboPoints[2])
+ ElvUF.colors.ComboPoints[3] = E:SetColorTable(ElvUF.colors.ComboPoints[3], db.classResources.comboPoints[3])
+ ElvUF.colors.ComboPoints[4] = E:SetColorTable(ElvUF.colors.ComboPoints[4], db.classResources.comboPoints[4])
+ ElvUF.colors.ComboPoints[5] = E:SetColorTable(ElvUF.colors.ComboPoints[5], db.classResources.comboPoints[5])
+
+ -- Death Knight
+ if not ElvUF.colors.runes then ElvUF.colors.runes = {} end
+ if not ElvUF.colors.ClassBars then ElvUF.colors.ClassBars = {} end
+ if not ElvUF.colors.ClassBars.DEATHKNIGHT then ElvUF.colors.ClassBars.DEATHKNIGHT = {} end
+ ElvUF.colors.runes[1] = E:SetColorTable(ElvUF.colors.ClassBars.DEATHKNIGHT[1], db.classResources.DEATHKNIGHT[1])
+ ElvUF.colors.runes[2] = E:SetColorTable(ElvUF.colors.ClassBars.DEATHKNIGHT[2], db.classResources.DEATHKNIGHT[2])
+ ElvUF.colors.runes[3] = E:SetColorTable(ElvUF.colors.ClassBars.DEATHKNIGHT[3], db.classResources.DEATHKNIGHT[3])
+ ElvUF.colors.runes[4] = E:SetColorTable(ElvUF.colors.ClassBars.DEATHKNIGHT[4], db.classResources.DEATHKNIGHT[4])
+
+ -- these are just holders.. to maintain and update tables
+ if not ElvUF.colors.reaction.good then ElvUF.colors.reaction.good = {} end
+ if not ElvUF.colors.reaction.bad then ElvUF.colors.reaction.bad = {} end
+ if not ElvUF.colors.reaction.neutral then ElvUF.colors.reaction.neutral = {} end
+ ElvUF.colors.reaction.good = E:SetColorTable(ElvUF.colors.reaction.good, db.reaction.GOOD)
+ ElvUF.colors.reaction.bad = E:SetColorTable(ElvUF.colors.reaction.bad, db.reaction.BAD)
+ ElvUF.colors.reaction.neutral = E:SetColorTable(ElvUF.colors.reaction.neutral, db.reaction.NEUTRAL)
+
+ if not ElvUF.colors.smoothHealth then ElvUF.colors.smoothHealth = {} end
+ ElvUF.colors.smoothHealth = E:SetColorTable(ElvUF.colors.smoothHealth, db.health)
+
+ if not ElvUF.colors.smooth then ElvUF.colors.smooth = {1, 0, 0, 1, 1, 0} end
+
+ ElvUF.colors.reaction[1] = ElvUF.colors.reaction.bad
+ ElvUF.colors.reaction[2] = ElvUF.colors.reaction.bad
+ ElvUF.colors.reaction[3] = ElvUF.colors.reaction.bad
+ ElvUF.colors.reaction[4] = ElvUF.colors.reaction.neutral
+ ElvUF.colors.reaction[5] = ElvUF.colors.reaction.good
+ ElvUF.colors.reaction[6] = ElvUF.colors.reaction.good
+ ElvUF.colors.reaction[7] = ElvUF.colors.reaction.good
+ ElvUF.colors.reaction[8] = ElvUF.colors.reaction.good
+ ElvUF.colors.smooth[7] = ElvUF.colors.smoothHealth[1]
+ ElvUF.colors.smooth[8] = ElvUF.colors.smoothHealth[2]
+ ElvUF.colors.smooth[9] = ElvUF.colors.smoothHealth[3]
+
+ ElvUF.colors.castColor = E:SetColorTable(ElvUF.colors.castColor, db.castColor)
+ ElvUF.colors.castNoInterrupt = E:SetColorTable(ElvUF.colors.castNoInterrupt, db.castNoInterrupt)
+
+ if not ElvUF.colors.DebuffHighlight then ElvUF.colors.DebuffHighlight = {} end
+ ElvUF.colors.DebuffHighlight.Magic = E:SetColorTable(ElvUF.colors.DebuffHighlight.Magic, db.debuffHighlight.Magic)
+ ElvUF.colors.DebuffHighlight.Curse = E:SetColorTable(ElvUF.colors.DebuffHighlight.Curse, db.debuffHighlight.Curse)
+ ElvUF.colors.DebuffHighlight.Disease = E:SetColorTable(ElvUF.colors.DebuffHighlight.Disease, db.debuffHighlight.Disease)
+ ElvUF.colors.DebuffHighlight.Poison = E:SetColorTable(ElvUF.colors.DebuffHighlight.Poison, db.debuffHighlight.Poison)
+end
+
+function UF:Update_StatusBars()
+ local statusBarTexture = LSM:Fetch("statusbar", self.db.statusbar)
+ for statusbar in pairs(UF.statusbars) do
+ if statusbar then
+ local useBlank = statusbar.isTransparent
+ if statusbar.parent then useBlank = statusbar.parent.isTransparent end
+ if statusbar:IsObjectType("StatusBar") then
+ if not useBlank then
+ statusbar:SetStatusBarTexture(statusBarTexture)
+ if statusbar.texture then statusbar.texture = statusBarTexture end --Update .texture on oUF Power element
+ end
+ elseif statusbar:IsObjectType("Texture") then
+ statusbar:SetTexture(statusBarTexture)
+ end
+
+ UF:Update_StatusBar(statusbar.bg or statusbar.BG, (not useBlank and statusBarTexture) or E.media.blankTex)
+ end
+ end
+end
+
+function UF:Update_StatusBar(statusbar, texture)
+ if not statusbar then return end
+ if not texture then texture = LSM:Fetch("statusbar", self.db.statusbar) end
+
+ if statusbar:IsObjectType("StatusBar") then
+ statusbar:SetStatusBarTexture(texture)
+ elseif statusbar:IsObjectType("Texture") then
+ statusbar:SetTexture(texture)
+ end
+end
+
+function UF:Update_FontString(object)
+ object:FontTemplate(LSM:Fetch("font", self.db.font), self.db.fontSize, self.db.fontOutline)
+end
+
+function UF:Update_FontStrings()
+ local stringFont = LSM:Fetch("font", self.db.font)
+ for font in pairs(UF.fontstrings) do
+ font:FontTemplate(stringFont, self.db.fontSize, self.db.fontOutline)
+ end
+end
+
+function UF:Construct_Fader()
+ return {UpdateRange = UF.UpdateRange}
+end
+
+function UF:Configure_Fader(frame)
+ if frame.db and frame.db.enable and (frame.db.fader and frame.db.fader.enable) then
+ if not frame:IsElementEnabled("Fader") then
+ frame:EnableElement("Fader")
+ end
+
+ frame.Fader:SetOption("Hover", frame.db.fader.hover)
+ frame.Fader:SetOption("Combat", frame.db.fader.combat)
+ frame.Fader:SetOption("PlayerTarget", frame.db.fader.playertarget)
+ frame.Fader:SetOption("Focus", frame.db.fader.focus)
+ frame.Fader:SetOption("Health", frame.db.fader.health)
+ frame.Fader:SetOption("Power", frame.db.fader.power)
+ frame.Fader:SetOption("Vehicle", frame.db.fader.vehicle)
+ frame.Fader:SetOption("Casting", frame.db.fader.casting)
+ frame.Fader:SetOption("MinAlpha", frame.db.fader.minAlpha)
+ frame.Fader:SetOption("MaxAlpha", frame.db.fader.maxAlpha)
+
+ if frame ~= ElvUF_Player then
+ frame.Fader:SetOption("Range", frame.db.fader.range)
+ frame.Fader:SetOption("UnitTarget", frame.db.fader.unittarget)
+ end
+
+ frame.Fader:SetOption("Smooth", (frame.db.fader.smooth > 0 and frame.db.fader.smooth) or nil)
+ frame.Fader:SetOption("Delay", (frame.db.fader.delay > 0 and frame.db.fader.delay) or nil)
+
+ frame.Fader:ClearTimers()
+ frame.Fader.configTimer = E:ScheduleTimer(frame.Fader.ForceUpdate, 0.25, frame.Fader, true)
+ elseif frame:IsElementEnabled("Fader") then
+ frame:DisableElement("Fader")
+ E:UIFrameFadeIn(frame, 1, frame:GetAlpha(), 1)
+ end
+end
+
+function UF:Configure_FontString(obj)
+ UF.fontstrings[obj] = true
+ obj:FontTemplate() --This is temporary.
+end
+
+function UF:Update_AllFrames()
+ if InCombatLockdown() then self:RegisterEvent("PLAYER_REGEN_ENABLED") return end
+ if E.private.unitframe.enable ~= true then return end
+
+ self:UpdateColors()
+ self:Update_FontStrings()
+ self:Update_StatusBars()
+
+ for unit in pairs(self.units) do
+ if self.db.units[unit].enable then
+ self[unit]:Update()
+ self[unit]:Enable()
+ E:EnableMover(self[unit].mover:GetName())
+ else
+ self[unit]:Update()
+ self[unit]:Disable()
+ E:DisableMover(self[unit].mover:GetName())
+ end
+ end
+
+ for unit, group in pairs(self.groupunits) do
+ if self.db.units[group].enable then
+ self[unit]:Enable()
+ self[unit]:Update()
+ E:EnableMover(self[unit].mover:GetName())
+ else
+ self[unit]:Disable()
+ E:DisableMover(self[unit].mover:GetName())
+ end
+ end
+
+ UF:UpdateAllHeaders()
+end
+
+function UF:CreateAndUpdateUFGroup(group, numGroup)
+ if InCombatLockdown() then self:RegisterEvent("PLAYER_REGEN_ENABLED") return end
+
+ for i = 1, numGroup do
+ local unit = group..i
+ local frameName = E:StringTitle(unit)
+ frameName = gsub(frameName, "t(arget)", "T%1")
+ local frame = self[unit]
+
+ if not frame then
+ self.groupunits[unit] = group
+ frame = ElvUF:Spawn(unit, "ElvUF_"..frameName)
+ frame.index = i
+ frame:SetParent(ElvUF_Parent)
+ frame:SetID(i)
+ self[unit] = frame
+ end
+
+ frameName = E:StringTitle(group)
+ frameName = gsub(frameName, "t(arget)", "T%1")
+ frame.Update = function()
+ UF["Update_"..E:StringTitle(frameName).."Frames"](self, frame, self.db.units[group])
+ end
+
+ if self.db.units[group].enable then
+ frame:Enable()
+ frame.Update()
+
+ if frame.isForced then
+ self:ForceShow(frame)
+ end
+ E:EnableMover(frame.mover:GetName())
+ else
+ frame:Disable()
+
+ -- for some reason the boss/arena 'uncheck disable' doesnt fire this, we need to so putting it here.
+ if group == "boss" or group == "arena" then
+ UF:Configure_Fader(frame)
+ end
+
+ E:DisableMover(frame.mover:GetName())
+ end
+ end
+end
+
+function UF:HeaderUpdateSpecificElement(group, elementName)
+ assert(self[group], "Invalid group specified.")
+ for i = 1, self[group]:GetNumChildren() do
+ local frame = select(i, self[group]:GetChildren())
+ if frame and frame.Health then
+ frame:UpdateElement(elementName)
+ end
+ end
+end
+
+function UF.groupPrototype:GetAttribute(name)
+ return self.groups[1]:GetAttribute(name)
+end
+
+function UF.groupPrototype:Configure_Groups(frame)
+ local db = UF.db.units[frame.groupName]
+
+ local point
+ local width, height, newCols, newRows = 0, 0, 0, 0
+ local direction = db.growthDirection
+ local xMult, yMult = DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER[direction], DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER[direction]
+ local UNIT_HEIGHT = db.infoPanel and db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+ local groupSpacing = db.groupSpacing
+
+ local numGroups = frame.numGroups
+ for i = 1, numGroups do
+ local group = frame.groups[i]
+
+ point = DIRECTION_TO_POINT[direction]
+
+ if group then
+ group:Hide()
+
+ UF:ConvertGroupDB(group)
+ if point == "LEFT" or point == "RIGHT" then
+ group:SetAttribute("xOffset", db.horizontalSpacing * DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER[direction])
+ group:SetAttribute("yOffset", 0)
+ group:SetAttribute("columnSpacing", db.verticalSpacing)
+ else
+ group:SetAttribute("xOffset", 0)
+ group:SetAttribute("yOffset", db.verticalSpacing * DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER[direction])
+ group:SetAttribute("columnSpacing", db.horizontalSpacing)
+ end
+
+ --[[if not group.isForced then
+ if not group.initialized then
+ group:SetAttribute("startingIndex", db.raidWideSorting and (-min(numGroups * (db.groupsPerRowCol * 5), MAX_RAID_MEMBERS) + 1) or -4)
+ group:Show()
+ group.initialized = true
+ end
+ group:SetAttribute("startingIndex", 1)
+ end]]
+
+ group:ClearAllPoints()
+ if db.raidWideSorting and db.invertGroupingOrder then
+ group:SetAttribute("columnAnchorPoint", INVERTED_DIRECTION_TO_COLUMN_ANCHOR_POINT[direction])
+ else
+ group:SetAttribute("columnAnchorPoint", DIRECTION_TO_COLUMN_ANCHOR_POINT[direction])
+ end
+
+ group:ClearChildPoints()
+ group:SetAttribute("point", point)
+
+ if not group.isForced then
+ group:SetAttribute("maxColumns", db.raidWideSorting and numGroups or 1)
+ group:SetAttribute("unitsPerColumn", db.raidWideSorting and (db.groupsPerRowCol * 5) or 5)
+ if UF.headerGroupBy[db.groupBy] then
+ UF.headerGroupBy[db.groupBy](group)
+ else
+ UF.headerGroupBy["GROUP"](group)
+ end
+ group:SetAttribute("sortDir", db.sortDir)
+ group:SetAttribute("showPlayer", db.showPlayer)
+ end
+
+ if i == 1 and db.raidWideSorting then
+ group:SetAttribute("groupFilter", "1,2,3,4,5,6,7,8")
+ else
+ group:SetAttribute("groupFilter", tostring(i))
+ end
+
+ -- group:Show()
+ end
+
+ --MATH!! WOOT
+ point = DIRECTION_TO_GROUP_ANCHOR_POINT[direction]
+ if db.raidWideSorting and db.startFromCenter then
+ point = DIRECTION_TO_GROUP_ANCHOR_POINT["OUT_"..direction]
+ end
+ if (i - 1) % db.groupsPerRowCol == 0 then
+ if DIRECTION_TO_POINT[direction] == "LEFT" or DIRECTION_TO_POINT[direction] == "RIGHT" then
+ if group then
+ group:Point(point, frame, point, 0, height * yMult)
+ end
+ height = height + UNIT_HEIGHT + db.verticalSpacing + groupSpacing
+ newRows = newRows + 1
+ else
+ if group then
+ group:Point(point, frame, point, width * xMult, 0)
+ end
+ width = width + db.width + db.horizontalSpacing + groupSpacing
+
+ newCols = newCols + 1
+ end
+ else
+ if DIRECTION_TO_POINT[direction] == "LEFT" or DIRECTION_TO_POINT[direction] == "RIGHT" then
+ if newRows == 1 then
+ if group then
+ group:Point(point, frame, point, width * xMult, 0)
+ end
+ width = width + ((db.width + db.horizontalSpacing) * 5) + groupSpacing
+ newCols = newCols + 1
+ elseif group then
+ group:Point(point, frame, point, ((((db.width + db.horizontalSpacing) * 5) * ((i - 1) % db.groupsPerRowCol)) + ((i - 1) % db.groupsPerRowCol)*groupSpacing) * xMult, (((UNIT_HEIGHT + db.verticalSpacing+groupSpacing) * (newRows - 1))) * yMult)
+ end
+ else
+ if newCols == 1 then
+ if group then
+ group:Point(point, frame, point, 0, height * yMult)
+ end
+ height = height + ((UNIT_HEIGHT + db.verticalSpacing) * 5) + groupSpacing
+ newRows = newRows + 1
+ elseif group then
+ group:Point(point, frame, point, (((db.width + db.horizontalSpacing +groupSpacing) * (newCols - 1))) * xMult, ((((UNIT_HEIGHT + db.verticalSpacing) * 5) * ((i-1) % db.groupsPerRowCol))+((i-1) % db.groupsPerRowCol)*groupSpacing) * yMult)
+ end
+ end
+ end
+
+ if height == 0 then
+ height = height + ((UNIT_HEIGHT + db.verticalSpacing) * 5) + groupSpacing
+ elseif width == 0 then
+ width = width + ((db.width + db.horizontalSpacing) * 5) + groupSpacing
+ end
+ end
+
+ if not frame.isInstanceForced then
+ frame.dirtyWidth = width - db.horizontalSpacing -groupSpacing
+ frame.dirtyHeight = height - db.verticalSpacing -groupSpacing
+ end
+
+ if frame.mover then
+ frame.mover.positionOverride = DIRECTION_TO_GROUP_ANCHOR_POINT[direction]
+ E:UpdatePositionOverride(frame.mover:GetName())
+ frame:GetScript("OnSizeChanged")(frame) --Mover size is not updated if frame is hidden, so call an update manually
+ end
+
+ frame:Size(width - db.horizontalSpacing -groupSpacing, height - db.verticalSpacing - groupSpacing)
+end
+
+function UF.groupPrototype:Update(frame)
+ local group = frame.groupName
+
+ UF[group].db = UF.db.units[group]
+ for i = 1, #frame.groups do
+ frame.groups[i].db = UF.db.units[group]
+ frame.groups[i]:Update()
+ end
+end
+
+function UF.groupPrototype:AdjustVisibility(frame)
+-- if not frame.isForced then
+ local numGroups = frame.numGroups
+ for i = 1, #frame.groups do
+ local group = frame.groups[i]
+ if (i <= numGroups) and ((frame.db.raidWideSorting and i <= 1) or not frame.db.raidWideSorting) then
+ group:Show()
+ else
+ if group.forceShow then
+ group:Hide()
+ UF:UnshowChildUnits(group, group:GetChildren())
+ group:SetAttribute("startingIndex", 1)
+ else
+ group:Reset()
+ end
+ end
+ end
+-- end
+end
+
+function UF.headerPrototype:ClearChildPoints()
+ for i = 1, self:GetNumChildren() do
+ local child = select(i, self:GetChildren())
+ child:ClearAllPoints()
+ end
+end
+
+function UF.headerPrototype:Update()
+ local group = self.groupName
+ local db = UF.db.units[group]
+ UF["Update_"..E:StringTitle(group).."Header"](UF, self, db)
+
+ local i = 1
+ local child = self:GetAttribute("child"..i)
+
+ while child do
+ UF["Update_"..E:StringTitle(group).."Frames"](UF, child, db)
+
+ if _G[child:GetName().."Pet"] then
+ UF["Update_"..E:StringTitle(group).."Frames"](UF, _G[child:GetName().."Pet"], db)
+ end
+
+ if _G[child:GetName().."Target"] then
+ UF["Update_"..E:StringTitle(group).."Frames"](UF, _G[child:GetName().."Target"], db)
+ end
+
+ i = i + 1
+ child = self:GetAttribute("child"..i)
+ end
+end
+
+function UF.headerPrototype:Reset()
+ self:Hide()
+
+ self:SetAttribute("showPlayer", true)
+
+ self:SetAttribute("showSolo", true)
+ self:SetAttribute("showParty", true)
+ self:SetAttribute("showRaid", true)
+
+ self:SetAttribute("columnSpacing", nil)
+ self:SetAttribute("columnAnchorPoint", nil)
+ self:SetAttribute("groupBy", nil)
+ self:SetAttribute("groupFilter", nil)
+ self:SetAttribute("groupingOrder", nil)
+ self:SetAttribute("maxColumns", nil)
+ self:SetAttribute("nameList", nil)
+ self:SetAttribute("point", nil)
+ self:SetAttribute("sortDir", nil)
+ self:SetAttribute("sortMethod", "NAME")
+ self:SetAttribute("startingIndex", nil)
+ self:SetAttribute("strictFiltering", nil)
+ self:SetAttribute("unitsPerColumn", nil)
+ self:SetAttribute("xOffset", nil)
+ self:SetAttribute("yOffset", nil)
+end
+
+function UF:CreateHeader(parent, groupFilter, overrideName, template, groupName, headerTemplate)
+ local group = parent.groupName or groupName
+ ElvUF:SetActiveStyle("ElvUF_"..E:StringTitle(group))
+ local header = ElvUF:SpawnHeader(overrideName, headerTemplate, nil,
+ "groupFilter", groupFilter,
+ "showParty", true,
+ "showRaid", group == "party" and false or true,
+ "showSolo", true,
+ template and "template", template)
+
+ header.groupName = group
+ header:SetParent(parent)
+ --header:Show()
+
+ for k, v in pairs(self.headerPrototype) do
+ header[k] = v
+ end
+
+ return header
+end
+
+function UF:CreateAndUpdateHeaderGroup(group, groupFilter, template, headerUpdate, headerTemplate)
+ if InCombatLockdown() then self:RegisterEvent("PLAYER_REGEN_ENABLED") return end
+ local db = self.db.units[group]
+ local raidFilter = UF.db.smartRaidFilter
+ local numGroups = db.numGroups
+ if raidFilter and numGroups and (self[group] and not self[group].blockVisibilityChanges) then
+ local _, instanceType, _, _, maxPlayers = GetInstanceInfo()
+ if instanceType == "raid" or instanceType == "pvp" then
+ local mapID = GetCurrentMapAreaID()
+ if UF.instanceMapIDs[mapID] then
+ maxPlayers = UF.instanceMapIDs[mapID]
+ end
+
+ if maxPlayers > 0 then
+ numGroups = E:Round(maxPlayers/5)
+ end
+ end
+ end
+
+ if not self[group] then
+ local stringTitle = E:StringTitle(group)
+ ElvUF:RegisterStyle("ElvUF_"..stringTitle, UF["Construct_"..stringTitle.."Frames"])
+ ElvUF:SetActiveStyle("ElvUF_"..stringTitle)
+
+ if db.numGroups then
+ self[group] = CreateFrame("Frame", "ElvUF_"..stringTitle, ElvUF_Parent, "SecureHandlerStateTemplate")
+ self[group]:Hide()
+ self[group].groups = {}
+ self[group].groupName = group
+ self[group].template = self[group].template or template
+ self[group].headerTemplate = self[group].headerTemplate or headerTemplate
+ if not UF.headerFunctions[group] then UF.headerFunctions[group] = {} end
+ for k, v in pairs(self.groupPrototype) do
+ UF.headerFunctions[group][k] = v
+ end
+ else
+ self[group] = self:CreateHeader(ElvUF_Parent, groupFilter, "ElvUF_"..E:StringTitle(group), template, group, headerTemplate)
+ end
+
+ self[group].db = db
+ self.headers[group] = self[group]
+ --self[group]:Show()
+ end
+
+ self[group].numGroups = numGroups
+ if numGroups then
+ if db.raidWideSorting then
+ if not self[group].groups[1] then
+ self[group].groups[1] = self:CreateHeader(self[group], nil, "ElvUF_"..E:StringTitle(self[group].groupName).."Group1", template or self[group].template, nil, headerTemplate or self[group].headerTemplate)
+ end
+ else
+ while numGroups > #self[group].groups do
+ local index = tostring(#self[group].groups + 1)
+ tinsert(self[group].groups, self:CreateHeader(self[group], index, "ElvUF_"..E:StringTitle(self[group].groupName).."Group"..index, template or self[group].template, nil, headerTemplate or self[group].headerTemplate))
+ end
+ end
+
+ -- UF.headerFunctions[group]:AdjustVisibility(self[group])
+
+ if headerUpdate or not self[group].mover then
+ UF.headerFunctions[group]:Configure_Groups(self[group])
+ if not self[group].isForced and not self[group].blockVisibilityChanges then
+ RegisterStateDriver(self[group], "visibility", db.visibility)
+ end
+
+ if not self[group].mover then
+ UF.headerFunctions[group]:Update(self[group])
+ end
+ else
+ UF.headerFunctions[group]:Configure_Groups(self[group])
+ UF.headerFunctions[group]:Update(self[group])
+ end
+
+ UF.headerFunctions[group]:AdjustVisibility(self[group])
+
+ if db.enable then
+ if self[group].mover then
+ E:EnableMover(self[group].mover:GetName())
+ end
+ else
+ UnregisterStateDriver(self[group], "visibility")
+ self[group]:Hide()
+ if self[group].mover then
+ E:DisableMover(self[group].mover:GetName())
+ end
+ return
+ end
+ else
+ self[group].db = db
+
+ if not UF.headerFunctions[group] then UF.headerFunctions[group] = {} end
+ UF.headerFunctions[group].Update = function()
+ -- local db = UF.db.units[group]
+ if db.enable ~= true then
+ UnregisterStateDriver(UF[group], "visibility")
+ UF[group]:Hide()
+ if UF[group].mover then
+ E:DisableMover(UF[group].mover:GetName())
+ end
+ return
+ end
+ UF["Update_"..E:StringTitle(group).."Header"](UF, UF[group], db)
+
+ for i = 1, UF[group]:GetNumChildren() do
+ local child = select(i, UF[group]:GetChildren())
+ UF["Update_"..E:StringTitle(group).."Frames"](UF, child, UF.db.units[group])
+
+ if _G[child:GetName().."Target"] then
+ UF["Update_"..E:StringTitle(group).."Frames"](UF, _G[child:GetName().."Target"], UF.db.units[group])
+ end
+
+ if _G[child:GetName().."Pet"] then
+ UF["Update_"..E:StringTitle(group).."Frames"](UF, _G[child:GetName().."Pet"], UF.db.units[group])
+ end
+ end
+
+ E:EnableMover(UF[group].mover:GetName())
+ end
+
+ if headerUpdate then
+ UF["Update_"..E:StringTitle(group).."Header"](self, self[group], db)
+ else
+ UF.headerFunctions[group]:Update(self[group])
+ end
+ end
+end
+
+function UF:PLAYER_REGEN_ENABLED()
+ self:Update_AllFrames()
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED")
+end
+
+function UF:CreateAndUpdateUF(unit)
+ assert(unit, "No unit provided to create or update.")
+ if InCombatLockdown() then self:RegisterEvent("PLAYER_REGEN_ENABLED") return end
+
+ local frameName = E:StringTitle(unit)
+ frameName = gsub(frameName, "t(arget)", "T%1")
+ if not self[unit] then
+ self[unit] = ElvUF:Spawn(unit, "ElvUF_"..frameName)
+ self.units[unit] = unit
+ end
+
+ self[unit].Update = function()
+ UF["Update_"..frameName.."Frame"](self, self[unit], self.db.units[unit])
+ end
+
+ if self[unit]:GetParent() ~= ElvUF_Parent then
+ self[unit]:SetParent(ElvUF_Parent)
+ end
+
+ if self.db.units[unit].enable then
+ self[unit]:Enable()
+ self[unit].Update()
+ E:EnableMover(self[unit].mover:GetName())
+ else
+ self[unit].Update()
+ self[unit]:Disable()
+ E:DisableMover(self[unit].mover:GetName())
+ end
+end
+
+function UF:LoadUnits()
+ for _, unit in pairs(self.unitstoload) do
+ self:CreateAndUpdateUF(unit)
+ end
+ self.unitstoload = nil
+
+ for group, groupOptions in pairs(self.unitgroupstoload) do
+ local numGroup, template = unpack(groupOptions)
+ self:CreateAndUpdateUFGroup(group, numGroup, template)
+ end
+ self.unitgroupstoload = nil
+
+ for group, groupOptions in pairs(self.headerstoload) do
+ local groupFilter, template, headerTemplate
+ if type(groupOptions) == "table" then
+ groupFilter, template, headerTemplate = unpack(groupOptions)
+ end
+
+ self:CreateAndUpdateHeaderGroup(group, groupFilter, template, nil, headerTemplate)
+ end
+ self.headerstoload = nil
+end
+
+function UF:RegisterRaidDebuffIndicator()
+ local ORD = ns.oUF_RaidDebuffs or oUF_RaidDebuffs
+ if ORD then
+ ORD:ResetDebuffData()
+
+ local _, instanceType = GetInstanceInfo()
+ if instanceType == "party" or instanceType == "raid" then
+ local instance = E.global.unitframe.raidDebuffIndicator.instanceFilter
+ local instanceSpells = ((E.global.unitframe.aurafilters[instance] and E.global.unitframe.aurafilters[instance].spells) or E.global.unitframe.aurafilters.RaidDebuffs.spells)
+ ORD:RegisterDebuffs(instanceSpells)
+ else
+ local other = E.global.unitframe.raidDebuffIndicator.otherFilter
+ local otherSpells = ((E.global.unitframe.aurafilters[other] and E.global.unitframe.aurafilters[other].spells) or E.global.unitframe.aurafilters.CCDebuffs.spells)
+ ORD:RegisterDebuffs(otherSpells)
+ end
+ end
+end
+
+function UF:UpdateAllHeaders(event)
+ if InCombatLockdown() then
+ self:RegisterEvent("PLAYER_REGEN_ENABLED", "UpdateAllHeaders")
+ return
+ end
+
+ if event == "PLAYER_REGEN_ENABLED" then
+ self:UnregisterEvent("PLAYER_REGEN_ENABLED")
+ end
+
+ if E.private.unitframe.disabledBlizzardFrames.party then
+ ElvUF:DisableBlizzard("party")
+ end
+
+ self:RegisterRaidDebuffIndicator()
+
+ local smartRaidFilterEnabled = self.db.smartRaidFilter
+ for group, header in pairs(self.headers) do
+ UF.headerFunctions[group]:Update(header)
+
+ local shouldUpdateHeader
+ if header.numGroups == nil or smartRaidFilterEnabled then
+ shouldUpdateHeader = false
+ elseif header.numGroups ~= nil and not smartRaidFilterEnabled then
+ shouldUpdateHeader = true
+ end
+ self:CreateAndUpdateHeaderGroup(group, nil, nil, shouldUpdateHeader)
+
+ if group == "party" or group == "raid" or group == "raid40" then
+ --Update BuffIndicators on profile change as they might be using profile specific data
+ self:UpdateAuraWatchFromHeader(group)
+ end
+ end
+end
+
+local hiddenParent = CreateFrame("Frame")
+hiddenParent:SetAllPoints()
+hiddenParent:Hide()
+local HandleFrame = function(baseName)
+ local frame
+ if type(baseName) == "string" then
+ frame = _G[baseName]
+ else
+ frame = baseName
+ end
+
+ if frame then
+ frame:UnregisterAllEvents()
+ frame:Hide()
+
+ -- Keep frame hidden without causing taint
+ frame:SetParent(hiddenParent)
+
+ local health = frame.healthbar
+ if health then
+ health:UnregisterAllEvents()
+ end
+
+ local power = frame.manabar
+ if power then
+ power:UnregisterAllEvents()
+ end
+
+ local spell = frame.spellbar
+ if spell then
+ spell:UnregisterAllEvents()
+ end
+ end
+end
+
+function ElvUF:DisableBlizzard(unit)
+ if (not unit) or InCombatLockdown() then return end
+
+ if (unit == "player") and E.private.unitframe.disabledBlizzardFrames.player then
+ HandleFrame(PlayerFrame)
+
+ -- For the damn vehicle support:
+ PlayerFrame:RegisterEvent("UNIT_ENTERING_VEHICLE")
+ PlayerFrame:RegisterEvent("UNIT_ENTERED_VEHICLE")
+ PlayerFrame:RegisterEvent("UNIT_EXITING_VEHICLE")
+ PlayerFrame:RegisterEvent("UNIT_EXITED_VEHICLE")
+
+ RuneFrame:SetParent(PlayerFrame)
+ elseif (unit == "pet") and E.private.unitframe.disabledBlizzardFrames.player then
+ HandleFrame(PetFrame)
+ elseif (unit == "target") and E.private.unitframe.disabledBlizzardFrames.target then
+ HandleFrame(TargetFrame)
+ HandleFrame(ComboFrame)
+ elseif (unit == "focus") and E.private.unitframe.disabledBlizzardFrames.focus then
+ HandleFrame(FocusFrame)
+ HandleFrame(FocusFrameToT)
+ elseif (unit == "targettarget") and E.private.unitframe.disabledBlizzardFrames.target then
+ HandleFrame(TargetFrameToT)
+ elseif (unit:match"(boss)%d?$" == "boss") and E.private.unitframe.disabledBlizzardFrames.boss then
+ local id = unit:match"boss(%d)"
+
+ if id then
+ HandleFrame("Boss"..id.."TargetFrame")
+ else
+ for i = 1, MAX_BOSS_FRAMES do
+ HandleFrame(format("Boss%dTargetFrame", i))
+ end
+ end
+ elseif (unit:match"(party)%d?$" == "party") and E.private.unitframe.disabledBlizzardFrames.party then
+ local id = unit:match"party(%d)"
+
+ if id then
+ HandleFrame("PartyMemberFrame"..id)
+ else
+ for i = 1, 4 do
+ HandleFrame(format("PartyMemberFrame%d", i))
+ end
+ end
+ HandleFrame(PartyMemberBackground)
+ elseif (unit:match"(arena)%d?$" == "arena") and E.private.unitframe.disabledBlizzardFrames.arena then
+ local id = unit:match"arena(%d)"
+
+ if id then
+ HandleFrame("ArenaEnemyFrame"..id)
+ HandleFrame("ArenaEnemyFrame"..id.."PetFrame")
+ else
+ for i = 1, 5 do
+ HandleFrame(format("ArenaEnemyFrame%d", i))
+ HandleFrame(format("ArenaEnemyFrame%dPetFrame", i))
+ end
+ end
+ end
+end
+
+function UF:ADDON_LOADED(_, addon)
+ if addon ~= "Blizzard_ArenaUI" then return end
+
+ ElvUF:DisableBlizzard("arena")
+ self:UnregisterEvent("ADDON_LOADED")
+end
+
+do
+ local hasEnteredWorld = false
+ function UF:PLAYER_ENTERING_WORLD()
+ if not hasEnteredWorld then
+ --We only want to run Update_AllFrames once when we first log in or /reload
+ UF:Update_AllFrames()
+ hasEnteredWorld = true
+ else
+ local _, instanceType = IsInInstance()
+ if instanceType ~= "none" then
+ --We need to update headers when we zone into an instance
+ UF:UpdateAllHeaders()
+ end
+ end
+ end
+end
+
+function UF:UnitFrameThreatIndicator_Initialize(_, unitFrame)
+ unitFrame:UnregisterAllEvents() --Arena Taint Fix
+end
+
+function UF:ResetUnitSettings(unit)
+ E:CopyTable(self.db.units[unit], P.unitframe.units[unit])
+
+ if self.db.units[unit].buffs and self.db.units[unit].buffs.sizeOverride then
+ self.db.units[unit].buffs.sizeOverride = P.unitframe.units[unit].buffs.sizeOverride or 0
+ end
+
+ if self.db.units[unit].debuffs and self.db.units[unit].debuffs.sizeOverride then
+ self.db.units[unit].debuffs.sizeOverride = P.unitframe.units[unit].debuffs.sizeOverride or 0
+ end
+
+ self:Update_AllFrames()
+end
+
+function UF:ToggleForceShowGroupFrames(unitGroup, numGroup)
+ for i = 1, numGroup do
+ if self[unitGroup..i] and not self[unitGroup..i].isForced then
+ UF:ForceShow(self[unitGroup..i])
+ elseif self[unitGroup..i] then
+ UF:UnforceShow(self[unitGroup..i])
+ end
+ end
+end
+
+local ignoreSettings = {
+ ["position"] = true,
+ ["priority"] = true
+}
+
+local ignoreSettingsGroup = {
+ ["visibility"] = true
+}
+
+local allowPass = {
+ ["sizeOverride"] = true
+}
+
+function UF:MergeUnitSettings(fromUnit, toUnit, isGroupUnit)
+ local db = self.db.units
+ local filter = ignoreSettings
+ if isGroupUnit then
+ filter = ignoreSettingsGroup
+ end
+ if fromUnit ~= toUnit then
+ for option, value in pairs(db[fromUnit]) do
+ if type(value) ~= "table" and not filter[option] then
+ if db[toUnit][option] ~= nil then
+ db[toUnit][option] = value
+ end
+ elseif not filter[option] then
+ if type(value) == "table" then
+ for opt, val in pairs(db[fromUnit][option]) do
+ --local val = db[fromUnit][option][opt]
+ if type(val) ~= "table" and not filter[opt] then
+ if db[toUnit][option] ~= nil and (db[toUnit][option][opt] ~= nil or allowPass[opt]) then
+ db[toUnit][option][opt] = val
+ end
+ elseif not filter[opt] then
+ if type(val) == "table" then
+ for o, v in pairs(db[fromUnit][option][opt]) do
+ if not filter[o] then
+ if db[toUnit][option] ~= nil and db[toUnit][option][opt] ~= nil and db[toUnit][option][opt][o] ~= nil then
+ db[toUnit][option][opt][o] = v
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ else
+ E:Print(L["You cannot copy settings from the same unit."])
+ end
+
+ self:Update_AllFrames()
+end
+
+function UF:UpdateBackdropTextureColor(r, g, b)
+ local m = 0.35
+ local n = self.isTransparent and (m * 2) or m
+
+ if self.invertColors then
+ local nn = n;n=m;m=nn
+ end
+
+ if self.isTransparent then
+ if self.backdrop then
+ local _, _, _, a = self.backdrop:GetBackdropColor()
+ self.backdrop:SetBackdropColor(r * n, g * n, b * n, a)
+ else
+ local parent = self:GetParent()
+ if parent and parent.template then
+ local _, _, _, a = parent:GetBackdropColor()
+ parent:SetBackdropColor(r * n, g * n, b * n, a)
+ end
+ end
+ end
+
+ local bg = self.bg or self.BG
+ if bg and bg:IsObjectType("Texture") and not bg.multiplier then
+ if self.custom_backdrop then
+ bg:SetVertexColor(self.custom_backdrop.r, self.custom_backdrop.g, self.custom_backdrop.b)
+ else
+ bg:SetVertexColor(r * m, g * m, b * m)
+ end
+ end
+end
+
+function UF:UpdatePredictionStatusBar(prediction, parent)
+ if not (prediction and parent) then return end
+ local texture = (not parent.isTransparent and parent:GetStatusBarTexture():GetTexture()) or E.media.blankTex
+
+ UF:Update_StatusBar(prediction.myBar, texture)
+ UF:Update_StatusBar(prediction.otherBar, texture)
+end
+
+function UF:SetStatusBarBackdropPoints(statusBar, statusBarTex, backdropTex, statusBarOrientation)
+ backdropTex:ClearAllPoints()
+ if statusBarOrientation == "VERTICAL" then
+ backdropTex:SetPoint("TOPLEFT", statusBar)
+ backdropTex:SetPoint("BOTTOMRIGHT", statusBarTex, "TOPRIGHT")
+ else
+ backdropTex:SetPoint("TOPRIGHT", statusBar)
+ backdropTex:SetPoint("BOTTOMLEFT", statusBarTex, "BOTTOMRIGHT")
+ end
+end
+
+function UF:ToggleTransparentStatusBar(isTransparent, statusBar, backdropTex, adjustBackdropPoints, invertColors)
+ statusBar.isTransparent = isTransparent
+ statusBar.invertColors = invertColors
+ statusBar.backdropTex = backdropTex
+
+ local statusBarTex = statusBar:GetStatusBarTexture()
+ local statusBarOrientation = statusBar:GetOrientation()
+
+ if not statusBar.hookedColor then
+ hooksecurefunc(statusBar, "SetStatusBarColor", UF.UpdateBackdropTextureColor)
+ statusBar.hookedColor = true
+ end
+
+ if isTransparent then
+ if statusBar.backdrop then
+ statusBar.backdrop:SetTemplate("Transparent", nil, nil, nil, true)
+ elseif statusBar:GetParent().template then
+ statusBar:GetParent():SetTemplate("Transparent", nil, nil, nil, true)
+ end
+
+ statusBar:SetStatusBarTexture("")
+ UF:Update_StatusBar(statusBar.bg or statusBar.BG, E.media.blankTex)
+
+ if statusBar.texture then statusBar.texture = statusBar:GetStatusBarTexture() end --Needed for Power element
+
+ UF:SetStatusBarBackdropPoints(statusBar, statusBarTex, backdropTex, statusBarOrientation)
+ else
+ if statusBar.backdrop then
+ statusBar.backdrop:SetTemplate(nil, nil, nil, not statusBar.PostCastStart and self.thinBorders, true)
+ elseif statusBar:GetParent().template then
+ statusBar:GetParent():SetTemplate(nil, nil, nil, self.thinBorders, true)
+ end
+
+ local texture = LSM:Fetch("statusbar", self.db.statusbar)
+ statusBar:SetStatusBarTexture(texture)
+ UF:Update_StatusBar(statusBar.bg or statusBar.BG, texture)
+
+ if statusBar.texture then statusBar.texture = statusBar:GetStatusBarTexture() end
+
+ if adjustBackdropPoints then
+ backdropTex:ClearAllPoints()
+ backdropTex:SetAllPoints(statusBar)
+ end
+ end
+end
+
+function UF:Initialize()
+ self.db = E.db.unitframe
+ self.thinBorders = self.db.thinBorders or E.PixelMode
+ if E.private.unitframe.enable ~= true then return end
+ self.Initialized = true
+
+ local ElvUF_Parent = CreateFrame("Frame", "ElvUF_Parent", E.UIParent, "SecureHandlerStateTemplate")
+ ElvUF_Parent:SetFrameStrata("LOW")
+
+ self:UpdateColors()
+ ElvUF:RegisterStyle("ElvUF", function(frame, unit)
+ self:Construct_UF(frame, unit)
+ end)
+
+ self:LoadUnits()
+ self:RegisterEvent("PLAYER_ENTERING_WORLD")
+
+ for k in pairs(UnitPopupMenus) do
+ for x, y in pairs(UnitPopupMenus[k]) do
+ if y == "SET_FOCUS" or y == "CLEAR_FOCUS" or y == "LOCK_FOCUS_FRAME" or y == "UNLOCK_FOCUS_FRAME" then
+ tremove(UnitPopupMenus[k], x)
+ end
+ end
+ end
+
+ if E.private.unitframe.disabledBlizzardFrames.arena and E.private.unitframe.disabledBlizzardFrames.focus and E.private.unitframe.disabledBlizzardFrames.party then
+ InterfaceOptionsFrameCategoriesButton10:SetScale(0.0001)
+ end
+
+ if E.private.unitframe.disabledBlizzardFrames.player then
+ InterfaceOptionsStatusTextPanelPlayer:SetScale(0.0001)
+ InterfaceOptionsStatusTextPanelPlayer:SetAlpha(0)
+ InterfaceOptionsStatusTextPanelPet:SetScale(0.0001)
+ InterfaceOptionsStatusTextPanelPet:SetAlpha(0)
+ end
+
+ if E.private.unitframe.disabledBlizzardFrames.target then
+ InterfaceOptionsStatusTextPanelTarget:SetScale(0.0001)
+ InterfaceOptionsStatusTextPanelTarget:SetAlpha(0)
+ InterfaceOptionsCombatPanelEnemyCastBarsOnPortrait:SetAlpha(0)
+ InterfaceOptionsCombatPanelEnemyCastBarsOnPortrait:EnableMouse(false)
+ InterfaceOptionsCombatPanelEnemyCastBarsOnNameplates:ClearAllPoints()
+ InterfaceOptionsCombatPanelEnemyCastBarsOnNameplates:Point(InterfaceOptionsCombatPanelEnemyCastBarsOnPortrait:GetPoint())
+ InterfaceOptionsCombatPanelTargetOfTarget:SetScale(0.0001)
+ InterfaceOptionsCombatPanelTargetOfTarget:SetAlpha(0)
+ InterfaceOptionsDisplayPanelShowAggroPercentage:SetScale(0.0001)
+ InterfaceOptionsDisplayPanelShowAggroPercentage:SetAlpha(0)
+ end
+
+ if E.private.unitframe.disabledBlizzardFrames.party then
+ InterfaceOptionsStatusTextPanelParty:SetScale(0.0001)
+ InterfaceOptionsStatusTextPanelParty:SetAlpha(0)
+ InterfaceOptionsFrameCategoriesButton11:SetScale(0.0001)
+ end
+
+ if E.private.unitframe.disabledBlizzardFrames.arena then
+ self:SecureHook("UnitFrameThreatIndicator_Initialize")
+
+ if not IsAddOnLoaded("Blizzard_ArenaUI") then
+ self:RegisterEvent("ADDON_LOADED")
+ else
+ ElvUF:DisableBlizzard("arena")
+ end
+ end
+
+ local ORD = ns.oUF_RaidDebuffs or oUF_RaidDebuffs
+ if ORD then
+ ORD.ShowDispellableDebuff = true
+ ORD.MatchBySpellName = true
+ end
+
+ self:UpdateRangeCheckSpells()
+ self:RegisterEvent("LEARNED_SPELL_IN_TAB", "UpdateRangeCheckSpells")
+end
+
+local function InitializeCallback()
+ UF:Initialize()
+end
+
+E:RegisterInitialModule(UF:GetName(), InitializeCallback)
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Units/Focus.lua b/ElvUI/Modules/UnitFrames/Units/Focus.lua
new file mode 100644
index 0000000..e808f60
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Units/Focus.lua
@@ -0,0 +1,137 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local _G = _G
+local tinsert = tinsert
+--WoW API / Variables
+
+function UF:Construct_FocusFrame(frame)
+ frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
+ frame.Health.frequentUpdates = true
+
+ frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
+
+ frame.Name = self:Construct_NameText(frame)
+
+ frame.Portrait3D = self:Construct_Portrait(frame, "model")
+ frame.Portrait2D = self:Construct_Portrait(frame, "texture")
+
+ frame.Buffs = self:Construct_Buffs(frame)
+ frame.Castbar = self:Construct_Castbar(frame, L["Focus Castbar"])
+ frame.Castbar.SafeZone = nil
+ frame.Castbar.LatencyTexture:Hide()
+ frame.RaidTargetIndicator = self:Construct_RaidIcon(frame)
+ frame.Debuffs = self:Construct_Debuffs(frame)
+ frame.HealCommBar = self:Construct_HealComm(frame)
+ frame.AuraBars = self:Construct_AuraBarHeader(frame)
+ frame.ThreatIndicator = self:Construct_Threat(frame)
+ frame.GPS = self:Construct_GPS(frame)
+ frame.MouseGlow = self:Construct_MouseGlow(frame)
+ frame.TargetGlow = self:Construct_TargetGlow(frame)
+ frame.InfoPanel = self:Construct_InfoPanel(frame)
+ frame.DebuffHighlight = self:Construct_DebuffHighlight(frame)
+ frame.Fader = self:Construct_Fader()
+ frame.Cutaway = self:Construct_Cutaway(frame)
+
+ frame.customTexts = {}
+ frame:Point("BOTTOMRIGHT", ElvUF_Target, "TOPRIGHT", 0, 220)
+ E:CreateMover(frame, frame:GetName().."Mover", L["Focus Frame"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,focus,generalGroup")
+
+ frame.unitframeType = "focus"
+end
+
+function UF:Update_FocusFrame(frame, db)
+ frame.db = db
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+ frame.colors = ElvUF.colors
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ _G[frame:GetName().."Mover"]:Size(frame:GetSize())
+
+ frame:SetAttribute("type3", "macro")
+ frame:SetAttribute("macrotext", "/clearfocus")
+
+ UF:Configure_InfoPanel(frame)
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --Castbar
+ UF:Configure_Castbar(frame)
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --OverHealing
+ UF:Configure_HealComm(frame)
+
+ --GPS
+ UF:Configure_GPS(frame)
+
+ --Raid Icon
+ UF:Configure_RaidIcon(frame)
+
+ --AuraBars
+ UF:Configure_AuraBars(frame)
+
+ --CustomTexts
+ UF:Configure_CustomTexts(frame)
+
+ --Debuff Highlight
+ UF:Configure_DebuffHighlight(frame)
+
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+tinsert(UF.unitstoload, "focus")
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Units/FocusTarget.lua b/ElvUI/Modules/UnitFrames/Units/FocusTarget.lua
new file mode 100644
index 0000000..2dd9815
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Units/FocusTarget.lua
@@ -0,0 +1,109 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local _G = _G
+local tinsert = table.insert
+--WoW API / Variables
+
+function UF:Construct_FocusTargetFrame(frame)
+ frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
+
+ frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
+ frame.Name = self:Construct_NameText(frame)
+
+ frame.Portrait3D = self:Construct_Portrait(frame, "model")
+ frame.Portrait2D = self:Construct_Portrait(frame, "texture")
+
+ frame.Buffs = self:Construct_Buffs(frame)
+ frame.RaidTargetIndicator = self:Construct_RaidIcon(frame)
+ frame.Debuffs = self:Construct_Debuffs(frame)
+ frame.ThreatIndicator = self:Construct_Threat(frame)
+ frame.MouseGlow = self:Construct_MouseGlow(frame)
+ frame.TargetGlow = self:Construct_TargetGlow(frame)
+ frame.InfoPanel = self:Construct_InfoPanel(frame)
+ frame.Fader = self:Construct_Fader()
+ frame.Cutaway = self:Construct_Cutaway(frame)
+
+ frame.customTexts = {}
+ frame:Point("BOTTOM", ElvUF_Focus, "TOP", 0, 7) --Set to default position
+ E:CreateMover(frame, frame:GetName().."Mover", L["FocusTarget Frame"], nil, -7, nil, "ALL,SOLO", nil, "unitframe,focustarget,generalGroup")
+
+ frame.unitframeType = "focustarget"
+end
+
+function UF:Update_FocusTargetFrame(frame, db)
+ frame.db = db
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+ frame.colors = ElvUF.colors
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ _G[frame:GetName().."Mover"]:Size(frame:GetSize())
+ UF:Configure_InfoPanel(frame)
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --Raid Icon
+ UF:Configure_RaidIcon(frame)
+
+ --CustomTexts
+ UF:Configure_CustomTexts(frame)
+
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+tinsert(UF.unitstoload, "focustarget")
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Units/Load_Units.xml b/ElvUI/Modules/UnitFrames/Units/Load_Units.xml
new file mode 100644
index 0000000..1493162
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Units/Load_Units.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Units/Pet.lua b/ElvUI/Modules/UnitFrames/Units/Pet.lua
new file mode 100644
index 0000000..1016108
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Units/Pet.lua
@@ -0,0 +1,127 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local _G = _G
+local tinsert = tinsert
+--WoW API / Variables
+
+function UF:Construct_PetFrame(frame)
+ frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
+ frame.Health.frequentUpdates = true
+ frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
+ frame.Name = self:Construct_NameText(frame)
+ frame.Portrait3D = self:Construct_Portrait(frame, "model")
+ frame.Portrait2D = self:Construct_Portrait(frame, "texture")
+ frame.Buffs = self:Construct_Buffs(frame)
+ frame.Debuffs = self:Construct_Debuffs(frame)
+ frame.Castbar = self:Construct_Castbar(frame, L["Pet Castbar"])
+ frame.Castbar.SafeZone = nil
+ frame.Castbar.LatencyTexture:Hide()
+ frame.ThreatIndicator = self:Construct_Threat(frame)
+ frame.HealCommBar = self:Construct_HealComm(frame)
+ frame.AuraWatch = self:Construct_AuraWatch(frame)
+ frame.AuraBars = self:Construct_AuraBarHeader(frame)
+ frame.HappinessIndicator = self:Construct_Happiness(frame)
+ frame.InfoPanel = self:Construct_InfoPanel(frame)
+ frame.MouseGlow = self:Construct_MouseGlow(frame)
+ frame.TargetGlow = self:Construct_TargetGlow(frame)
+ frame.Fader = self:Construct_Fader()
+ frame.Cutaway = self:Construct_Cutaway(frame)
+ frame.customTexts = {}
+
+ frame:Point("BOTTOM", E.UIParent, "BOTTOM", 0, 118)
+ E:CreateMover(frame, frame:GetName().."Mover", L["Pet Frame"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,pet,generalGroup")
+
+ frame.unitframeType = "pet"
+end
+
+function UF:Update_PetFrame(frame, db)
+ frame.db = db
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.HAPPINESS_SHOWN = (db.happiness and db.happiness.enable) and frame.HappinessIndicator and frame.HappinessIndicator:IsShown()
+ frame.HAPPINESS_WIDTH = frame.HAPPINESS_SHOWN and (db.happiness.width + (frame.BORDER*2)) or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ frame.colors = ElvUF.colors
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ _G[frame:GetName().."Mover"]:Size(frame:GetSize())
+
+ UF:Configure_InfoPanel(frame)
+
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --Castbar
+ UF:Configure_Castbar(frame)
+
+ --OverHealing
+ UF:Configure_HealComm(frame)
+
+ --AuraBars
+ UF:Configure_AuraBars(frame)
+
+ UF:Configure_Happiness(frame)
+
+ --CustomTexts
+ UF:Configure_CustomTexts(frame)
+
+ UF:UpdateAuraWatch(frame)
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+tinsert(UF.unitstoload, "pet")
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Units/PetTarget.lua b/ElvUI/Modules/UnitFrames/Units/PetTarget.lua
new file mode 100644
index 0000000..4e49cea
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Units/PetTarget.lua
@@ -0,0 +1,104 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local _G = _G
+local tinsert = tinsert
+--WoW API / Variables
+
+function UF:Construct_PetTargetFrame(frame)
+ frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
+ frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
+ frame.Name = self:Construct_NameText(frame)
+ frame.Portrait3D = self:Construct_Portrait(frame, "model")
+ frame.Portrait2D = self:Construct_Portrait(frame, "texture")
+ frame.InfoPanel = self:Construct_InfoPanel(frame)
+ frame.Buffs = self:Construct_Buffs(frame)
+ frame.ThreatIndicator = self:Construct_Threat(frame)
+ frame.Debuffs = self:Construct_Debuffs(frame)
+ frame.MouseGlow = self:Construct_MouseGlow(frame)
+ frame.TargetGlow = self:Construct_TargetGlow(frame)
+ frame.Fader = self:Construct_Fader()
+ frame.Cutaway = self:Construct_Cutaway(frame)
+ frame.customTexts = {}
+
+ frame:Point("BOTTOM", ElvUF_Pet, "TOP", 0, 7) --Set to default position
+ E:CreateMover(frame, frame:GetName().."Mover", L["PetTarget Frame"], nil, -7, nil, "ALL,SOLO", nil, "unitframe,pettarget,generalGroup")
+
+ frame.unitframeType = "pettarget"
+end
+
+function UF:Update_PetTargetFrame(frame, db)
+ frame.db = db
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ frame.colors = ElvUF.colors
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ _G[frame:GetName().."Mover"]:Size(frame:GetSize())
+
+ UF:Configure_InfoPanel(frame)
+
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --CustomTexts
+ UF:Configure_CustomTexts(frame)
+
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+tinsert(UF.unitstoload, "pettarget")
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Units/Player.lua b/ElvUI/Modules/UnitFrames/Units/Player.lua
new file mode 100644
index 0000000..2270b3d
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Units/Player.lua
@@ -0,0 +1,237 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local _G = _G
+local tinsert = tinsert
+--WoW API / Variables
+local CreateFrame = CreateFrame
+local CastingBarFrame_OnLoad = CastingBarFrame_OnLoad
+local CastingBarFrame_SetUnit = CastingBarFrame_SetUnit
+
+function UF:Construct_PlayerFrame(frame)
+ frame.ThreatIndicator = self:Construct_Threat(frame)
+ frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
+ frame.Health.frequentUpdates = true
+ frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
+ frame.Power.frequentUpdates = true
+ frame.Energy = self:Construct_EnergyBar(frame, true, true, "LEFT")
+ frame.Rage = self:Construct_RageBar(frame, true, true, "LEFT")
+ frame.Name = self:Construct_NameText(frame)
+ frame.Portrait3D = self:Construct_Portrait(frame, "model")
+ frame.Portrait2D = self:Construct_Portrait(frame, "texture")
+ frame.Buffs = self:Construct_Buffs(frame)
+ frame.Debuffs = self:Construct_Debuffs(frame)
+ frame.Castbar = self:Construct_Castbar(frame, L["Player Castbar"])
+
+ --Create a holder frame all "classbars" can be positioned into
+ frame.ClassBarHolder = CreateFrame("Frame", nil, frame)
+ frame.ClassBarHolder:Point("BOTTOM", E.UIParent, "BOTTOM", 0, 150)
+
+ frame.AdditionalPower = self:Construct_AdditionalPowerBar(frame, nil, UF.UpdateClassBar)
+ frame.ClassBar = "AdditionalPower"
+
+ --frame.Runes = self:Construct_DeathKnightResourceBar(frame)
+ --frame.ClassBar = "Runes"
+
+ frame.MouseGlow = self:Construct_MouseGlow(frame)
+ frame.TargetGlow = self:Construct_TargetGlow(frame)
+ frame.RaidTargetIndicator = self:Construct_RaidIcon(frame)
+ frame.RaidRoleFramesAnchor = self:Construct_RaidRoleFrames(frame)
+ frame.RestingIndicator = self:Construct_RestingIndicator(frame)
+ frame.CombatIndicator = self:Construct_CombatIndicator(frame)
+ frame.PvPText = self:Construct_PvPIndicator(frame)
+ frame.DebuffHighlight = self:Construct_DebuffHighlight(frame)
+ frame.HealCommBar = self:Construct_HealComm(frame)
+ frame.AuraBars = self:Construct_AuraBarHeader(frame)
+ frame.InfoPanel = self:Construct_InfoPanel(frame)
+ frame.PvPIndicator = self:Construct_PvPIcon(frame)
+ frame.Fader = self:Construct_Fader()
+ frame.Cutaway = self:Construct_Cutaway(frame)
+ frame.customTexts = {}
+
+ frame:Point("BOTTOMLEFT", E.UIParent, "BOTTOM", -413, 68) --Set to default position
+ E:CreateMover(frame, frame:GetName().."Mover", L["Player Frame"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,player,generalGroup")
+
+ frame.unitframeType = "player"
+end
+
+function UF:Update_PlayerFrame(frame, db)
+ frame.db = db
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ -- Power
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ -- Energy
+ frame.USE_ENERGYBAR = db.energy.enable
+ frame.ENERGYBAR_DETACHED = db.energy.detachFromFrame
+ frame.USE_INSET_ENERGYBAR = not frame.ENERGYBAR_DETACHED and db.energy.width == "inset" and frame.USE_ENERGYBAR
+ frame.USE_MINI_ENERGYBAR = (not frame.ENERGYBAR_DETACHED and db.energy.width == "spaced" and frame.USE_ENERGYBAR)
+ frame.USE_ENERGYBAR_OFFSET = db.energy.offset ~= 0 and frame.USE_ENERGYBAR and not frame.ENERGYBAR_DETACHED
+ frame.ENERGYBAR_OFFSET = frame.USE_ENERGYBAR_OFFSET and db.energy.offset or 0
+
+ frame.ENERGYBAR_HEIGHT = not frame.USE_ENERGYBAR and 0 or db.energy.height
+ frame.ENERGYBAR_WIDTH = frame.USE_MINI_ENERGYBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.ENERGYBAR_DETACHED and db.energy.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ -- Rage
+ frame.USE_RAGEBAR = db.rage.enable
+ frame.RAGEBAR_DETACHED = db.rage.detachFromFrame
+ frame.USE_INSET_RAGEBAR = not frame.RAGEBAR_DETACHED and db.rage.width == "inset" and frame.USE_RAGEBAR
+ frame.USE_MINI_RAGEBAR = (not frame.RAGEBAR_DETACHED and db.rage.width == "spaced" and frame.USE_RAGEBAR)
+ frame.USE_RAGEBAR_OFFSET = db.rage.offset ~= 0 and frame.USE_RAGEBAR and not frame.RAGEBAR_DETACHED
+ frame.RAGEBAR_OFFSET = frame.USE_RAGEBAR_OFFSET and db.rage.offset or 0
+
+ frame.RAGEBAR_HEIGHT = not frame.USE_RAGEBAR and 0 or db.rage.height
+ frame.RAGEBAR_WIDTH = frame.USE_MINI_RAGEBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.RAGEBAR_DETACHED and db.rage.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.MAX_CLASS_BAR = frame.MAX_CLASS_BAR or UF.classMaxResourceBar[E.myclass] or 0
+ frame.USE_CLASSBAR = db.classbar.enable
+ frame.CLASSBAR_SHOWN = frame[frame.ClassBar]:IsShown()
+ frame.CLASSBAR_DETACHED = db.classbar.detachFromFrame
+ frame.USE_MINI_CLASSBAR = db.classbar.fill == "spaced" and frame.USE_CLASSBAR
+ frame.CLASSBAR_HEIGHT = frame.USE_CLASSBAR and db.classbar.height or 0
+ frame.CLASSBAR_WIDTH = frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2) - frame.PORTRAIT_WIDTH -(frame.ORIENTATION == "MIDDLE" and (frame.POWERBAR_OFFSET*2) or frame.POWERBAR_OFFSET)
+ --If formula for frame.CLASSBAR_YOFFSET changes, then remember to update it in classbars.lua too
+ frame.CLASSBAR_YOFFSET = (not frame.USE_CLASSBAR or not frame.CLASSBAR_SHOWN or frame.CLASSBAR_DETACHED) and 0 or (frame.USE_MINI_CLASSBAR and (frame.SPACING+(frame.CLASSBAR_HEIGHT/2)) or (frame.CLASSBAR_HEIGHT - (frame.BORDER-frame.SPACING)))
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and not frame.USE_MINI_RAGEBAR and not frame.USE_RAGEBAR_OFFSET and not frame.USE_MINI_ENERGYBAR and not frame.USE_ENERGYBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ frame.colors = ElvUF.colors
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ _G[frame:GetName().."Mover"]:Size(frame:GetSize())
+
+ UF:Configure_InfoPanel(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Rest Icon
+ UF:Configure_RestingIndicator(frame)
+
+ --Combat Icon
+ UF:Configure_CombatIndicator(frame)
+
+ --Resource Bars
+ UF:Configure_ClassBar(frame)
+
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --PvP
+ UF:Configure_PVPIndicator(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+
+ --Energy
+ UF:Configure_Energy(frame)
+
+ --Rage
+ UF:Configure_Rage(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --Castbar
+ frame:DisableElement("Castbar")
+ UF:Configure_Castbar(frame)
+
+ if (not db.enable and not E.private.unitframe.disabledBlizzardFrames.player) then
+ CastingBarFrame_OnLoad(CastingBarFrame, "player", true, false)
+ CastingBarFrame_SetUnit(CastingBarFrame, "player", true, false)
+ PetCastingBarFrame_OnLoad(PetCastingBarFrame)
+ CastingBarFrame_SetUnit(PetCastingBarFrame, "pet", false, false)
+ elseif not db.enable and E.private.unitframe.disabledBlizzardFrames.player or (db.enable and not db.castbar.enable) then
+ CastingBarFrame_SetUnit(CastingBarFrame, nil)
+ CastingBarFrame_SetUnit(PetCastingBarFrame, nil)
+ end
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --Debuff Highlight
+ UF:Configure_DebuffHighlight(frame)
+
+ --Raid Icon
+ UF:Configure_RaidIcon(frame)
+
+ --OverHealing
+ UF:Configure_HealComm(frame)
+
+ --AuraBars
+ UF:Configure_AuraBars(frame)
+ --We need to update Target AuraBars if attached to Player AuraBars
+ --mainly because of issues when using power offset on player and switching to/from middle orientation
+ if E.db.unitframe.units.target.aurabar.attachTo == "PLAYER_AURABARS" and ElvUF_Target then
+ UF:Configure_AuraBars(ElvUF_Target)
+ end
+
+ --PvP
+ UF:Configure_PVPIcon(frame)
+
+ UF:Configure_RaidRoleIcons(frame)
+
+ --CustomTexts
+ UF:Configure_CustomTexts(frame)
+
+ E:SetMoverSnapOffset(frame:GetName().."Mover", -(12 + db.castbar.height))
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+tinsert(UF.unitstoload, "player")
+
+local function UpdateClassBar()
+ local frame = _G.ElvUF_Player
+ if frame and frame.ClassBar then
+ frame:UpdateElement(frame.ClassBar)
+ UF.ToggleResourceBar(frame[frame.ClassBar])
+ end
+end
+
+local f = CreateFrame("Frame")
+f:RegisterEvent("PLAYER_ENTERING_WORLD")
+f:SetScript("OnEvent", function(self, event)
+ self:UnregisterEvent(event)
+ if not E.db.unitframe.units.player.enable then return end
+ UpdateClassBar()
+end)
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Units/Target.lua b/ElvUI/Modules/UnitFrames/Units/Target.lua
new file mode 100644
index 0000000..1d1ae7e
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Units/Target.lua
@@ -0,0 +1,163 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local _G = _G
+local tinsert = tinsert
+--WoW API / Variables
+local IsAddOnLoaded = IsAddOnLoaded
+
+function UF:Construct_TargetFrame(frame)
+ frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
+ frame.Health.frequentUpdates = true
+ frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
+ frame.Power.frequentUpdates = true
+ frame.Name = self:Construct_NameText(frame)
+ frame.Portrait3D = self:Construct_Portrait(frame, "model")
+ frame.Portrait2D = self:Construct_Portrait(frame, "texture")
+ frame.Buffs = self:Construct_Buffs(frame)
+ frame.Debuffs = self:Construct_Debuffs(frame)
+ frame.ThreatIndicator = self:Construct_Threat(frame)
+ frame.Castbar = self:Construct_Castbar(frame, L["Target Castbar"])
+ frame.Castbar.SafeZone = nil
+ frame.Castbar.LatencyTexture:Hide()
+ frame.RaidTargetIndicator = self:Construct_RaidIcon(frame)
+
+ frame.ComboPointsHolder = CreateFrame("Frame", nil, frame)
+ frame.ComboPointsHolder:Point("BOTTOM", E.UIParent, "BOTTOM", 0, 200)
+ frame.ComboPoints = self:Construct_Combobar(frame)
+
+ frame.HealCommBar = self:Construct_HealComm(frame)
+ frame.DebuffHighlight = self:Construct_DebuffHighlight(frame)
+ frame.InfoPanel = self:Construct_InfoPanel(frame)
+ frame.MouseGlow = self:Construct_MouseGlow(frame)
+ frame.TargetGlow = self:Construct_TargetGlow(frame)
+ frame.AuraBars = self:Construct_AuraBarHeader(frame)
+ frame.GPS = self:Construct_GPS(frame)
+ frame.PvPIndicator = self:Construct_PvPIcon(frame)
+ frame.Fader = self:Construct_Fader()
+ frame.Cutaway = self:Construct_Cutaway(frame)
+ frame.customTexts = {}
+ frame:Point("BOTTOMRIGHT", E.UIParent, "BOTTOM", 413, 68)
+ E:CreateMover(frame, frame:GetName().."Mover", L["Target Frame"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,target,generalGroup")
+
+ frame.unitframeType = "target"
+end
+
+function UF:Update_TargetFrame(frame, db)
+ frame.db = db
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.CAN_HAVE_CLASSBAR = db.combobar.enable
+ frame.MAX_CLASS_BAR = MAX_COMBO_POINTS
+ frame.USE_CLASSBAR = db.combobar.enable
+ frame.CLASSBAR_SHOWN = frame.CAN_HAVE_CLASSBAR and frame.ComboPoints:IsShown()
+ frame.CLASSBAR_DETACHED = db.combobar.detachFromFrame
+ frame.USE_MINI_CLASSBAR = db.combobar.fill == "spaced" and frame.USE_CLASSBAR
+ frame.CLASSBAR_HEIGHT = frame.USE_CLASSBAR and db.combobar.height or 0
+ frame.CLASSBAR_WIDTH = frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2) - frame.PORTRAIT_WIDTH - frame.POWERBAR_OFFSET
+ frame.CLASSBAR_YOFFSET = (not frame.USE_CLASSBAR or not frame.CLASSBAR_SHOWN or frame.CLASSBAR_DETACHED) and 0 or (frame.USE_MINI_CLASSBAR and (frame.SPACING+(frame.CLASSBAR_HEIGHT/2)) or (frame.CLASSBAR_HEIGHT + frame.SPACING))
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ frame.colors = ElvUF.colors
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ _G[frame:GetName().."Mover"]:Size(frame:GetSize())
+
+ if not IsAddOnLoaded("Clique") then
+ if db.middleClickFocus then
+ frame:SetAttribute("type3", "focus")
+ elseif frame:GetAttribute("type3") == "focus" then
+ frame:SetAttribute("type3", nil)
+ end
+ end
+
+ UF:Configure_InfoPanel(frame)
+
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --Castbar
+ UF:Configure_Castbar(frame)
+
+ --ComboBar
+ UF:Configure_ComboPoints(frame)
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --Debuff Highlight
+ UF:Configure_DebuffHighlight(frame)
+
+ --OverHealing
+ UF:Configure_HealComm(frame)
+
+ --Raid Icon
+ UF:Configure_RaidIcon(frame)
+
+ --AuraBars
+ UF:Configure_AuraBars(frame)
+
+ --GPS
+ UF:Configure_GPS(frame)
+
+ --PvP
+ UF:Configure_PVPIcon(frame)
+
+ --CustomTexts
+ UF:Configure_CustomTexts(frame)
+
+ E:SetMoverSnapOffset(frame:GetName().."Mover", -(12 + db.castbar.height))
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+tinsert(UF.unitstoload, "target")
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Units/TargetTarget.lua b/ElvUI/Modules/UnitFrames/Units/TargetTarget.lua
new file mode 100644
index 0000000..562e9b0
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Units/TargetTarget.lua
@@ -0,0 +1,109 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local _G = _G
+local tinsert = tinsert
+--WoW API / Variables
+
+function UF:Construct_TargetTargetFrame(frame)
+ frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
+ frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
+ frame.Name = self:Construct_NameText(frame)
+ frame.Portrait3D = self:Construct_Portrait(frame, "model")
+ frame.Portrait2D = self:Construct_Portrait(frame, "texture")
+ frame.Buffs = self:Construct_Buffs(frame)
+ frame.RaidTargetIndicator = self:Construct_RaidIcon(frame)
+ frame.Debuffs = self:Construct_Debuffs(frame)
+ frame.ThreatIndicator = self:Construct_Threat(frame)
+ frame.InfoPanel = self:Construct_InfoPanel(frame)
+ frame.MouseGlow = self:Construct_MouseGlow(frame)
+ frame.TargetGlow = self:Construct_TargetGlow(frame)
+ frame.Fader = self:Construct_Fader()
+ frame.Cutaway = self:Construct_Cutaway(frame)
+ frame.customTexts = {}
+
+ frame:Point("BOTTOM", E.UIParent, "BOTTOM", 0, 75) --Set to default position
+ E:CreateMover(frame, frame:GetName().."Mover", L["TargetTarget Frame"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,targettarget,generalGroup")
+
+ frame.unitframeType = "targettarget"
+end
+
+function UF:Update_TargetTargetFrame(frame, db)
+ frame.db = db
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ frame.colors = ElvUF.colors
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ _G[frame:GetName().."Mover"]:Size(frame:GetSize())
+
+ UF:Configure_InfoPanel(frame)
+
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --Raid Icon
+ UF:Configure_RaidIcon(frame)
+
+ --CustomTexts
+ UF:Configure_CustomTexts(frame)
+
+ E:SetMoverSnapOffset(frame:GetName().."Mover", -(12 + self.db.units.player.castbar.height))
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+tinsert(UF.unitstoload, "targettarget")
\ No newline at end of file
diff --git a/ElvUI/Modules/UnitFrames/Units/TargetTargetTarget.lua b/ElvUI/Modules/UnitFrames/Units/TargetTargetTarget.lua
new file mode 100644
index 0000000..10e7311
--- /dev/null
+++ b/ElvUI/Modules/UnitFrames/Units/TargetTargetTarget.lua
@@ -0,0 +1,106 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local UF = E:GetModule("UnitFrames")
+local _, ns = ...
+local ElvUF = ns.oUF
+assert(ElvUF, "ElvUI was unable to locate oUF.")
+
+--Lua functions
+local _G = _G
+local tinsert = tinsert
+--WoW API / Variables
+
+function UF:Construct_TargetTargetTargetFrame(frame)
+ frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
+ frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
+ frame.Name = self:Construct_NameText(frame)
+ frame.Portrait3D = self:Construct_Portrait(frame, "model")
+ frame.Portrait2D = self:Construct_Portrait(frame, "texture")
+ frame.Buffs = self:Construct_Buffs(frame)
+ frame.RaidTargetIndicator = self:Construct_RaidIcon(frame)
+ frame.Debuffs = self:Construct_Debuffs(frame)
+ frame.ThreatIndicator = self:Construct_Threat(frame)
+ frame.InfoPanel = self:Construct_InfoPanel(frame)
+ frame.MouseGlow = self:Construct_MouseGlow(frame)
+ frame.TargetGlow = self:Construct_TargetGlow(frame)
+ frame.Fader = self:Construct_Fader()
+ frame.Cutaway = self:Construct_Cutaway(frame)
+ frame.customTexts = {}
+
+ frame:Point("BOTTOM", E.UIParent, "BOTTOM", 0, 160) --Set to default position
+ E:CreateMover(frame, frame:GetName().."Mover", L["TargetTargetTarget Frame"], nil, nil, nil, "ALL,SOLO", nil, "unitframe,targettargettarget,generalGroup")
+
+ frame.unitframeType = "targettargettarget"
+end
+
+function UF:Update_TargetTargetTargetFrame(frame, db)
+ frame.db = db
+
+ do
+ frame.ORIENTATION = db.orientation --allow this value to change when unitframes position changes on screen?
+ frame.UNIT_WIDTH = db.width
+ frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
+
+ frame.USE_POWERBAR = db.power.enable
+ frame.POWERBAR_DETACHED = db.power.detachFromFrame
+ frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
+ frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
+ frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
+ frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
+
+ frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
+ frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
+
+ frame.USE_PORTRAIT = db.portrait and db.portrait.enable
+ frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
+ frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
+
+ frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
+ frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
+
+ frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
+
+ frame.VARIABLES_SET = true
+ end
+
+ frame.colors = ElvUF.colors
+ frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
+ frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
+ frame:Size(frame.UNIT_WIDTH, frame.UNIT_HEIGHT)
+ _G[frame:GetName().."Mover"]:Size(frame:GetSize())
+ UF:Configure_InfoPanel(frame)
+ --Health
+ UF:Configure_HealthBar(frame)
+
+ --Name
+ UF:UpdateNameSettings(frame)
+
+ --Power
+ UF:Configure_Power(frame)
+
+ --Portrait
+ UF:Configure_Portrait(frame)
+
+ --Threat
+ UF:Configure_Threat(frame)
+
+ --Auras
+ UF:EnableDisable_Auras(frame)
+ UF:Configure_Auras(frame, "Buffs")
+ UF:Configure_Auras(frame, "Debuffs")
+
+ --Fader
+ UF:Configure_Fader(frame)
+
+ --Cutaway
+ UF:Configure_Cutaway(frame)
+
+ --Raid Icon
+ UF:Configure_RaidIcon(frame)
+
+ UF:Configure_CustomTexts(frame)
+
+ E:SetMoverSnapOffset(frame:GetName().."Mover", -(12 + self.db.units.player.castbar.height))
+ frame:UpdateAllElements("ForceUpdate")
+end
+
+tinsert(UF.unitstoload, "targettargettarget")
\ No newline at end of file
diff --git a/ElvUI/Settings/Filters/Load_Filters.xml b/ElvUI/Settings/Filters/Load_Filters.xml
new file mode 100644
index 0000000..dd470ff
--- /dev/null
+++ b/ElvUI/Settings/Filters/Load_Filters.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Settings/Filters/NamePlate.lua b/ElvUI/Settings/Filters/NamePlate.lua
new file mode 100644
index 0000000..bf59e6c
--- /dev/null
+++ b/ElvUI/Settings/Filters/NamePlate.lua
@@ -0,0 +1,171 @@
+--[[
+ Nameplate Filter
+
+ Add the nameplates name that you do NOT want to see.
+]]
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+G.nameplates.filters = {
+ ElvUI_Boss = {
+ triggers = {
+ level = true,
+ curlevel = -1,
+ nameplateType = {
+ enable = true,
+ enemyNPC = true
+ }
+ },
+ actions = {
+ scale = 1.15
+ }
+ },
+ ElvUI_Totem = {
+ triggers = {
+ totems = {
+ enable = true
+ }
+ },
+ actions = {
+ iconOnly = true
+ }
+ }
+}
+
+E.StyleFilterDefaults = {
+ triggers = {
+ priority = 1,
+ isTarget = false,
+ notTarget = false,
+ level = false,
+ casting = {
+ isCasting = false,
+ isChanneling = false,
+ notCasting = false,
+ notChanneling = false,
+ interruptible = false,
+ notSpell = false,
+ spells = {}
+ },
+ role = {
+ tank = false,
+ healer = false,
+ damager = false
+ },
+ raidTarget = {
+ star = false,
+ circle = false,
+ diamond = false,
+ triangle = false,
+ moon = false,
+ square = false,
+ cross = false,
+ skull = false
+ },
+ curlevel = 0,
+ maxlevel = 0,
+ minlevel = 0,
+ healthThreshold = false,
+ healthUsePlayer = false,
+ underHealthThreshold = 0,
+ overHealthThreshold = 0,
+ powerThreshold = false,
+ underPowerThreshold = 0,
+ overPowerThreshold = 0,
+ names = {},
+ nameplateType = {
+ enable = false,
+ friendlyPlayer = false,
+ friendlyNPC = false,
+ enemyPlayer = false,
+ enemyNPC = false
+ },
+ reactionType = {
+ enabled = false,
+ hostile = false,
+ neutral = false,
+ friendly = false
+ },
+ instanceType = {
+ none = false,
+ sanctuary = false,
+ party = false,
+ raid = false,
+ arena = false,
+ pvp = false
+ },
+ instanceDifficulty = {
+ dungeon = {
+ normal = false,
+ heroic = false
+ },
+ raid = {
+ normal = false,
+ heroic = false
+ }
+ },
+ cooldowns = {
+ names = {},
+ mustHaveAll = false
+ },
+ buffs = {
+ mustHaveAll = false,
+ missing = false,
+ names = {},
+ minTimeLeft = 0,
+ maxTimeLeft = 0
+ },
+ debuffs = {
+ mustHaveAll = false,
+ missing = false,
+ names = {},
+ minTimeLeft = 0,
+ maxTimeLeft = 0
+ },
+ totems = {
+ enable = false,
+ a1 = true, a2 = true, a3 = true, a4 = true, a5 = true,
+ e1 = true, e2 = true, e3 = true, e4 = true, e5 = true, e6 = true,
+ f1 = true, f2 = true, f3 = true, f4 = true, f5 = true, f6 = true,
+ w1 = true, w2 = true, w3 = true, w4 = true, w5 = true,
+ o1 = true
+ },
+ uniqueUnits = {
+ enable = false,
+ u1 = true, u2 = true
+ },
+ inCombat = false,
+ outOfCombat = false
+ },
+ actions = {
+ color = {
+ health = false,
+ border = false,
+ name = false,
+ healthColor = {r = 1, g = 1, b = 1, a = 1},
+ borderColor = {r = 1, g = 1, b = 1, a = 1},
+ nameColor = {r = 1, g = 1, b = 1, a = 1}
+ },
+ texture = {
+ enable = false,
+ texture = "ElvUI Norm"
+ },
+ flash = {
+ enable = false,
+ color = {r = 1, g = 1, b = 1, a = 1},
+ speed = 4
+ },
+ hide = false,
+ nameOnly = false,
+ icon = false,
+ iconOnly = false,
+ scale = 1.0,
+ alpha = -1
+ }
+}
+
+G.nameplates.specialFilters = {
+ Personal = true,
+ nonPersonal = true,
+ blockNonPersonal = true,
+ blockNoDuration = true
+}
\ No newline at end of file
diff --git a/ElvUI/Settings/Filters/UnitFrame.lua b/ElvUI/Settings/Filters/UnitFrame.lua
new file mode 100644
index 0000000..3395402
--- /dev/null
+++ b/ElvUI/Settings/Filters/UnitFrame.lua
@@ -0,0 +1,610 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+--Lua functions
+local print, unpack = print, unpack
+--WoW API / Variables
+local GetSpellInfo = GetSpellInfo
+
+local function SpellName(id)
+ local name = GetSpellInfo(id)
+ if not name then
+ print("|cff1784d1ElvUI:|r SpellID is not valid: "..id..". Please check for an updated version, if none exists report to ElvUI author.")
+ return "Impale"
+ else
+ return name
+ end
+end
+
+local function Defaults(priorityOverride)
+ return {
+ enable = true,
+ priority = priorityOverride or 0,
+ stackThreshold = 0
+ }
+end
+
+G.unitframe.aurafilters = {}
+
+-- These are debuffs that are some form of CC
+G.unitframe.aurafilters.CCDebuffs = {
+ type = "Whitelist",
+ spells = {
+ -- Death Knight
+ [SpellName(47476)] = Defaults(), -- Strangulate
+ [SpellName(51209)] = Defaults(), -- Hungering Cold
+ -- Druid
+ [SpellName(99)] = Defaults(), -- Demoralizing Roar
+ [SpellName(339)] = Defaults(), -- Entangling Roots
+ [SpellName(2637)] = Defaults(), -- Hibernate
+ [SpellName(5211)] = Defaults(), -- Bash
+ [SpellName(9005)] = Defaults(), -- Pounce
+ [SpellName(22570)] = Defaults(), -- Maim
+ [SpellName(33786)] = Defaults(), -- Cyclone
+ [SpellName(45334)] = Defaults(), -- Feral Charge Effect
+ -- Hunter
+ [SpellName(1513)] = Defaults(), -- Scare Beast
+ [SpellName(3355)] = Defaults(), -- Freezing Trap Effect
+ [SpellName(19386)] = Defaults(), -- Wyvern Sting
+ [SpellName(19503)] = Defaults(), -- Scatter Shot
+ [SpellName(24394)] = Defaults(), -- Intimidation
+ [SpellName(34490)] = Defaults(), -- Silencing Shot
+ [SpellName(50245)] = Defaults(), -- Pin
+ [SpellName(50519)] = Defaults(), -- Sonic Blast
+ [SpellName(50541)] = Defaults(), -- Snatch
+ [SpellName(54706)] = Defaults(), -- Venom Web Spray
+ [SpellName(56626)] = Defaults(), -- Sting
+ [SpellName(60210)] = Defaults(), -- Freezing Arrow Effect
+ [SpellName(64803)] = Defaults(), -- Entrapment
+ -- Mage
+ [SpellName(118)] = Defaults(), -- Polymorph (Sheep)
+ [SpellName(122)] = Defaults(), -- Frost Nova
+ [SpellName(18469)] = Defaults(), -- Silenced - Improved Counterspell (Rank 1)
+ [SpellName(31589)] = Defaults(), -- Slow
+ [SpellName(31661)] = Defaults(), -- Dragon's Breath
+ [SpellName(33395)] = Defaults(), -- Freeze
+ [SpellName(44572)] = Defaults(), -- Deep Freeze
+ [SpellName(55080)] = Defaults(), -- Shattered Barrier
+ [SpellName(61305)] = Defaults(), -- Polymorph (Black Cat)
+ [SpellName(55021)] = Defaults(), -- Silenced - Improved Counterspell (Rank 2)
+ -- Paladin
+ [SpellName(853)] = Defaults(), -- Hammer of Justice
+ [SpellName(10326)] = Defaults(), -- Turn Evil
+ [SpellName(20066)] = Defaults(), -- Repentance
+ [SpellName(31935)] = Defaults(), -- Avenger's Shield
+ -- Priest
+ [SpellName(605)] = Defaults(), -- Mind Control
+ [SpellName(8122)] = Defaults(), -- Psychic Scream
+ [SpellName(9484)] = Defaults(), -- Shackle Undead
+ [SpellName(15487)] = Defaults(), -- Silence
+ [SpellName(64044)] = Defaults(), -- Psychic Horror
+ -- Rogue
+ [SpellName(408)] = Defaults(), -- Kidney Shot
+ [SpellName(1330)] = Defaults(), -- Garrote - Silence
+ [SpellName(1776)] = Defaults(), -- Gouge
+ [SpellName(1833)] = Defaults(), -- Cheap Shot
+ [SpellName(2094)] = Defaults(), -- Blind
+ [SpellName(6770)] = Defaults(), -- Sap
+ [SpellName(18425)] = Defaults(), -- Silenced - Improved Kick
+ [SpellName(51722)] = Defaults(), -- Dismantle
+ -- Shaman
+ [SpellName(3600)] = Defaults(), -- Earthbind
+ [SpellName(8056)] = Defaults(), -- Frost Shock
+ [SpellName(39796)] = Defaults(), -- Stoneclaw Stun
+ [SpellName(51514)] = Defaults(), -- Hex
+ [SpellName(63685)] = Defaults(), -- Freeze
+ [SpellName(64695)] = Defaults(), -- Earthgrab
+ -- Warlock
+ [SpellName(710)] = Defaults(), -- Banish
+ [SpellName(5782)] = Defaults(), -- Fear
+ [SpellName(6358)] = Defaults(), -- Seduction
+ [SpellName(6789)] = Defaults(), -- Death Coil
+ [SpellName(17928)] = Defaults(), -- Howl of Terror
+ [SpellName(24259)] = Defaults(), -- Spell Lock
+ [SpellName(30283)] = Defaults(), -- Shadowfury
+ -- Warrior
+ [SpellName(676)] = Defaults(), -- Disarm
+ [SpellName(7922)] = Defaults(), -- Charge Stun
+ [SpellName(18498)] = Defaults(), -- Silenced - Gag Order
+ [SpellName(20511)] = Defaults(), -- Intimidating Shout
+ -- Racial
+ [SpellName(25046)] = Defaults(), -- Arcane Torrent
+ [SpellName(20549)] = Defaults(), -- War Stomp
+ -- The Lich King
+ [SpellName(73787)] = Defaults(), -- Necrotic Plague
+ }
+}
+
+G.unitframe.aurafilters.TurtleBuffs = {
+ type = "Whitelist",
+ spells = {
+ -- Mage
+ [SpellName(45438)] = Defaults(5), -- Ice Block
+ -- Death Knight
+ [SpellName(48707)] = Defaults(5), -- Anti-Magic Shell
+ [SpellName(48792)] = Defaults(), -- Icebound Fortitude
+ [SpellName(49039)] = Defaults(), -- Lichborne
+ [SpellName(50461)] = Defaults(), -- Anti-Magic Zone
+ [SpellName(55233)] = Defaults(), -- Vampiric Blood
+ -- Priest
+ [SpellName(33206)] = Defaults(3), -- Pain Suppression
+ [SpellName(47585)] = Defaults(5), -- Dispersion
+ [SpellName(47788)] = Defaults(), -- Guardian Spirit
+ -- Warlock
+
+ -- Druid
+ [SpellName(22812)] = Defaults(2), -- Barkskin
+ [SpellName(61336)] = Defaults(), -- Survival Instincts
+ -- Hunter
+ [SpellName(19263)] = Defaults(5), -- Deterrence
+ [SpellName(53480)] = Defaults(), -- Roar of Sacrifice
+ -- Rogue
+ [SpellName(5277)] = Defaults(5), -- Evasion
+ [SpellName(31224)] = Defaults(), -- Cloak of Shadows
+ [SpellName(45182)] = Defaults(), -- Cheating Death
+ -- Shaman
+ [SpellName(30823)] = Defaults(), -- Shamanistic Rage
+ -- Paladin
+ [SpellName(498)] = Defaults(2), -- Divine Protection
+ [SpellName(642)] = Defaults(5), -- Divine Shield
+ [SpellName(1022)] = Defaults(5), -- Hand of Protection
+ [SpellName(6940)] = Defaults(), -- Hand of Sacrifice
+ [SpellName(31821)] = Defaults(3), -- Aura Mastery
+ -- Warrior
+ [SpellName(871)] = Defaults(3), -- Shield Wall
+ [SpellName(55694)] = Defaults(), -- Enraged Regeneration
+ }
+}
+
+G.unitframe.aurafilters.PlayerBuffs = {
+ type = "Whitelist",
+ spells = {
+ -- Mage
+ [SpellName(12042)] = Defaults(), -- Arcane Power
+ [SpellName(12051)] = Defaults(), -- Evocation
+ [SpellName(12472)] = Defaults(), -- Icy Veins
+ [SpellName(32612)] = Defaults(), -- Invisibility
+ [SpellName(45438)] = Defaults(), -- Ice Block
+ -- Death Knight
+ [SpellName(48707)] = Defaults(), -- Anti-Magic Shell
+ [SpellName(48792)] = Defaults(), -- Icebound Fortitude
+ [SpellName(49016)] = Defaults(), -- Hysteria
+ [SpellName(49039)] = Defaults(), -- Lichborne
+ [SpellName(49222)] = Defaults(), -- Bone Shield
+ [SpellName(50461)] = Defaults(), -- Anti-Magic Zone
+ [SpellName(51271)] = Defaults(), -- Unbreakable Armor
+ [SpellName(55233)] = Defaults(), -- Vampiric Blood
+ -- Priest
+ [SpellName(6346)] = Defaults(), -- Fear Ward
+ [SpellName(10060)] = Defaults(), -- Power Infusion
+ [SpellName(27827)] = Defaults(), -- Spirit of Redemption
+ [SpellName(33206)] = Defaults(), -- Pain Suppression
+ [SpellName(47585)] = Defaults(), -- Dispersion
+ [SpellName(47788)] = Defaults(), -- Guardian Spirit
+ -- Warlock
+
+ -- Druid
+ [SpellName(1850)] = Defaults(), -- Dash
+ [SpellName(22812)] = Defaults(), -- Barkskin
+ [SpellName(52610)] = Defaults(), -- Savage Roar
+ -- Hunter
+ [SpellName(3045)] = Defaults(), -- Rapid Fire
+ [SpellName(5384)] = Defaults(), -- Feign Death
+ [SpellName(19263)] = Defaults(), -- Deterrence
+ [SpellName(53480)] = Defaults(), -- Roar of Sacrifice (Cunning)
+ [SpellName(54216)] = Defaults(), -- Master's Call
+ -- Rogue
+ [SpellName(2983)] = Defaults(), -- Sprint
+ [SpellName(5277)] = Defaults(), -- Evasion
+ [SpellName(11327)] = Defaults(), -- Vanish
+ [SpellName(13750)] = Defaults(), -- Adrenaline Rush
+ [SpellName(31224)] = Defaults(), -- Cloak of Shadows
+ [SpellName(45182)] = Defaults(), -- Cheating Death
+ -- Shaman
+ [SpellName(2825)] = Defaults(), -- Bloodlust
+ [SpellName(8178)] = Defaults(), -- Grounding Totem Effect
+ [SpellName(16166)] = Defaults(), -- Elemental Mastery
+ [SpellName(16188)] = Defaults(), -- Nature's Swiftness
+ [SpellName(16191)] = Defaults(), -- Mana Tide
+ [SpellName(30823)] = Defaults(), -- Shamanistic Rage
+ [SpellName(32182)] = Defaults(), -- Heroism
+ [SpellName(58875)] = Defaults(), -- Spirit Walk
+ -- Paladin
+ [SpellName(498)] = Defaults(), -- Divine Protection
+ [SpellName(1022)] = Defaults(), -- Hand of Protection
+ [SpellName(1044)] = Defaults(), -- Hand of Freedom
+ [SpellName(6940)] = Defaults(), -- Hand of Sacrifice
+ [SpellName(31821)] = Defaults(), -- Aura Mastery
+ [SpellName(31842)] = Defaults(), -- Divine Illumination
+ [SpellName(31850)] = Defaults(), -- Ardent Defender
+ [SpellName(31884)] = Defaults(), -- Avenging Wrath
+ [SpellName(53563)] = Defaults(), -- Beacon of Light
+ -- Warrior
+ [SpellName(871)] = Defaults(), -- Shield Wall
+ [SpellName(1719)] = Defaults(), -- Recklessness
+ [SpellName(3411)] = Defaults(), -- Intervene
+ [SpellName(12292)] = Defaults(), -- Death Wish
+ [SpellName(12975)] = Defaults(), -- Last Stand
+ [SpellName(18499)] = Defaults(), -- Berserker Rage
+ [SpellName(23920)] = Defaults(), -- Spell Reflection
+ [SpellName(46924)] = Defaults(), -- Bladestorm
+ -- Racial
+ [SpellName(20594)] = Defaults(), -- Stoneform
+ [SpellName(59545)] = Defaults(), -- Gift of the Naaru
+ [SpellName(20572)] = Defaults(), -- Blood Fury
+ [SpellName(26297)] = Defaults(), -- Berserking
+ }
+}
+
+-- Buffs that really we dont need to see
+G.unitframe.aurafilters.Blacklist = {
+ type = "Blacklist",
+ spells = {
+ [6788] = Defaults(), -- Weakened Soul
+ [SpellName(8326)] = Defaults(), -- Ghost
+ [15007] = Defaults(), -- Resurrection Sickness
+ [23445] = Defaults(), -- Evil Twin
+ [24755] = Defaults(), -- Tricked or Treated
+ [25771] = Defaults(), -- Forbearance
+ [26013] = Defaults(), -- Deserter
+ [SpellName(36032)] = Defaults(), -- Arcane Blast
+ [SpellName(36893)] = Defaults(), -- Transporter Malfunction
+ [36900] = Defaults(), -- Soul Split: Evil!
+ [36901] = Defaults(), -- Soul Split: Good
+ [41425] = Defaults(), -- Hypothermia
+ [55711] = Defaults(), -- Weakened Heart
+ [57723] = Defaults(), -- Exhaustion
+ [57724] = Defaults(), -- Sated
+ [58539] = Defaults(), -- Watcher's Corpse
+ [SpellName(67604)] = Defaults(), -- Powering Up
+ [69127] = Defaults(), -- Chill of the Throne
+ [71041] = Defaults(), -- Dungeon Deserter
+ -- Festergut
+ [SpellName(70852)] = Defaults(), -- Malleable Goo
+ [72144] = Defaults(), -- Orange Blight Residue
+ [SpellName(73034)] = Defaults(), -- Blighted Spores
+ -- Rotface
+ [72145] = Defaults(), -- Green Blight Residue
+ -- Professor Putricide
+ [SpellName(72460)] = Defaults(), -- Choking Gas
+ [SpellName(72511)] = Defaults(), -- Mutated Transformation
+ -- Blood Prince Council
+ [SpellName(71911)] = Defaults(), -- Shadow Resonance
+ },
+}
+
+--[[
+ This should be a list of important buffs that we always want to see when they are active
+ bloodlust, paladin hand spells, raid cooldowns, etc..
+]]
+G.unitframe.aurafilters.Whitelist = {
+ type = "Whitelist",
+ spells = {
+ [SpellName(1022)] = Defaults(), -- Hand of Protection
+ [SpellName(1490)] = Defaults(), -- Curse of the Elements
+ [SpellName(2825)] = Defaults(), -- Bloodlust
+ [SpellName(12051)] = Defaults(), -- Evocation
+ [SpellName(18708)] = Defaults(), -- Fel Domination
+ [SpellName(29166)] = Defaults(), -- Innervate
+ [SpellName(31821)] = Defaults(), -- Aura Mastery
+ [SpellName(32182)] = Defaults(), -- Heroism
+ [SpellName(47788)] = Defaults(), -- Guardian Spirit
+ [SpellName(54428)] = Defaults(), -- Divine Plea
+ -- Turtling abilities
+ [SpellName(871)] = Defaults(), -- Shield Wall
+ [SpellName(19263)] = Defaults(), -- Deterrence
+ [SpellName(22812)] = Defaults(), -- Barkskin
+ [SpellName(31224)] = Defaults(), -- Cloak of Shadows
+ [SpellName(33206)] = Defaults(), -- Pain Suppression
+ [SpellName(48707)] = Defaults(), -- Anti-Magic Shell
+ -- Immunities
+ [SpellName(642)] = Defaults(), -- Divine Shield
+ [SpellName(45438)] = Defaults(), -- Ice Block
+ -- Offensive
+ [SpellName(12292)] = Defaults(), -- Death Wish
+ [SpellName(31884)] = Defaults(), -- Avenging Wrath
+ [SpellName(34471)] = Defaults(), -- The Beast Within
+ }
+}
+
+-- RAID DEBUFFS: This should be pretty self explainitory
+G.unitframe.aurafilters.RaidDebuffs = {
+ type = "Whitelist",
+ spells = {
+ -- Naxxramas
+ -- Anub'Rekhan
+ [SpellName(54022)] = Defaults(), -- Locust Swarm
+ -- Grand Widow Faerlina
+ [SpellName(54098)] = Defaults(), -- Poison Bolt Volley
+ -- Maexxna
+ [SpellName(54121)] = Defaults(), -- Necrotic Poison
+ [SpellName(54125)] = Defaults(), -- Web Spray
+ -- Gluth
+ [SpellName(29306)] = Defaults(), -- Infected Wound
+ [SpellName(54378)] = Defaults(), -- Mortal Wound
+ -- Gothik the Harvester
+ [SpellName(27825)] = Defaults(), -- Shadow Mark
+ [SpellName(28679)] = Defaults(), -- Harvest Soul
+ [SpellName(55645)] = Defaults(), -- Death Plague
+ -- The Four Horsemem
+ [SpellName(28832)] = Defaults(), -- Mark of Korth'azz
+ [SpellName(28833)] = Defaults(), -- Mark of Blaumeux
+ [SpellName(28834)] = Defaults(), -- Mark of Rivendare
+ [SpellName(28835)] = Defaults(), -- Mark of Zeliek
+ [SpellName(57369)] = Defaults(), -- Unholy Shadow
+ -- Noth the Plaguebringer
+ [SpellName(29212)] = Defaults(), -- Cripple
+ [SpellName(29213)] = Defaults(), -- Curse of the Plaguebringer
+ [SpellName(29214)] = Defaults(), -- Wrath of the Plaguebringer
+ -- Heigan the Unclean
+ [SpellName(29310)] = Defaults(), -- Spell Disruption
+ [SpellName(29998)] = Defaults(), -- Decrepit Fever
+ -- Loatheb
+ [SpellName(55052)] = Defaults(), -- Inevitable Doom
+ [SpellName(55053)] = Defaults(), -- Deathbloom
+ -- Sapphiron
+ [SpellName(28522)] = Defaults(), -- Icebolt
+ [SpellName(55665)] = Defaults(), -- Life Drain
+ [SpellName(55699)] = Defaults(), -- Chill
+ -- Kel'Thuzad
+ [SpellName(28410)] = Defaults(), -- Chains of Kel'Thuzad
+ [SpellName(27819)] = Defaults(), -- Detonate Mana
+ [SpellName(27808)] = Defaults(), -- Frost Blast
+
+ -- Ulduar
+ -- Ignis the Furnace Master
+ [SpellName(62717)] = Defaults(), -- Slag Pot
+
+ -- XT-002
+ [SpellName(63024)] = Defaults(), -- Gravity Bomb
+ [SpellName(63018)] = Defaults(), -- Light Bomb
+
+ -- The Assembly of Iron
+ [SpellName(61903)] = Defaults(), -- Fusion Punch
+ [SpellName(61912)] = Defaults(), -- Static Disruption
+
+ -- Kologarn
+ [SpellName(64290)] = Defaults(), -- Stone Grip
+
+ -- Thorim
+ [SpellName(62130)] = Defaults(), -- Unbalancing Strike
+
+ -- Yogg-Saron
+ [SpellName(63134)] = Defaults(), -- Sara's Blessing
+ [SpellName(64157)] = Defaults(), -- Curse of Doom
+
+ -- Algalon
+ [SpellName(64412)] = Defaults(), -- Phase Punch
+
+ -- Trial of the Crusader
+ -- Beast of Northrend
+ -- Gormok the Impaler
+ [SpellName(66331)] = Defaults(), -- Impale
+ [SpellName(66406)] = Defaults(), -- Snowbolled!
+ -- Jormungar Behemoth
+ [SpellName(66869)] = Defaults(), -- Burning Bile
+ [SpellName(67618)] = Defaults(), -- Paralytic Toxin
+ -- Icehowl
+ [SpellName(66689)] = Defaults(), -- Arctic Breathe
+
+ -- Lord Jaraxxus
+ [SpellName(66237)] = Defaults(), -- Incinerate Flesh
+ [SpellName(66197)] = Defaults(), -- Legion Flame
+
+ -- Faction Champions
+ [SpellName(65812)] = Defaults(), -- Unstable Affliction
+
+ -- The Twin Val'kyr
+ [SpellName(67309)] = Defaults(), -- Twin Spike
+
+ -- Anub'arak
+ [SpellName(66013)] = Defaults(), -- Penetrating Cold
+ [SpellName(67574)] = Defaults(), -- Pursued by Anub'arak
+ [SpellName(67847)] = Defaults(), -- Expose Weakness
+
+ -- Icecrown Citadel
+ -- Lord Marrowgar
+ [SpellName(69065)] = Defaults(), -- Impaled
+
+ -- Lady Deathwhisper
+ [SpellName(72109)] = Defaults(), -- Death and Decay
+ [SpellName(71289)] = Defaults(), -- Dominate Mind
+ [SpellName(71237)] = Defaults(), -- Curse of Torpor
+
+ -- Deathbringer Saurfang
+ [SpellName(72293)] = Defaults(), -- Mark of the Fallen Champion
+ [SpellName(72442)] = Defaults(), -- Boiling Blood
+ [SpellName(72449)] = Defaults(), -- Rune of Blood
+ [SpellName(72769)] = Defaults(), -- Scent of Blood
+
+ -- Festergut
+ [SpellName(71218)] = Defaults(), -- Vile Gas
+ [SpellName(72219)] = Defaults(), -- Gastric Bloat
+ [SpellName(69279)] = Defaults(), -- Gas Spore
+
+ -- Rotface
+ [SpellName(71224)] = Defaults(), -- Mutated Infection
+
+ -- Professor Putricide
+ [SpellName(71278)] = Defaults(), -- Choking Gas Bomb
+ [SpellName(70215)] = Defaults(), -- Gaseous Bloat
+ [SpellName(72549)] = Defaults(), -- Malleable Goo
+ [SpellName(70953)] = Defaults(), -- Plague Sickness
+ [SpellName(72856)] = Defaults(), -- Unbound Plague
+ [SpellName(70447)] = Defaults(), -- Volatile Ooze Adhesive
+
+ -- Blood Prince Council
+ [SpellName(72796)] = Defaults(), -- Glittering Sparks
+ [SpellName(71822)] = Defaults(), -- Shadow Resonance
+
+ -- Blood-Queen Lana'thel
+ [SpellName(72265)] = Defaults(), -- Delirious Slash
+ [SpellName(71473)] = Defaults(), -- Essence of the Blood Queen
+ [SpellName(71474)] = Defaults(), -- Frenzied Bloodthirst
+ [SpellName(71340)] = Defaults(), -- Pact of the Darkfallen
+ [SpellName(71265)] = Defaults(), -- Swarming Shadows
+ [SpellName(70923)] = Defaults(), -- Uncontrollable Frenzy
+
+ -- Valithria Dreamwalker
+ [SpellName(71733)] = Defaults(), -- Acid Burst
+ [SpellName(71738)] = Defaults(), -- Corrosion
+ [SpellName(70873)] = Defaults(), -- Emerald Vigor
+ [SpellName(71283)] = Defaults(), -- Gut Spray
+
+ -- Sindragosa
+ [SpellName(70106)] = Defaults(), -- Chilled to the Bone
+ [SpellName(70126)] = Defaults(), -- Frost Beacon
+ [SpellName(70157)] = Defaults(), -- Ice Tomb
+ [SpellName(69766)] = Defaults(), -- Instability
+ [SpellName(69762)] = Defaults(), -- Unchained Magic
+
+ -- The Lich King
+ [SpellName(72762)] = Defaults(), -- Defile
+ [SpellName(70541)] = Defaults(), -- Infest
+ [SpellName(70337)] = Defaults(), -- Necrotic plague
+ [SpellName(72149)] = Defaults(), -- Shockwave
+ [SpellName(69409)] = Defaults(), -- Soul Reaper
+ [SpellName(69242)] = Defaults(), -- Soul Shriek
+
+ -- The Ruby Sanctum
+ -- Trash
+ -- Baltharus the Warborn
+ [SpellName(75887)] = Defaults(), -- Blazing Aura
+ [SpellName(74502)] = Defaults(), -- Enervating Brand
+ -- General Zarithrian
+ [SpellName(74367)] = Defaults(), -- Cleave Armor
+
+ -- Halion
+ [SpellName(74562)] = Defaults(), -- Fiery Combustion
+ [SpellName(74567)] = Defaults(), -- Mark of Combustion
+ [SpellName(74792)] = Defaults(), -- Soul Consumption
+ [SpellName(74795)] = Defaults(), -- Mark of Consumption
+ },
+}
+
+--Spells that we want to show the duration backwards
+E.ReverseTimer = {
+
+}
+
+-- BuffWatch: List of personal spells to show on unitframes as icon
+local function ClassBuff(id, point, xOffset, yOffset, color, anyUnit, onlyShowMissing, style, displayText, decimalThreshold, textColor, textThreshold, sizeOverride)
+ local r, g, b = unpack(color)
+
+ local r2, g2, b2 = 1, 1, 1
+ if textColor then
+ r2, g2, b2 = unpack(textColor)
+ end
+
+ return {
+ enabled = true,
+ id = id,
+ point = point,
+ color = {r = r, g = g, b = b},
+ anyUnit = anyUnit,
+ onlyShowMissing = onlyShowMissing,
+ style = style or "coloredIcon",
+ displayText = displayText or false,
+ decimalThreshold = decimalThreshold or 5,
+ textColor = {r = r2, g = g2, b = b2},
+ textThreshold = textThreshold or -1,
+ xOffset = xOffset or 0,
+ yOffset = yOffset or 0,
+ sizeOverride = sizeOverride or 0
+ }
+end
+
+local OFFSET_X, OFFSET_Y = 12, 12 -- Highly recommend textured indicators.
+G.unitframe.buffwatch = {
+ HERO = {
+ [6788] = ClassBuff(6788, "TOPLEFT", 0, 0, {1, 0, 0}, true), -- Weakened Soul
+ [10060] = ClassBuff(10060, "RIGHT", 0, 0, {0.89, 0.09, 0.05}), -- Power Infusion
+ [48066] = ClassBuff(48066, "BOTTOMRIGHT", 0, 0, {0.81, 0.85, 0.1}, true), -- Power Word: Shield
+ [48068] = ClassBuff(48068, "BOTTOMLEFT", 0, 0, {0.4, 0.7, 0.2}), -- Renew
+ [48111] = ClassBuff(48111, "TOPRIGHT", 0, 0, {0.2, 0.7, 0.2}), -- Prayer of Mending
+ [48441] = ClassBuff(48441, "TOPRIGHT", -OFFSET_X, 0, {0.8, 0.4, 0.8}), -- Rejuvenation
+ [48443] = ClassBuff(48443, "BOTTOMLEFT", OFFSET_X, 0, {0.2, 0.8, 0.2}), -- Regrowth
+ [48451] = ClassBuff(48451, "TOPLEFT", OFFSET_X, 0, {0.4, 0.8, 0.2}), -- Lifebloom
+ [53251] = ClassBuff(53251, "BOTTOMRIGHT", -OFFSET_X, 0, {0.8, 0.4, 0}), -- Wild Growth
+
+ -- All hand-buffs have same default location.
+ [1038] = ClassBuff(1038, "BOTTOMRIGHT", 0, OFFSET_Y, {0.9, 0.78, 0}, true), -- Hand of Salvation
+ [1044] = ClassBuff(1044, "BOTTOMRIGHT", 0, OFFSET_Y, {0.86, 0.45, 0}, true), -- Hand of Freedom
+ [6940] = ClassBuff(6940, "BOTTOMRIGHT", 0, OFFSET_Y, {0.89, 0.09, 0.05}, true), -- Hand of Sacrifice
+ [10278] = ClassBuff(10278, "BOTTOMRIGHT", 0, OFFSET_Y, {0.2, 0.2, 1}, true), -- Hand of Protection
+
+ [53563] = ClassBuff(53563, "TOPLEFT", 0, -OFFSET_Y, {0.7, 0.3, 0.7}), -- Beacon of Light
+ [53601] = ClassBuff(53601, "TOPRIGHT", 0, -OFFSET_Y, {0.4, 0.7, 0.2}), -- Sacred Shield
+ [16237] = ClassBuff(16237, "BOTTOMLEFT", 0, OFFSET_Y, {0.4, 0.7, 0.2}), -- Ancestral Fortitude
+ [49284] = ClassBuff(49284, "TOPRIGHT", 0, -OFFSET_Y, {0.2, 0.7, 0.2}), -- Earth Shield
+ [52000] = ClassBuff(52000, "BOTTOMRIGHT", 0, OFFSET_Y, {0.7, 0.4, 0}), -- Earthliving
+ [61301] = ClassBuff(61301, "TOPLEFT", OFFSET_X, -OFFSET_Y, {0.7, 0.3, 0.7}), -- Riptide
+ [57933] = ClassBuff(57933, "TOPRIGHT", -OFFSET_X, -OFFSET_Y, {0.89, 0.09, 0.05}), -- Tricks of the Trade
+ [54646] = ClassBuff(54646, "TOPRIGHT", 0, -2 * OFFSET_Y, {0.2, 0.2, 1}), -- Focus Magic
+ [3411] = ClassBuff(3411, "TOPRIGHT", -OFFSET_X, -2 * OFFSET_Y, {0.89, 0.09, 0.05}), -- Intervene
+ [59665] = ClassBuff(59665, "TOPLEFT", 2 * OFFSET_X, 0, {0.2, 0.2, 1}), -- Vigilance
+ [49016] = ClassBuff(49016, "TOPRIGHT", 0, -3 * OFFSET_Y, {0.89, 0.09, 0.05}) -- Hysteria
+ },
+ PET = {
+ [1539] = ClassBuff(1539, "TOPLEFT", 0, 0, {0.81, 0.85, 0.1}, true), -- Feed Pet
+ [48990] = ClassBuff(48990, "TOPRIGHT", 0, 0, {0.2, 0.8, 0.2}, true) -- Mend Pet
+ },
+}
+
+-- Profile specific BuffIndicator
+P.unitframe.filters = {
+ buffwatch = {}
+}
+
+-- Ticks
+G.unitframe.ChannelTicks = {
+ -- Warlock
+ [SpellName(1120)] = 5, -- Drain Soul
+ [SpellName(689)] = 5, -- Drain Life
+ [SpellName(5138)] = 5, -- Drain Mana
+ [SpellName(5740)] = 4, -- Rain of Fire
+ [SpellName(755)] = 10, -- Health Funnel
+ [SpellName(1949)] = 15, -- Hellfire
+ -- Druid
+ [SpellName(44203)] = 4, -- Tranquility
+ [SpellName(16914)] = 10, -- Hurricane
+ -- Priest
+ [SpellName(15407)] = 3, -- Mind Flay
+ [SpellName(48045)] = 5, -- Mind Sear
+ [SpellName(47540)] = 3, -- Penance
+ [SpellName(64843)] = 4, -- Divine Hymn
+ [SpellName(64901)] = 4, -- Hymn of Hope
+ -- Mage
+ [SpellName(5143)] = 5, -- Arcane Missiles
+ [SpellName(10)] = 8, -- Blizzard
+ [SpellName(12051)] = 4, -- Evocation
+ -- Hunter
+ [SpellName(58434)] = 6, -- Volley
+ -- Death Knight
+ [SpellName(42650)] = 8, -- Army of the Dead
+}
+
+-- This should probably be the same as the whitelist filter + any personal class ones that may be important to watch
+G.unitframe.AuraBarColors = {
+ [SpellName(2825)] = {r = 0.98, g = 0.57, b = 0.10}, -- Bloodlust
+ [SpellName(32182)] = {r = 0.98, g = 0.57, b = 0.10}, -- Heroism
+}
+
+G.unitframe.DebuffHighlightColors = {
+ [25771] = {enable = false, style = "FILL", color = {r = 0.85, g = 0, b = 0, a = 0.85}}, -- Forbearance
+}
+
+G.unitframe.specialFilters = {
+ -- Whitelists
+ Personal = true,
+ nonPersonal = true,
+ CastByUnit = true,
+ notCastByUnit = true,
+ Dispellable = true,
+ notDispellable = true,
+
+ -- Blacklists
+ blockNonPersonal = true,
+ blockNoDuration = true,
+ blockDispellable = true,
+ blockNotDispellable = true,
+}
\ No newline at end of file
diff --git a/ElvUI/Settings/Global.lua b/ElvUI/Settings/Global.lua
new file mode 100644
index 0000000..0d88b49
--- /dev/null
+++ b/ElvUI/Settings/Global.lua
@@ -0,0 +1,220 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+--Global Settings
+G.general = {
+ UIScale = 0.7111111111111111,
+ version = 6.10,
+ versionCheck = true,
+ locale = "auto",
+ eyefinity = false,
+ ignoreScalePopup = false,
+ smallerWorldMap = true,
+ fadeMapWhenMoving = true,
+ mapAlphaWhenMoving = 0.35,
+ AceGUI = {
+ width = 1000,
+ height = 720
+ },
+ WorldMapCoordinates = {
+ enable = true,
+ position = "BOTTOMLEFT",
+ xOffset = 0,
+ yOffset = 0
+ }
+}
+
+G.classtimer = {}
+
+G.chat = {
+ classColorMentionExcludedNames = {},
+}
+
+G.bags = {
+ ignoredItems = {},
+}
+
+G.nameplates = {}
+
+G.unitframe = {
+ aurafilters = {},
+ buffwatch = {},
+ raidDebuffIndicator = {
+ instanceFilter = "RaidDebuffs",
+ otherFilter = "CCDebuffs",
+ },
+ spellRangeCheck = {
+ HERO = {
+ enemySpells = {
+ [5246] = true, -- Intimidating Shout (8 yards)
+ [20271] = true, -- Judgement of Light (10 yards)
+ [53408] = true, -- Judgement of Wisdom (10 yards)
+ [53407] = true, -- Judgement of Justice (10 yards)
+ [2094] = true, -- Blind (10 yards)
+ [2136] = true, -- Fire Blast (20 yards)
+ [33786] = true, -- Cyclone (20 yards)
+ [51514] = true, -- Hex (20 yards)
+ [5782] = true, -- Fear (25 yards)
+ [8056] = true, -- Frost Shock (25 yards)
+ [100] = true, -- Charge (25 yards)
+ [49376] = true, -- Feral Charge (25 yards)
+ },
+ longEnemySpells = {
+ [8042] = true, -- Earth Shock (30 yards)
+ [8050] = true, -- Flame Shock (30 yards)
+ [5176] = true, -- Wrath (30 yards)
+ [589] = true, -- Shadow Word: Pain (30 yards)
+ [879] = true, -- Exorcism (30 yards)
+ [403] = true, -- Lightning Bolt (30 yards)
+ [686] = true, -- Shadow Bolt (30 yards)
+ [49576] = true, -- Death Grip (30 yards)
+ [2948] = true, -- Scorch (30 yards)
+ [116] = true, -- Frostbolt (30 yards)
+ [133] = true, -- Fireball (30 yards)
+ [5143] = true, -- Arcane Missiles (30 yards)
+ [12826] = true, -- Polymorph (30 yards)
+ [8092] = true, -- Mind Blast (30 yards)
+ [585] = true, -- Smite (30 yards)
+ [26679] = true, -- Deadly Throw (30 yards)
+ [355] = true, -- Taunt (30 yards)
+ [75] = true, -- Auto Shot (35 yards)
+ [44614] = true, -- Frostfire Bolt (40 yards)
+ },
+ friendlySpells = {
+ [57934] = true, -- Tricks of the Trade (20 yards)
+ [3411] = true, -- Intervene (25 yards)
+ [5697] = true, -- Unending Breath (30 yards)
+ [5185] = true, -- Healing Touch (40 yards)
+ [774] = true, -- Rejuvenation (40 yards)
+ [8936] = true, -- Regrowth (40 yards)
+ [635] = true, -- Holy Light (40 yards)
+ [19750] = true, -- Flash of Light (40 yards)
+ [2050] = true, -- Greater Heal (40 yards)
+ [139] = true, -- Renew (40 yards)
+ [2061] = true, -- Flash Heal (40 yards)
+ [17] = true, -- Power Word: Shield (40 yards)
+ [331] = true, -- Healing Wave (40 yards)
+ [8004] = true, -- Lesser Healing Wave (40 yards)
+ [475] = true, -- Remove Curse (40 yards)
+ [4987] = true, -- Cleanse (40 yards)
+ [47541] = true, -- Death Coil (40 yards)
+ },
+ resSpells = {
+ [50769] = true, -- Revive (30 yards)
+ [20484] = true, -- Rebirth (30 yards)
+ [2006] = true, -- Resurrection (30 yards)
+ [7328] = true, -- Redemption (30 yards)
+ [2008] = true, -- Ancestral Spirit (30 yards)
+ [61999] = true, -- Raise Ally (30 yards)
+ },
+ petSpells = {
+ [53271] = true, -- Master's Call (25 yards)
+ [755] = true, -- Health Funnel (45 yards)
+ [136] = true, -- Mend Pet (45 yards)
+ [34026] = true, -- Kill Command (45 yards)
+ },
+ },
+ }
+}
+
+
+G.profileCopy = {
+ --Specific values
+ selected = "Minimalistic",
+ movers = {},
+ --Modules
+ actionbar = {
+ general = true,
+ bar1 = true,
+ bar2 = true,
+ bar3 = true,
+ bar4 = true,
+ bar5 = true,
+ bar6 = true,
+ barPet = true,
+ stanceBar = true,
+ microbar = true,
+ cooldown = true
+ },
+ auras = {
+ general = true,
+ buffs = true,
+ debuffs = true,
+ cooldown = true
+ },
+ bags = {
+ general = true,
+ split = true,
+ vendorGrays = true,
+ bagBar = true,
+ cooldown = true
+ },
+ chat = {
+ general = true
+ },
+ cooldown = {
+ general = true,
+ fonts = true
+ },
+ databars = {
+ experience = true,
+ reputation = true
+ },
+ datatexts = {
+ general = true,
+ panels = true
+ },
+ general = {
+ general = true,
+ minimap = true,
+ threat = true,
+ totems = true
+ },
+ nameplates = {
+ general = true,
+ cooldown = true,
+ reactions = true,
+ threat = true,
+ units = {
+ FRIENDLY_PLAYER = true,
+ ENEMY_PLAYER = true,
+ FRIENDLY_NPC = true,
+ ENEMY_NPC = true
+ }
+ },
+ tooltip = {
+ general = true,
+ visibility = true,
+ healthBar = true
+ },
+ unitframe = {
+ general = true,
+ cooldown = true,
+ colors = {
+ general = true,
+ power = true,
+ reaction = true,
+ healPrediction = true,
+ classResources = true,
+ frameGlow = true,
+ debuffHighlight = true
+ },
+ units = {
+ player = true,
+ target = true,
+ targettarget = true,
+ targettargettarget = true,
+ focus = true,
+ focustarget = true,
+ pet = true,
+ pettarget = true,
+ boss = true,
+ arena = true,
+ party = true,
+ raid = true,
+ raid40 = true,
+ raidpet = true,
+ tank = true,
+ assist = true
+ }
+ }
+}
\ No newline at end of file
diff --git a/ElvUI/Settings/Load_Config.xml b/ElvUI/Settings/Load_Config.xml
new file mode 100644
index 0000000..f9136f7
--- /dev/null
+++ b/ElvUI/Settings/Load_Config.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI/Settings/Private.lua b/ElvUI/Settings/Private.lua
new file mode 100644
index 0000000..c91a9ee
--- /dev/null
+++ b/ElvUI/Settings/Private.lua
@@ -0,0 +1,146 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+--Locked Settings, These settings are stored for your character only regardless of profile options.
+
+V.general = {
+ loot = true,
+ lootRoll = true,
+ normTex = "ElvUI Norm",
+ glossTex = "ElvUI Norm",
+ dmgfont = "PT Sans Narrow",
+ namefont = "PT Sans Narrow",
+ chatBubbles = "backdrop",
+ chatBubbleFont = "PT Sans Narrow",
+ chatBubbleFontSize = 14,
+ chatBubbleFontOutline = "NONE",
+ chatBubbleName = false,
+ pixelPerfect = true,
+ replaceBlizzFonts = true,
+ minimap = {
+ enable = true,
+ hideCalendar = true,
+ },
+ classColorMentionsSpeech = true,
+ raidUtility = true,
+ reminder = {
+ classtype = "Caster"
+ }
+}
+
+V.bags = {
+ enable = true,
+ bagBar = false
+}
+
+V.nameplates = {
+ enable = true,
+}
+
+V.auras = {
+ enable = true,
+ disableBlizzard = true,
+
+ lbf = {
+ enable = false,
+ skin = "Blizzard"
+ }
+}
+
+V.chat = {
+ enable = true
+}
+
+V.skins = {
+ ace3 = {
+ enable = true
+ },
+ checkBoxSkin = true,
+ dropdownCheckBoxSkin = false,
+ parchmentRemover = {
+ enable = false,
+ },
+ blizzard = {
+ enable = true,
+ achievement = true,
+ alertframes = true,
+ arena = true,
+ arenaregistrar = true,
+ auctionhouse = true,
+ bags = true,
+ barber = true,
+ bgmap = true,
+ bgscore = true,
+ binding = true,
+ BlizzardOptions = true,
+ calendar = true,
+ character = true,
+ debug = true,
+ dressingroom = true,
+ friends = true,
+ gbank = true,
+ glyph = true,
+ gmchat = true,
+ gossip = true,
+ greeting = true,
+ guildregistrar = true,
+ help = true,
+ inspect = true,
+ lfd = true,
+ lfr = true,
+ loot = true,
+ lootRoll = true,
+ macro = true,
+ mail = true,
+ merchant = true,
+ misc = true,
+ petition = true,
+ pvp = true,
+ quest = true,
+ raid = true,
+ socket = true,
+ spellbook = true,
+ stable = true,
+ tabard = true,
+ talent = true,
+ taxi = true,
+ tooltip = true,
+ timemanager = true,
+ trade = true,
+ tradeskill = true,
+ trainer = true,
+ tutorial = true,
+ watchframe = true,
+ worldmap = true,
+ mirrorTimers = true,
+ WorldStateFrame = true
+ }
+}
+
+V.tooltip = {
+ enable = true,
+}
+
+V.unitframe = {
+ enable = true,
+ disabledBlizzardFrames = {
+ player = true,
+ target = true,
+ focus = true,
+ boss = true,
+ arena = true,
+ party = true,
+ }
+}
+
+V.actionbar = {
+ enable = true,
+
+ lbf = {
+ enable = false,
+ skin = "Blizzard",
+ }
+}
+
+V.worldmap = {
+ enable = true
+}
\ No newline at end of file
diff --git a/ElvUI/Settings/Profile.lua b/ElvUI/Settings/Profile.lua
new file mode 100644
index 0000000..bd56bf5
--- /dev/null
+++ b/ElvUI/Settings/Profile.lua
@@ -0,0 +1,4336 @@
+local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+
+P.gridSize = 64
+P.farmSize = 340
+
+--Core
+P.general = {
+ messageRedirect = DEFAULT_CHAT_FRAME:GetName(),
+ smoothingAmount = 0.33,
+ taintLog = false,
+ stickyFrames = true,
+ loginmessage = true,
+ interruptAnnounce = "NONE",
+ autoRepair = "NONE",
+ autoRoll = false,
+ autoAcceptInvite = false,
+ bottomPanel = true,
+ hideErrorFrame = true,
+ enhancedPvpMessages = true,
+ watchFrameHeight = 480,
+ watchFrameAutoHide = true,
+ vehicleSeatIndicatorSize = 128,
+ afk = true,
+ numberPrefixStyle = "ENGLISH",
+ decimalLength = 1,
+ font = "PT Sans Narrow",
+ fontSize = 12,
+ fontStyle = "OUTLINE",
+ bordercolor = {r = 0, g = 0, b = 0},
+ backdropcolor = {r = 0.1, g = 0.1, b = 0.1},
+ backdropfadecolor = {r = 0.06, g = 0.06, b = 0.06, a = 0.8},
+ valuecolor = {r = 0.99, g = 0.48, b = 0.17},
+ herocolor = {r = 0.0, g = 1.0, b = 0.0},
+ cropIcon = 2,
+ minimap = {
+ size = 176,
+ locationText = "MOUSEOVER",
+ locationFontSize = 12,
+ locationFontOutline = "OUTLINE",
+ locationFont = "PT Sans Narrow",
+ resetZoom = {
+ enable = false,
+ time = 3
+ },
+ icons = {
+ calendar = {
+ scale = 1,
+ position = "TOPRIGHT",
+ xOffset = 0,
+ yOffset = 0,
+ hide = true
+ },
+ mail = {
+ scale = 1,
+ position = "TOPRIGHT",
+ xOffset = 3,
+ yOffset = 4
+ },
+ lfgEye = {
+ scale = 1,
+ position = "BOTTOMRIGHT",
+ xOffset = 3,
+ yOffset = 0
+ },
+ battlefield = {
+ scale = 1,
+ position = "BOTTOMRIGHT",
+ xOffset = 3,
+ yOffset = 0
+ },
+ difficulty = {
+ scale = 1,
+ position = "TOPLEFT",
+ xOffset = 0,
+ yOffset = 0
+ },
+ vehicleLeave = {
+ scale = 1,
+ position = "BOTTOMLEFT",
+ xOffset = 2,
+ yOffset = 2,
+ hide = false
+ }
+ }
+ },
+ threat = {
+ enable = true,
+ position = "RIGHTCHAT",
+ textSize = 12,
+ textOutline = "NONE"
+ },
+ totems = {
+ enable = true,
+ growthDirection = "VERTICAL",
+ sortDirection = "ASCENDING",
+ size = 40,
+ spacing = 4
+ },
+ reminder = {
+ enable = false,
+ durations = true,
+ reverse = true,
+ position = "RIGHT",
+ font = "Homespun",
+ fontSize = 10,
+ fontOutline = "MONOCHROMEOUTLINE"
+ },
+ kittys = false
+}
+
+--DataBars
+P.databars = {
+ experience = {
+ enable = true,
+ width = 10,
+ height = 180,
+ textFormat = "NONE",
+ textSize = 11,
+ font = "PT Sans Narrow",
+ fontOutline = "NONE",
+ mouseover = false,
+ orientation = "VERTICAL",
+ hideAtMaxLevel = true,
+ hideInVehicle = false,
+ hideInCombat = false
+ },
+ reputation = {
+ enable = false,
+ width = 10,
+ height = 180,
+ textFormat = "NONE",
+ textSize = 11,
+ font = "PT Sans Narrow",
+ fontOutline = "NONE",
+ mouseover = false,
+ orientation = "VERTICAL",
+ hideInVehicle = false,
+ hideInCombat = false
+ }
+}
+
+--Bags
+P.bags = {
+ sortInverted = true,
+ bagSize = 34,
+ bankSize = 34,
+ bagWidth = 406,
+ bankWidth = 406,
+ currencyFormat = "ICON_TEXT_ABBR",
+ moneyFormat = "SMART",
+ moneyCoins = true,
+ junkIcon = false,
+ junkDesaturate = true,
+ ignoredItems = {},
+ itemLevel = true,
+ itemLevelThreshold = 1,
+ itemLevelFont = "Homespun",
+ itemLevelFontSize = 10,
+ itemLevelFontOutline = "MONOCHROMEOUTLINE",
+ itemLevelCustomColorEnable = false,
+ itemLevelCustomColor = {r = 1, g = 1, b = 1},
+ countFont = "Homespun",
+ countFontSize = 10,
+ countFontOutline = "MONOCHROMEOUTLINE",
+ countFontColor = {r = 1, g = 1, b = 1},
+ reverseSlots = false,
+ clearSearchOnClose = false,
+ disableBagSort = false,
+ disableBankSort = false,
+ strata = "DIALOG",
+ qualityColors = true,
+ showBindType = false,
+ transparent = false,
+ questIcon = true,
+ professionBagColors = true,
+ questItemColors = true,
+ colors = {
+ profession = {
+ quiver = {r = 1, g = 0.69, b = 0.41},
+ ammoPouch = {r = 1, g = 0.69, b = 0.41},
+ soulBag = {r = 1, g = 0.69, b = 0.41},
+ leatherworking = {r = 0.88, g = 0.73, b = 0.29},
+ inscription = {r = 0.29, g = 0.30, b = 0.88},
+ herbs = {r = 0.07, g = 0.71, b = 0.13},
+ enchanting = {r = 0.76, g = 0.02, b = 0.8},
+ engineering = {r = 0.91, g = 0.46, b = 0.18},
+ gems = {r = 0.03, g = 0.71, b = 0.81},
+ mining = {r = 0.54, g = 0.40, b = 0.04}
+ },
+ items = {
+ questStarter = {r = 1, g = 1, b = 0},
+ questItem = {r = 1, g = 0.30, b = 0.30}
+ }
+ },
+ vendorGrays = {
+ enable = false,
+ interval = 0.2,
+ details = false,
+ progressBar = true
+ },
+ split = {
+ bagSpacing = 5,
+ player = false,
+ bank = false,
+ bag1 = false,
+ bag2 = false,
+ bag3 = false,
+ bag4 = false,
+ bag5 = false,
+ bag6 = false,
+ bag7 = false,
+ bag8 = false,
+ bag9 = false,
+ bag10 = false,
+ bag11 = false
+ },
+ cooldown = {
+ override = false,
+ reverse = false,
+ threshold = 3,
+ expiringColor = {r = 1, g = 0, b = 0},
+ secondsColor = {r = 1, g = 1, b = 1},
+ minutesColor = {r = 1, g = 1, b = 1},
+ hoursColor = {r = 1, g = 1, b = 1},
+ daysColor = {r = 1, g = 1, b = 1},
+ expireIndicator = {r = 1, g = 1, b = 1},
+ secondsIndicator = {r = 1, g = 1, b = 1},
+ minutesIndicator = {r = 1, g = 1, b = 1},
+ hoursIndicator = {r = 1, g = 1, b = 1},
+ daysIndicator = {r = 1, g = 1, b = 1},
+ hhmmColorIndicator = {r = 1, g = 1, b = 1},
+ mmssColorIndicator = {r = 1, g = 1, b = 1},
+
+ checkSeconds = false,
+ hhmmColor = {r = 0.43, g = 0.43, b = 0.43},
+ mmssColor = {r = 0.56, g = 0.56, b = 0.56},
+ hhmmThreshold = -1,
+ mmssThreshold = -1,
+
+ fonts = {
+ enable = false,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 18
+ }
+ },
+ bagBar = {
+ growthDirection = "VERTICAL",
+ sortDirection = "ASCENDING",
+ size = 30,
+ spacing = 4,
+ backdropSpacing = 4,
+ showBackdrop = false,
+ mouseover = false,
+ visibility = ""
+ }
+}
+
+--NamePlate
+P.nameplates = {
+ statusbar = "ElvUI Norm",
+ smoothbars = false,
+ clickThrough = {
+ friendly = false,
+ enemy = false,
+ },
+ plateSize ={
+ friendlyWidth = 150,
+ friendlyHeight = 30,
+ enemyWidth = 150,
+ enemyHeight = 30,
+ },
+ font = "PT Sans Narrow",
+ fontSize = 11,
+ fontOutline = "OUTLINE",
+
+ useTargetScale = true,
+ targetScale = 1.15,
+ nonTargetTransparency = 0.40,
+
+ motionType = "OVERLAP",
+
+ lowHealthThreshold = 0.4,
+
+ showFriendlyCombat = "DISABLED",
+ showEnemyCombat = "DISABLED",
+
+ nameColoredGlow = false,
+ highlight = true,
+
+ cutawayHealth = false,
+ cutawayHealthLength = 0.3,
+ cutawayHealthFadeOutTime = 0.6,
+
+ alwaysShowTargetHealth = true,
+
+ colors = {
+ glowColor = {r = 1, g = 1, b = 1, a = 1},
+ castColor = {r = 1, g = 0.81, b = 0},
+ castNoInterruptColor = {r = 0.78, g = 0.25, b = 0.25},
+ castInterruptedColor = {r = 0.30, g = 0.30, b = 0.30},
+ castbarDesaturate = true,
+ reactions = {
+ friendlyPlayer = {r = 0.31, g = 0.45, b = 0.63},
+ good = {r = .29, g = .68, b = .30},
+ neutral = {r = .85, g = .77, b = .36},
+ bad = {r = 0.78, g = 0.25, b = 0.25},
+ },
+ threat = {
+ goodColor = {r = 75/255, g = 175/255, b = 76/255},
+ badColor = {r = 0.78, g = 0.25, b = 0.25},
+ goodTransition = {r = 218/255, g = 197/255, b = 92/255},
+ badTransition = {r = 235/255, g = 163/255, b = 40/255},
+ },
+ comboPoints = {
+ [1] = {r = .69, g = .31, b = .31},
+ [2] = {r = .69, g = .31, b = .31},
+ [3] = {r = .65, g = .63, b = .35},
+ [4] = {r = .65, g = .63, b = .35},
+ [5] = {r = .33, g = .59, b = .33}
+ }
+ },
+ cooldown = {
+ override = true,
+ reverse = false,
+ threshold = 3,
+ expiringColor = {r = 1, g = 0, b = 0},
+ secondsColor = {r = 1, g = 1, b = 1},
+ minutesColor = {r = 1, g = 1, b = 1},
+ hoursColor = {r = 1, g = 1, b = 1},
+ daysColor = {r = 1, g = 1, b = 1},
+ expireIndicator = {r = 1, g = 1, b = 1},
+ secondsIndicator = {r = 1, g = 1, b = 1},
+ minutesIndicator = {r = 1, g = 1, b = 1},
+ hoursIndicator = {r = 1, g = 1, b = 1},
+ daysIndicator = {r = 1, g = 1, b = 1},
+ hhmmColorIndicator = {r = 1, g = 1, b = 1},
+ mmssColorIndicator = {r = 1, g = 1, b = 1},
+
+ checkSeconds = false,
+ hhmmColor = {r = 0.43, g = 0.43, b = 0.43},
+ mmssColor = {r = 0.56, g = 0.56, b = 0.56},
+ hhmmThreshold = -1,
+ mmssThreshold = -1,
+
+ fonts = {
+ enable = false,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 18
+ }
+ },
+ fadeIn = true,
+ threat = {
+ goodScale = 0.8,
+ badScale = 1.2,
+ useThreatColor = true
+ },
+ filters = {
+ ElvUI_Boss = {triggers = {enable = false}},
+ ElvUI_Totem = {triggers = {enable = true}}
+ },
+ units = {
+ TARGET = {
+ enable = true,
+ glowStyle = "style4",
+ comboPoints = {
+ enable = true,
+ width = 8,
+ height = 4,
+ spacing = 5,
+ xOffset = 0,
+ yOffset = 0
+ },
+ },
+ FRIENDLY_PLAYER = {
+ health = {
+ enable = false,
+ height = 10,
+ width = 150,
+ glowStyle = "TARGET_THREAT",
+ text = {
+ enable = false,
+ format = "CURRENT",
+ position = "CENTER",
+ parent = "Health",
+ xOffset = 0,
+ yOffset = 0,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11,
+ },
+ useClassColor = true,
+ },
+ name = {
+ enable = true,
+ useClassColor = true,
+ abbrev = false,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11
+ },
+ level = {
+ enable = false,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11
+ },
+ castbar = {
+ enable = true,
+ width = 150,
+ height = 8,
+ hideSpellName = false,
+ hideTime = false,
+ textPosition = "BELOW",
+ castTimeFormat = "CURRENT",
+ channelTimeFormat = "CURRENT",
+ timeToHold = 0,
+ iconPosition = "RIGHT",
+ iconSize = 20,
+ iconOffsetX = 2,
+ iconOffsetY = 0,
+ showIcon = true,
+ xOffset = 0,
+ yOffset = -2,
+ font = "PT Sans Narrow",
+ fontSize = 11,
+ fontOutline = "OUTLINE"
+ },
+ buffs = {
+ enable = true,
+ perrow = 6,
+ size = 24,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "TOPLEFT",
+ growthX = "RIGHT",
+ growthY = "UP",
+ spacing = 1,
+ yOffset = 20,
+ xOffset = 0,
+ cooldownOrientation = "VERTICAL",
+ reverseCooldown = false,
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 11,
+ countPosition = "BOTTOMRIGHT",
+ countXOffset = -1,
+ countYOffset = 1,
+ durationFont = "PT Sans Narrow",
+ durationFontOutline = "OUTLINE",
+ durationFontSize = 11,
+ durationPosition = "CENTER",
+ durationXOffset = 0,
+ durationYOffset = 0,
+ filters = {
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,blockNoDuration,Personal,TurtleBuffs" --NamePlate FriendlyPlayer Buffs
+ },
+ },
+ debuffs = {
+ enable = true,
+ perrow = 6,
+ size = 24,
+ numrows = 1,
+ yOffset = 1,
+ xOffset = 0,
+ attachTo = "BUFFS",
+ anchorPoint = "TOPRIGHT",
+ growthX = "LEFT",
+ growthY = "UP",
+ onlyShowPlayer = false,
+ spacing = 1,
+ cooldownOrientation = "VERTICAL",
+ reverseCooldown = false,
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 11,
+ countPosition = "BOTTOMRIGHT",
+ countXOffset = -1,
+ countYOffset = 1,
+ durationFont = "PT Sans Narrow",
+ durationFontOutline = "OUTLINE",
+ durationFontSize = 11,
+ durationPosition = "CENTER",
+ durationXOffset = 0,
+ durationYOffset = 0,
+ filters = {
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,blockNoDuration,Personal,CCDebuffs" --NamePlate FriendlyPlayer Debuffs
+ },
+ },
+ raidTargetIndicator = {
+ size = 24,
+ position = "LEFT",
+ xOffset = -4,
+ yOffset = 0
+ }
+ },
+ ENEMY_PLAYER = {
+ markHealers = true,
+ health = {
+ enable = true,
+ height = 10,
+ width = 150,
+ glowStyle = "TARGET_THREAT",
+ text = {
+ enable = false,
+ format = "CURRENT",
+ position = "CENTER",
+ parent = "Health",
+ xOffset = 0,
+ yOffset = 0,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11
+ },
+ useClassColor = true
+ },
+ name = {
+ enable = true,
+ useClassColor = true,
+ abbrev = false,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11
+ },
+ level = {
+ enable = true,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11
+ },
+ castbar = {
+ enable = true,
+ width = 150,
+ height = 8,
+ hideSpellName = false,
+ hideTime = false,
+ textPosition = "BELOW",
+ castTimeFormat = "CURRENT",
+ channelTimeFormat = "CURRENT",
+ timeToHold = 0,
+ iconPosition = "RIGHT",
+ iconSize = 20,
+ iconOffsetX = 2,
+ iconOffsetY = 0,
+ showIcon = true,
+ xOffset = 0,
+ yOffset = -2,
+ font = "PT Sans Narrow",
+ fontSize = 11,
+ fontOutline = "OUTLINE"
+ },
+ comboPoints = {
+ enable = true,
+ width = 8,
+ height = 4,
+ spacing = 5,
+ xOffset = 0,
+ yOffset = 0
+ },
+ buffs = {
+ enable = true,
+ perrow = 6,
+ size = 24,
+ numrows = 1,
+ yOffset = 20,
+ xOffset = 0,
+ attachTo = "FRAME",
+ anchorPoint = "TOPLEFT",
+ growthX = "RIGHT",
+ growthY = "UP",
+ onlyShowPlayer = false,
+ cooldownOrientation = "VERTICAL",
+ reverseCooldown = false,
+ spacing = 1,
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 11,
+ countPosition = "BOTTOMRIGHT",
+ countXOffset = -1,
+ countYOffset = 1,
+ durationFont = "PT Sans Narrow",
+ durationFontOutline = "OUTLINE",
+ durationFontSize = 11,
+ durationPosition = "CENTER",
+ durationXOffset = 0,
+ durationYOffset = 0,
+ filters = {
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,PlayerBuffs,TurtleBuffs" --NamePlate EnemyPlayer Buffs
+ },
+ },
+ debuffs = {
+ enable = true,
+ perrow = 6,
+ size = 24,
+ numrows = 1,
+ yOffset = 1,
+ xOffset = 0,
+ attachTo = "BUFFS",
+ anchorPoint = "TOPRIGHT",
+ growthX = "LEFT",
+ growthY = "UP",
+ onlyShowPlayer = false,
+ spacing = 1,
+ cooldownOrientation = "VERTICAL",
+ reverseCooldown = false,
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 11,
+ countPosition = "BOTTOMRIGHT",
+ countXOffset = -1,
+ countYOffset = 1,
+ durationFont = "PT Sans Narrow",
+ durationFontOutline = "OUTLINE",
+ durationFontSize = 11,
+ durationPosition = "CENTER",
+ durationXOffset = 0,
+ durationYOffset = 0,
+ filters = {
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,blockNoDuration,Personal,CCDebuffs,RaidDebuffs" --NamePlate EnemyPlayer Debuffs
+ },
+ },
+ raidTargetIndicator = {
+ size = 24,
+ position = "LEFT",
+ xOffset = -4,
+ yOffset = 0
+ },
+ },
+ FRIENDLY_NPC = {
+ health = {
+ enable = false,
+ height = 10,
+ width = 150,
+ glowStyle = "TARGET_THREAT",
+ text = {
+ enable = false,
+ format = "CURRENT",
+ position = "CENTER",
+ parent = "Health",
+ xOffset = 0,
+ yOffset = 0,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11
+ }
+ },
+ name = {
+ enable = true,
+ abbrev = false,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11
+ },
+ level = {
+ enable = true,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11
+ },
+ castbar = {
+ enable = true,
+ width = 150,
+ height = 8,
+ hideSpellName = false,
+ hideTime = false,
+ textPosition = "BELOW",
+ castTimeFormat = "CURRENT",
+ channelTimeFormat = "CURRENT",
+ timeToHold = 0,
+ iconPosition = "RIGHT",
+ iconSize = 20,
+ iconOffsetX = 2,
+ iconOffsetY = 0,
+ showIcon = true,
+ xOffset = 0,
+ yOffset = -2,
+ font = "PT Sans Narrow",
+ fontSize = 11,
+ fontOutline = "OUTLINE"
+ },
+ buffs = {
+ enable = true,
+ perrow = 6,
+ size = 24,
+ numrows = 1,
+ yOffset = 20,
+ xOffset = 0,
+ attachTo = "FRAME",
+ anchorPoint = "TOPLEFT",
+ growthX = "RIGHT",
+ growthY = "UP",
+ onlyShowPlayer = false,
+ spacing = 1,
+ cooldownOrientation = "VERTICAL",
+ reverseCooldown = false,
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 11,
+ countPosition = "BOTTOMRIGHT",
+ countXOffset = -1,
+ countYOffset = 1,
+ durationFont = "PT Sans Narrow",
+ durationFontOutline = "OUTLINE",
+ durationFontSize = 11,
+ durationPosition = "CENTER",
+ durationXOffset = 0,
+ durationYOffset = 0,
+ filters = {
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,blockNoDuration,Personal,TurtleBuffs" --NamePlate FriendlyNPC Buffs
+ },
+ },
+ debuffs = {
+ enable = true,
+ perrow = 6,
+ size = 24,
+ numrows = 1,
+ yOffset = 1,
+ xOffset = 0,
+ attachTo = "BUFFS",
+ anchorPoint = "TOPRIGHT",
+ growthX = "LEFT",
+ growthY = "UP",
+ onlyShowPlayer = false,
+ spacing = 1,
+ cooldownOrientation = "VERTICAL",
+ reverseCooldown = false,
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 11,
+ countPosition = "BOTTOMRIGHT",
+ countXOffset = -1,
+ countYOffset = 1,
+ durationFont = "PT Sans Narrow",
+ durationFontOutline = "OUTLINE",
+ durationFontSize = 11,
+ durationPosition = "CENTER",
+ durationXOffset = 0,
+ durationYOffset = 0,
+ filters = {
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,CCDebuffs,RaidDebuffs" --NamePlate FriendlyNPC Debuffs
+ },
+ },
+ eliteIcon = {
+ enable = false,
+ size = 15,
+ position = "RIGHT",
+ xOffset = 10,
+ yOffset = 0
+ },
+ raidTargetIndicator = {
+ size = 24,
+ position = "LEFT",
+ xOffset = -4,
+ yOffset = 0
+ },
+ iconFrame = {
+ enable = false,
+ size = 24,
+ parent = "Nameplate",
+ position = "CENTER",
+ xOffset = 0,
+ yOffset = 42
+ }
+ },
+ ENEMY_NPC = {
+ health = {
+ enable = true,
+ height = 10,
+ width = 150,
+ glowStyle = "TARGET_THREAT",
+ text = {
+ enable = false,
+ format = "CURRENT",
+ position = "CENTER",
+ parent = "Health",
+ xOffset = 0,
+ yOffset = 0,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11
+ }
+ },
+ name = {
+ enable = true,
+ abbrev = false,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11
+ },
+ level = {
+ enable = true,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 11
+ },
+ castbar = {
+ enable = true,
+ width = 150,
+ height = 8,
+ hideSpellName = false,
+ hideTime = false,
+ textPosition = "BELOW",
+ castTimeFormat = "CURRENT",
+ channelTimeFormat = "CURRENT",
+ timeToHold = 0,
+ iconPosition = "RIGHT",
+ iconSize = 20,
+ iconOffsetX = 2,
+ iconOffsetY = 0,
+ showIcon = true,
+ xOffset = 0,
+ yOffset = -2,
+ font = "PT Sans Narrow",
+ fontSize = 11,
+ fontOutline = "OUTLINE"
+ },
+ comboPoints = {
+ enable = true,
+ width = 8,
+ height = 4,
+ spacing = 5,
+ xOffset = 0,
+ yOffset = 0
+ },
+ buffs = {
+ enable = true,
+ perrow = 6,
+ size = 24,
+ numrows = 1,
+ yOffset = 20,
+ xOffset = 0,
+ attachTo = "FRAME",
+ anchorPoint = "TOPLEFT",
+ growthX = "RIGHT",
+ growthY = "UP",
+ spacing = 1,
+ cooldownOrientation = "VERTICAL",
+ reverseCooldown = false,
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 11,
+ countPosition = "BOTTOMRIGHT",
+ countXOffset = -1,
+ countYOffset = 1,
+ durationFont = "PT Sans Narrow",
+ durationFontOutline = "OUTLINE",
+ durationFontSize = 11,
+ durationPosition = "CENTER",
+ durationXOffset = 0,
+ durationYOffset = 0,
+ filters = {
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,blockNoDuration,PlayerBuffs,TurtleBuffs" --NamePlate EnemyNPC Buffs
+ },
+ },
+ debuffs = {
+ enable = true,
+ perrow = 6,
+ size = 24,
+ numrows = 1,
+ yOffset = 1,
+ xOffset = 0,
+ attachTo = "BUFFS",
+ anchorPoint = "TOPRIGHT",
+ growthX = "LEFT",
+ growthY = "UP",
+ spacing = 1,
+ cooldownOrientation = "VERTICAL",
+ reverseCooldown = false,
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 11,
+ countPosition = "BOTTOMRIGHT",
+ countXOffset = -1,
+ countYOffset = 1,
+ durationFont = "PT Sans Narrow",
+ durationFontOutline = "OUTLINE",
+ durationFontSize = 11,
+ durationPosition = "CENTER",
+ durationXOffset = 0,
+ durationYOffset = 0,
+ filters = {
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,Personal,CCDebuffs" --NamePlate EnemyNPC Debuffs
+ },
+ },
+ eliteIcon = {
+ enable = false,
+ size = 15,
+ position = "RIGHT",
+ xOffset = 10,
+ yOffset = 0
+ },
+ raidTargetIndicator = {
+ size = 24,
+ position = "LEFT",
+ xOffset = -4,
+ yOffset = 0
+ },
+ iconFrame = {
+ enable = false,
+ size = 24,
+ parent = "Nameplate",
+ position = "CENTER",
+ xOffset = 0,
+ yOffset = 42
+ }
+ }
+ }
+}
+
+--Auras
+P.auras = {
+ font = "Homespun",
+ fontOutline = "MONOCHROMEOUTLINE",
+ countYOffset = 0,
+ countXOffset = 0,
+ timeYOffset = 0,
+ timeXOffset = 0,
+ fadeThreshold = 6,
+ showDuration = true,
+ barShow = false,
+ barTexture = "ElvUI Norm",
+ barPosition = "BOTTOM",
+ barWidth = 2,
+ barHeight = 2,
+ barSpacing = 2,
+ barColor = {r = 0, g = .8, b = 0},
+ barColorGradient = false,
+ barNoDuration = true,
+ buffs = {
+ growthDirection = "LEFT_DOWN",
+ wrapAfter = 12,
+ maxWraps = 3,
+ horizontalSpacing = 6,
+ verticalSpacing = 16,
+ sortMethod = "TIME",
+ sortDir = "-",
+ seperateOwn = 1,
+ size = 32,
+ countFontsize = 10,
+ durationFontSize = 10
+ },
+ debuffs = {
+ growthDirection = "LEFT_DOWN",
+ wrapAfter = 12,
+ maxWraps = 1,
+ horizontalSpacing = 6,
+ verticalSpacing = 16,
+ sortMethod = "TIME",
+ sortDir = "-",
+ seperateOwn = 1,
+ size = 32,
+ countFontsize = 10,
+ durationFontSize = 10
+ },
+ cooldown = {
+ override = false,
+ reverse = false,
+ threshold = 3,
+ expiringColor = {r = 1, g = 0, b = 0},
+ secondsColor = {r = 1, g = 1, b = 1},
+ minutesColor = {r = 1, g = 1, b = 1},
+ hoursColor = {r = 1, g = 1, b = 1},
+ daysColor = {r = 1, g = 1, b = 1},
+ expireIndicator = {r = 1, g = 1, b = 1},
+ secondsIndicator = {r = 1, g = 1, b = 1},
+ minutesIndicator = {r = 1, g = 1, b = 1},
+ hoursIndicator = {r = 1, g = 1, b = 1},
+ daysIndicator = {r = 1, g = 1, b = 1},
+ hhmmColorIndicator = {r = 1, g = 1, b = 1},
+ mmssColorIndicator = {r = 1, g = 1, b = 1},
+
+ checkSeconds = false,
+ hhmmColor = {r = 0.43, g = 0.43, b = 0.43},
+ mmssColor = {r = 0.56, g = 0.56, b = 0.56},
+ hhmmThreshold = -1,
+ mmssThreshold = -1
+ }
+}
+
+--Chat
+P.chat = {
+ lockPositions = true,
+ url = true,
+ shortChannels = true,
+ hyperlinkHover = true,
+ throttleInterval = 30,
+ scrollDownInterval = 15,
+ fade = true,
+ inactivityTimer = 120,
+ font = "PT Sans Narrow",
+ fontOutline = "NONE",
+ sticky = true,
+ emotionIcons = true,
+ keywordSound = "None",
+ noAlertInCombat = false,
+ chatHistory = true,
+ maxLines = 128,
+ historySize = 100,
+ editboxHistorySize = 20,
+ channelAlerts = {
+ GUILD = "None",
+ OFFICER = "None",
+ BATTLEGROUND = "None",
+ PARTY = "None",
+ RAID = "None",
+ WHISPER = "Whisper Alert"
+ },
+ showHistory = {
+ WHISPER = true,
+ GUILD = true,
+ OFFICER = true,
+ PARTY = true,
+ RAID = true,
+ BATTLEGROUND = true,
+ CHANNEL = true,
+ SAY = true,
+ YELL = true,
+ EMOTE = true
+ },
+ tabSelector = "NONE",
+ tabSelectedTextEnabled = false,
+ tabSelectedTextColor = {r = 1, g = 1, b = 1},
+ tabSelectorColor = {r = 0.3, g = 1, b = 0.3},
+ timeStampFormat = "NONE",
+ keywords = "ElvUI",
+ separateSizes = false,
+ panelWidth = 412,
+ panelHeight = 180,
+ panelWidthRight = 412,
+ panelHeightRight = 180,
+ panelBackdropNameLeft = "",
+ panelBackdropNameRight = "",
+ panelBackdrop = "SHOWBOTH",
+ panelTabBackdrop = false,
+ panelTabTransparency = false,
+ editBoxPosition = "BELOW_CHAT",
+ fadeUndockedTabs = true,
+ fadeTabsNoBackdrop = true,
+ fadeChatToggles = true,
+ useAltKey = false,
+ classColorMentionsChat = true,
+ numAllowedCombatRepeat = 5,
+ useCustomTimeColor = true,
+ customTimeColor = {r = 0.7, g = 0.7, b = 0.7},
+ numScrollMessages = 3,
+ tabFont = "PT Sans Narrow",
+ tabFontSize = 12,
+ tabFontOutline = "NONE",
+ panelColor = {r = 0.06, g = 0.06, b = 0.06, a = 0.8}
+}
+
+--Datatexts
+P.datatexts = {
+ font = "PT Sans Narrow",
+ fontSize = 12,
+ fontOutline = "NONE",
+ wordWrap = false,
+ panels = {
+ LeftChatDataPanel = {
+ left = "Armor",
+ middle = "Durability",
+ right = "Avoidance"
+ },
+ RightChatDataPanel = {
+ left = "System",
+ middle = "Time",
+ right = "Gold"
+ },
+ LeftMiniPanel = "Guild",
+ RightMiniPanel = "Friends",
+ BottomMiniPanel = "",
+ TopMiniPanel = "",
+ BottomLeftMiniPanel = "",
+ BottomRightMiniPanel = "",
+ TopRightMiniPanel = "",
+ TopLeftMiniPanel = ""
+ },
+ battleground = true,
+ panelTransparency = false,
+ panelBackdrop = true,
+ noCombatClick = false,
+ noCombatHover = false,
+
+ --Datatext Options
+ ---General
+ goldFormat = "BLIZZARD",
+ goldCoins = true,
+ ---Time
+ realmTime = false,
+ timeFormat = "%I:%M",
+ dateFormat = "",
+ ---Friends
+ friends = {
+ --status
+ hideAFK = false,
+ hideDND = false,
+ },
+ --Enabled/Disabled Panels
+ minimapPanels = true,
+ leftChatPanel = true,
+ rightChatPanel = true,
+ minimapTop = false,
+ minimapTopLeft = false,
+ minimapTopRight = false,
+ minimapBottom = false,
+ minimapBottomLeft = false,
+ minimapBottomRight = false
+}
+
+--Tooltip
+P.tooltip = {
+ cursorAnchor = false,
+ cursorAnchorType = "ANCHOR_CURSOR",
+ cursorAnchorX = 0,
+ cursorAnchorY = 0,
+ alwaysShowRealm = false,
+ targetInfo = true,
+ playerTitles = true,
+ guildRanks = true,
+ itemCount = "BAGS_ONLY",
+ spellID = true,
+ npcID = true,
+ inspectInfo = true,
+ font = "PT Sans Narrow",
+ fontOutline = "NONE",
+ headerFontSize = 12,
+ textFontSize = 12,
+ smallTextFontSize = 12,
+ colorAlpha = 0.8,
+ visibility = {
+ unitFrames = "NONE",
+ bags = "NONE",
+ actionbars = "NONE",
+ combat = false,
+ combatOverride = "ALL",
+ },
+ healthBar = {
+ text = true,
+ height = 7,
+ font = "Homespun",
+ fontSize = 10,
+ fontOutline = "OUTLINE",
+ statusPosition = "BOTTOM"
+ },
+ useCustomFactionColors = false,
+ factionColors = {
+ [1] = {r = 0.8, g = 0.3, b = 0.22},
+ [2] = {r = 0.8, g = 0.3, b = 0.22},
+ [3] = {r = 0.75, g = 0.27, b = 0},
+ [4] = {r = 0.9, g = 0.7, b = 0},
+ [5] = {r = 0, g = 0.6, b = 0.1},
+ [6] = {r = 0, g = 0.6, b = 0.1},
+ [7] = {r = 0, g = 0.6, b = 0.1},
+ [8] = {r = 0, g = 0.6, b = 0.1}
+ }
+}
+
+--UnitFrame
+P.unitframe = {
+ smoothbars = false,
+ statusbar = "ElvUI Norm",
+ font = "Homespun",
+ fontSize = 10,
+ fontOutline = "MONOCHROMEOUTLINE",
+ debuffHighlighting = "FILL",
+ smartRaidFilter = true,
+ targetOnMouseDown = false,
+ auraBlacklistModifier = "SHIFT",
+ thinBorders = false,
+ cooldown = {
+ override = true,
+ reverse = false,
+ threshold = 3,
+ expiringColor = {r = 1, g = 0, b = 0},
+ secondsColor = {r = 1, g = 1, b = 1},
+ minutesColor = {r = 1, g = 1, b = 1},
+ hoursColor = {r = 1, g = 1, b = 1},
+ daysColor = {r = 1, g = 1, b = 1},
+ expireIndicator = {r = 1, g = 1, b = 1},
+ secondsIndicator = {r = 1, g = 1, b = 1},
+ minutesIndicator = {r = 1, g = 1, b = 1},
+ hoursIndicator = {r = 1, g = 1, b = 1},
+ daysIndicator = {r = 1, g = 1, b = 1},
+ hhmmColorIndicator = {r = 1, g = 1, b = 1},
+ mmssColorIndicator = {r = 1, g = 1, b = 1},
+
+ checkSeconds = false,
+ hhmmColor = {r = 0.43, g = 0.43, b = 0.43},
+ mmssColor = {r = 0.56, g = 0.56, b = 0.56},
+ hhmmThreshold = -1,
+ mmssThreshold = -1,
+
+ fonts = {
+ enable = false,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 18
+ }
+ },
+ colors = {
+ borderColor = {r = 0, g = 0, b = 0},
+ healthclass = false,
+ forcehealthreaction = false,
+ powerclass = false,
+ colorhealthbyvalue = true,
+ colorhealthbyvalue_threshold = false,
+ colorhealthbyvalue_thresholdgradient = true,
+ customhealthbackdrop = false,
+ custompowerbackdrop = false,
+ customcastbarbackdrop = false,
+ customaurabarbackdrop = false,
+ customclasspowerbackdrop = false,
+ useDeadBackdrop = false,
+ classbackdrop = false,
+ healthMultiplier = 0,
+ auraBarByType = true,
+ auraBarTurtle = true,
+ auraBarTurtleColor = {r = 0.56, g = 0.39, b = 0.61},
+ transparentHealth = false,
+ transparentPower = false,
+ transparentCastbar = false,
+ transparentAurabars = false,
+ transparentClasspower = false,
+ invertCastBar = false,
+ invertAurabars = false,
+ invertPower = false,
+ invertClasspower = false,
+ castColor = {r = 0.31, g = 0.31, b = 0.31},
+ castNoInterrupt = {r = 0.78, g = 0.25, b = 0.25},
+ castClassColor = false,
+ castReactionColor = false,
+ health = {r = 0.31, g = 0.31, b = 0.31},
+ health_backdrop = {r = 0.8, g = 0.01, b = 0.01},
+ health_backdrop_dead = {r = 0.8, g = 0.01, b = 0.01},
+ castbar_backdrop = {r = 0.5, g = 0.5, b = 0.5},
+ classpower_backdrop = {r = 0.5, g = 0.5, b = 0.5},
+ aurabar_backdrop = {r = 0.5, g = 0.5, b = 0.5},
+ power_backdrop = {r = 0.5, g = 0.5, b = 0.5},
+ tapped = {r = 0.55, g = 0.57, b = 0.61},
+ disconnected = {r = 0.84, g = 0.75, b = 0.65},
+ auraBarBuff = {r = 0.31, g = 0.31, b = 0.31},
+ auraBarDebuff = {r = 0.8, g = 0.1, b = 0.1},
+ threshold_20 = {r = 1, g = 0, b = 0},
+ threshold_35 = {r = 1, g = 0, b = 0.8},
+ threshold_50 = {r = 1, g = 0.5, b = 0},
+ threshold_75 = {r = 1, g = 1, b = 0},
+ power = {
+ MANA = {r = 0.31, g = 0.45, b = 0.63},
+ RAGE = {r = 0.78, g = 0.25, b = 0.25},
+ FOCUS = {r = 0.71, g = 0.43, b = 0.27},
+ ENERGY = {r = 0.65, g = 0.63, b = 0.35},
+ RUNIC_POWER = {r = 0, g = 0.82, b = 1}
+ },
+ reaction = {
+ BAD = {r = 0.78, g = 0.25, b = 0.25},
+ NEUTRAL = {r = 0.85, g = 0.77, b = 0.36},
+ GOOD = {r = 0.29, g = 0.68, b = 0.29}
+ },
+ threat = {
+ [ 0] = {r = 0.5, g = 0.5, b = 0.5}, -- low
+ [ 1] = {r = 1.0, g = 1.0, b = 0.5}, -- overnuking
+ [ 2] = {r = 1.0, g = 0.5, b = 0.0}, -- losing threat
+ [ 3] = {r = 1.0, g = 0.2, b = 0.2}, -- tanking securely
+ },
+ healPrediction = {
+ personal = {r = 0, g = 1, b = 0.5, a = 0.25},
+ others = {r = 0, g = 1, b = 0, a = 0.25},
+ maxOverflow = 0
+ },
+ classResources = {
+ comboPoints = {
+ [1] = {r = 0.69, g = 0.31, b = 0.31},
+ [2] = {r = 0.69, g = 0.31, b = 0.31},
+ [3] = {r = 0.65, g = 0.63, b = 0.35},
+ [4] = {r = 0.65, g = 0.63, b = 0.35},
+ [5] = {r = 0.33, g = 0.59, b = 0.33}
+ },
+ DEATHKNIGHT = {
+ [1] = {r = 1, g = 0, b = 0},
+ [2] = {r = 0, g = 1, b = 0},
+ [3] = {r = 0, g = 1, b = 1},
+ [4] = {r = 0.9, g = 0.1, b = 1}
+ }
+ },
+ frameGlow = {
+ mainGlow = {
+ enable = false,
+ class = false,
+ color = {r = 1, g = 1, b = 1, a = 1}
+ },
+ targetGlow = {
+ enable = true,
+ class = true,
+ color = {r = 1, g = 1, b = 1, a = 1}
+ },
+ mouseoverGlow = {
+ enable = true,
+ class = false,
+ texture = "ElvUI Blank",
+ color = {r = 1, g = 1, b = 1, a = 0.1}
+ }
+ },
+ debuffHighlight = {
+ Magic = {r = 0.2, g = 0.6, b = 1, a = 0.45},
+ Curse = {r = 0.6, g = 0, b = 1, a = 0.45},
+ Disease = {r = 0.6, g = 0.4, b = 0, a = 0.45},
+ Poison = {r = 0, g = 0.6, b = 0, a = 0.45},
+ blendMode = "ADD"
+ }
+ },
+ units = {
+ player = {
+ enable = true,
+ orientation = "LEFT",
+ width = 270,
+ height = 54,
+ lowmana = 30,
+ healPrediction = {
+ enable = true
+ },
+ threatStyle = "GLOW",
+ smartAuraPosition = "DISABLED",
+ colorOverride = "USE_DEFAULT",
+ disableMouseoverGlow = false,
+ disableTargetGlow = true,
+ health = {
+ text_format = "[healthcolor][health:current-percent]",
+ position = "LEFT",
+ xOffset = 2,
+ yOffset = 0,
+ attachTextTo = "Health"
+ },
+ fader = {
+ enable = false,
+ --range = true, [player doesnt get this option]
+ hover = true,
+ combat = true,
+ playertarget = true,
+ --unittarget = false, [player doesnt get this option]
+ focus = false,
+ health = true,
+ power = true,
+ vehicle = true,
+ casting = true,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = true,
+ text_format = "[powercolor][power:current]",
+ width = "fill",
+ height = 10,
+ offset = 0,
+ position = "RIGHT",
+ hideonnpc = false,
+ xOffset = -2,
+ yOffset = 0,
+ attachTextTo = "Health",
+ detachFromFrame = false,
+ detachedWidth = 250,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ },
+ parent = "FRAME"
+ },
+ energy = {
+ enable = true,
+ text_format = "[energycolor][energy:current]",
+ width = "fill",
+ height = 10,
+ offset = 0,
+ position = "RIGHT",
+ hideonnpc = false,
+ xOffset = -2,
+ yOffset = 0,
+ attachTextTo = "Health",
+ detachFromFrame = false,
+ detachedWidth = 250,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ },
+ parent = "FRAME"
+ },
+ rage = {
+ enable = true,
+ text_format = "[ragecolor][rage:current]",
+ width = "fill",
+ height = 10,
+ offset = 0,
+ position = "RIGHT",
+ hideonnpc = false,
+ xOffset = -2,
+ yOffset = 0,
+ attachTextTo = "Health",
+ detachFromFrame = false,
+ detachedWidth = 250,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ },
+ parent = "FRAME"
+ },
+ infoPanel = {
+ enable = false,
+ height = 20,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ text_format = "",
+ xOffset = 0,
+ yOffset = 0,
+ attachTextTo = "Health"
+ },
+ pvp = {
+ position = "BOTTOM",
+ text_format = "||cFFB04F4F[pvptimer][mouseover]||r",
+ xOffset = 0,
+ yOffset = 0
+ },
+ RestIcon = {
+ enable = true,
+ defaultColor = true,
+ color = {r = 1, g = 1, b = 1, a = 1},
+ anchorPoint = "TOPLEFT",
+ xOffset = -3,
+ yOffset = 6,
+ size = 22,
+ texture = "DEFAULT"
+ },
+ raidRoleIcons = {
+ enable = true,
+ position = "TOPLEFT"
+ },
+ CombatIcon = {
+ enable = true,
+ defaultColor = true,
+ color = {r = 1, g = 0.2, b = 0.2, a = 1},
+ anchorPoint = "CENTER",
+ xOffset = 0,
+ yOffset = 0,
+ size = 20,
+ texture = "DEFAULT"
+ },
+ pvpIcon = {
+ enable = false,
+ anchorPoint = "CENTER",
+ xOffset = 0,
+ yOffset = 0,
+ scale = 1
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = false,
+ perrow = 8,
+ numrows = 1,
+ attachTo = "DEBUFFS",
+ anchorPoint = "TOPLEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,Personal,PlayerBuffs,Whitelist,blockNoDuration,nonPersonal", --Player Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = true,
+ perrow = 8,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "TOPLEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,Personal,nonPersonal", --Player Debuffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ castbar = {
+ enable = true,
+ width = 270,
+ height = 18,
+ icon = true,
+ latency = true,
+ format = "REMAINING",
+ ticks = true,
+ spark = true,
+ displayTarget = false,
+ iconSize = 42,
+ iconAttached = true,
+ insideInfoPanel = true,
+ iconAttachedTo = "Frame",
+ iconPosition = "LEFT",
+ iconXOffset = -10,
+ iconYOffset = 0,
+ tickWidth = 1,
+ tickColor = {r = 0, g = 0, b = 0, a = 0.8},
+ timeToHold = 0,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ }
+ },
+ classbar = {
+ enable = true,
+ fill = "fill",
+ height = 10,
+ autoHide = false,
+ additionalPowerText = true,
+ detachFromFrame = false,
+ detachedWidth = 250,
+ parent = "FRAME",
+ verticalOrientation = false,
+ orientation = "HORIZONTAL",
+ spacing = 5,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ }
+ },
+ aurabar = {
+ enable = true,
+ anchorPoint = "ABOVE",
+ attachTo = "DEBUFFS",
+ maxBars = 6,
+ minDuration = 0,
+ maxDuration = 120,
+ priority = "Blacklist,blockNoDuration,Personal,RaidDebuffs,PlayerBuffs", --Player AuraBars
+ friendlyAuraType = "HELPFUL",
+ enemyAuraType = "HARMFUL",
+ height = 20,
+ sort = "TIME_REMAINING",
+ uniformThreshold = 0,
+ yOffset = 0,
+ spacing = 0
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ target = {
+ enable = true,
+ width = 270,
+ height = 54,
+ orientation = "RIGHT",
+ threatStyle = "GLOW",
+ smartAuraPosition = "DISABLED",
+ colorOverride = "USE_DEFAULT",
+ healPrediction = {
+ enable = true
+ },
+ middleClickFocus = true,
+ disableMouseoverGlow = false,
+ disableTargetGlow = true,
+ health = {
+ text_format = "[healthcolor][health:current-percent]",
+ position = "RIGHT",
+ xOffset = -2,
+ yOffset = 0,
+ attachTextTo = "Health"
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = true,
+ text_format = "[powercolor][power:current]",
+ width = "fill",
+ height = 10,
+ offset = 0,
+ position = "LEFT",
+ hideonnpc = false,
+ xOffset = 2,
+ yOffset = 0,
+ detachFromFrame = false,
+ detachedWidth = 250,
+ attachTextTo = "Health",
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ },
+ parent = "FRAME"
+ },
+ infoPanel = {
+ enable = false,
+ height = 20,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium] [difficultycolor][smartlevel] [shortclassification]",
+ xOffset = 0,
+ yOffset = 0,
+ attachTextTo = "Health"
+ },
+ pvpIcon = {
+ enable = false,
+ anchorPoint = "CENTER",
+ xOffset = 0,
+ yOffset = 0,
+ scale = 1
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = true,
+ perrow = 8,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "TOPRIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,Personal,nonPersonal", --Target Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = true,
+ perrow = 8,
+ numrows = 1,
+ attachTo = "BUFFS",
+ anchorPoint = "TOPRIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,Personal,RaidDebuffs,CCDebuffs,Friendly:Dispellable", --Target Debuffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ castbar = {
+ enable = true,
+ width = 270,
+ height = 18,
+ icon = true,
+ format = "REMAINING",
+ spark = true,
+ iconSize = 42,
+ iconAttached = true,
+ insideInfoPanel = true,
+ iconAttachedTo = "Frame",
+ iconPosition = "LEFT",
+ iconXOffset = -10,
+ iconYOffset = 0,
+ timeToHold = 0,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ }
+ },
+ combobar = {
+ enable = true,
+ fill = "fill",
+ height = 10,
+ autoHide = true,
+ detachFromFrame = false,
+ detachedWidth = 250,
+ parent = "FRAME",
+ orientation = "HORIZONTAL",
+ spacing = 5,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ }
+ },
+ aurabar = {
+ enable = true,
+ anchorPoint = "ABOVE",
+ attachTo = "DEBUFFS",
+ maxBars = 6,
+ minDuration = 0,
+ maxDuration = 120,
+ priority = "Blacklist,Personal,blockNoDuration,PlayerBuffs,RaidDebuffs", --Target AuraBars
+ friendlyAuraType = "HELPFUL",
+ enemyAuraType = "HARMFUL",
+ height = 20,
+ sort = "TIME_REMAINING",
+ uniformThreshold = 0,
+ yOffset = 0,
+ spacing = 0
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ GPSArrow = {
+ enable = false,
+ size = 45,
+ xOffset = 0,
+ yOffset = 0,
+ onMouseOver = true,
+ outOfRange = true
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ targettarget = {
+ enable = true,
+ threatStyle = "NONE",
+ orientation = "MIDDLE",
+ smartAuraPosition = "DISABLED",
+ colorOverride = "USE_DEFAULT",
+ width = 130,
+ height = 36,
+ disableMouseoverGlow = false,
+ disableTargetGlow = true,
+ health = {
+ text_format = "",
+ position = "RIGHT",
+ xOffset = -2,
+ yOffset = 0
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = true,
+ text_format = "",
+ width = "fill",
+ height = 7,
+ offset = 0,
+ position = "LEFT",
+ hideonnpc = false,
+ xOffset = 2,
+ yOffset = 0
+ },
+ infoPanel = {
+ enable = false,
+ height = 14,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ xOffset = 0,
+ yOffset = 0,
+ attachTextTo = "Health"
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = false,
+ perrow = 7,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "BOTTOMLEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,Personal,PlayerBuffs,Dispellable", --TargetTarget Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = true,
+ perrow = 5,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "BOTTOMRIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,Personal,RaidDebuffs,CCDebuffs,Dispellable,Whitelist", --TargetTarget Debuffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ targettargettarget = {
+ enable = false,
+ orientation = "MIDDLE",
+ threatStyle = "NONE",
+ smartAuraPosition = "DISABLED",
+ colorOverride = "USE_DEFAULT",
+ width = 130,
+ height = 36,
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ health = {
+ text_format = "",
+ position = "RIGHT",
+ xOffset = -2,
+ yOffset = 0
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = true,
+ text_format = "",
+ width = "fill",
+ height = 7,
+ offset = 0,
+ position = "LEFT",
+ hideonnpc = false,
+ xOffset = 2,
+ yOffset = 0
+ },
+ infoPanel = {
+ enable = false,
+ height = 12,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ xOffset = 0,
+ yOffset = 0
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = false,
+ perrow = 7,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "BOTTOMLEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,Personal,nonPersonal", --TargetTargetTarget Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = true,
+ perrow = 5,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "BOTTOMRIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,Personal,nonPersonal", --TargetTargetTarget Debuffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ focus = {
+ enable = true,
+ threatStyle = "GLOW",
+ orientation = "MIDDLE",
+ smartAuraPosition = "DISABLED",
+ colorOverride = "USE_DEFAULT",
+ width = 190,
+ height = 36,
+ healPrediction = {
+ enable = true
+ },
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ health = {
+ text_format = "",
+ position = "RIGHT",
+ xOffset = -2,
+ yOffset = 0,
+ attachTextTo = "Health",
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = true,
+ text_format = "",
+ width = "fill",
+ height = 7,
+ offset = 0,
+ position = "LEFT",
+ hideonnpc = false,
+ xOffset = 2,
+ yOffset = 0,
+ attachTextTo = "Health"
+ },
+ infoPanel = {
+ enable = false,
+ height = 14,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ xOffset = 0,
+ yOffset = 0,
+ attachTextTo = "Health"
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = false,
+ perrow = 7,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "BOTTOMLEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,Personal,PlayerBuffs,CastByUnit,Dispellable", --Focus Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = true,
+ perrow = 5,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "TOPRIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,Personal,RaidDebuffs,Dispellable,Whitelist", --Focus Debuffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ castbar = {
+ enable = true,
+ width = 190,
+ height = 18,
+ icon = true,
+ format = "REMAINING",
+ spark = true,
+ iconSize = 32,
+ iconAttached = true,
+ insideInfoPanel = true,
+ iconAttachedTo = "Frame",
+ iconPosition = "LEFT",
+ iconXOffset = -10,
+ iconYOffset = 0,
+ timeToHold = 0,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ }
+ },
+ aurabar = {
+ enable = false,
+ anchorPoint = "ABOVE",
+ attachTo = "DEBUFFS",
+ maxBars = 3,
+ minDuration = 0,
+ maxDuration = 120,
+ priority = "Blacklist,blockNoDuration,Personal,PlayerBuffs,RaidDebuffs", --Focus AuraBars
+ friendlyAuraType = "HELPFUL",
+ enemyAuraType = "HARMFUL",
+ height = 20,
+ sort = "TIME_REMAINING",
+ uniformThreshold = 0,
+ yOffset = 0,
+ spacing = 0
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ GPSArrow = {
+ enable = true,
+ size = 45,
+ xOffset = 0,
+ yOffset = 0,
+ onMouseOver = true,
+ outOfRange = true
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ focustarget = {
+ enable = false,
+ threatStyle = "NONE",
+ orientation = "MIDDLE",
+ smartAuraPosition = "DISABLED",
+ colorOverride = "USE_DEFAULT",
+ width = 190,
+ height = 26,
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ health = {
+ text_format = "",
+ position = "RIGHT",
+ xOffset = -2,
+ yOffset = 0,
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = false,
+ text_format = "",
+ width = "fill",
+ height = 7,
+ offset = 0,
+ position = "LEFT",
+ hideonnpc = false,
+ xOffset = 2,
+ yOffset = 0
+ },
+ infoPanel = {
+ enable = false,
+ height = 12,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ yOffset = 0,
+ xOffset = 0
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = false,
+ perrow = 7,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "BOTTOMLEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,Personal,PlayerBuffs,Dispellable,CastByUnit", --FocusTarget Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = false,
+ perrow = 5,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "BOTTOMRIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,Personal,RaidDebuffs,Dispellable,Whitelist", --FocusTarget Debuffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ pet = {
+ enable = true,
+ orientation = "MIDDLE",
+ threatStyle = "GLOW",
+ smartAuraPosition = "DISABLED",
+ colorOverride = "USE_DEFAULT",
+ width = 130,
+ height = 36,
+ healPrediction = {
+ enable = true
+ },
+ disableMouseoverGlow = false,
+ disableTargetGlow = true,
+ health = {
+ text_format = "",
+ position = "RIGHT",
+ yOffset = 0,
+ xOffset = -2,
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = true,
+ text_format = "",
+ width = "fill",
+ height = 7,
+ offset = 0,
+ position = "LEFT",
+ hideonnpc = false,
+ yOffset = 0,
+ xOffset = 2
+ },
+ infoPanel = {
+ enable = false,
+ height = 12,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ yOffset = 0,
+ xOffset = 0
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ happiness = {
+ enable = false,
+ autoHide = false,
+ width = 10
+ },
+ buffs = {
+ enable = false,
+ perrow = 7,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "BOTTOMLEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,Personal,PlayerBuffs", --Pet Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = false,
+ perrow = 5,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "BOTTOMRIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,RaidDebuffs,Dispellable,Whitelist", --Pet Debuffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ aurabar = {
+ enable = false,
+ anchorPoint = "ABOVE",
+ attachTo = "FRAME",
+ maxBars = 6,
+ minDuration = 0,
+ maxDuration = 120,
+ priority = "",
+ friendlyAuraType = "HELPFUL",
+ enemyAuraType = "HARMFUL",
+ height = 20,
+ sort = "TIME_REMAINING",
+ uniformThreshold = 0,
+ yOffset = 2,
+ spacing = 2
+ },
+ buffIndicator = {
+ enable = true,
+ size = 8,
+ fontSize = 10
+ },
+ castbar = {
+ enable = true,
+ width = 130,
+ height = 18,
+ icon = true,
+ format = "REMAINING",
+ spark = true,
+ iconSize = 26,
+ iconAttached = true,
+ insideInfoPanel = true,
+ iconAttachedTo = "Frame",
+ iconPosition = "LEFT",
+ iconXOffset = -10,
+ iconYOffset = 0,
+ timeToHold = 0,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ }
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ pettarget = {
+ enable = false,
+ threatStyle = "NONE",
+ orientation = "MIDDLE",
+ smartAuraPosition = "DISABLED",
+ colorOverride = "USE_DEFAULT",
+ width = 130,
+ height = 26,
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ health = {
+ text_format = "",
+ position = "RIGHT",
+ yOffset = 0,
+ xOffset = -2,
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = false,
+ text_format = "",
+ width = "fill",
+ height = 7,
+ offset = 0,
+ position = "LEFT",
+ hideonnpc = false,
+ yOffset = 0,
+ xOffset = 2
+ },
+ infoPanel = {
+ enable = false,
+ height = 12,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ yOffset = 0,
+ xOffset = 0
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = false,
+ perrow = 7,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "BOTTOMLEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,PlayerBuffs,CastByUnit,Whitelist", --PetTarget Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = false,
+ perrow = 5,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "BOTTOMRIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,Personal,RaidDebuffs", --PetTarget Debuffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ boss = {
+ enable = true,
+ growthDirection = "DOWN",
+ orientation = "RIGHT",
+ smartAuraPosition = "DISABLED",
+ colorOverride = "USE_DEFAULT",
+ width = 216,
+ height = 46,
+ spacing = 25,
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ health = {
+ text_format = "[healthcolor][health:current]",
+ position = "LEFT",
+ yOffset = 0,
+ xOffset = 2,
+ attachTextTo = "Health",
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = true,
+ text_format = "[powercolor][power:current]",
+ width = "fill",
+ height = 7,
+ offset = 0,
+ position = "RIGHT",
+ hideonnpc = false,
+ yOffset = 0,
+ xOffset = -2,
+ attachTextTo = "Health"
+ },
+ portrait = {
+ enable = false,
+ width = 35,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ infoPanel = {
+ enable = false,
+ height = 16,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ yOffset = 0,
+ xOffset = 0,
+ attachTextTo = "Health"
+ },
+ buffs = {
+ enable = true,
+ perrow = 3,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "LEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,CastByUnit,Whitelist", --Boss Buffs
+ xOffset = 0,
+ yOffset = 20,
+ sizeOverride = 22
+ },
+ debuffs = {
+ enable = true,
+ perrow = 3,
+ numrows = 2,
+ attachTo = "FRAME",
+ anchorPoint = "LEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,Personal,RaidDebuffs,CastByUnit,Whitelist", --Boss Debuffs
+ xOffset = 0,
+ yOffset = -3,
+ sizeOverride = 22
+ },
+ castbar = {
+ enable = true,
+ width = 215,
+ height = 18,
+ icon = true,
+ format = "REMAINING",
+ spark = true,
+ iconSize = 32,
+ iconAttached = true,
+ insideInfoPanel = true,
+ iconAttachedTo = "Frame",
+ iconPosition = "LEFT",
+ iconXOffset = -10,
+ iconYOffset = 0,
+ timeToHold = 0,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ }
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ arena = {
+ enable = true,
+ growthDirection = "DOWN",
+ orientation = "RIGHT",
+ smartAuraPosition = "DISABLED",
+ spacing = 25,
+ width = 246,
+ height = 47,
+ healPrediction = {
+ enable = true
+ },
+ colorOverride = "USE_DEFAULT",
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ health = {
+ text_format = "[healthcolor][health:current]",
+ position = "LEFT",
+ yOffset = 0,
+ xOffset = 2,
+ attachTextTo = "Health",
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = true,
+ text_format = "[powercolor][power:current]",
+ width = "fill",
+ height = 7,
+ offset = 0,
+ attachTextTo = "Health",
+ position = "RIGHT",
+ hideonnpc = false,
+ yOffset = 0,
+ xOffset = -2
+ },
+ infoPanel = {
+ enable = false,
+ height = 17,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ yOffset = 0,
+ xOffset = 0,
+ attachTextTo = "Health"
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = true,
+ perrow = 3,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "LEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,TurtleBuffs,PlayerBuffs,Dispellable", --Arena Buffs
+ sizeOverride = 27,
+ xOffset = 0,
+ yOffset = 16
+ },
+ debuffs = {
+ enable = true,
+ perrow = 3,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "LEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,blockNoDuration,Personal,CCDebuffs,Whitelist", --Arena Debuffs
+ sizeOverride = 27,
+ xOffset = 0,
+ yOffset = -16
+ },
+ castbar = {
+ enable = true,
+ width = 256,
+ height = 18,
+ icon = true,
+ format = "REMAINING",
+ spark = true,
+ iconSize = 32,
+ iconAttached = true,
+ insideInfoPanel = true,
+ iconAttachedTo = "Frame",
+ iconPosition = "LEFT",
+ iconXOffset = -10,
+ iconYOffset = 0,
+ timeToHold = 0,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ }
+ },
+ pvpTrinket = {
+ enable = true,
+ position = "RIGHT",
+ size = 46,
+ xOffset = 1,
+ yOffset = 0
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ party = {
+ enable = true,
+ threatStyle = "GLOW",
+ orientation = "LEFT",
+ visibility = "[@raid6,exists][nogroup] hide;show",
+ growthDirection = "UP_RIGHT",
+ horizontalSpacing = 0,
+ verticalSpacing = 3,
+ numGroups = 1,
+ groupsPerRowCol = 1,
+ groupBy = "GROUP",
+ sortDir = "ASC",
+ raidWideSorting = false,
+ invertGroupingOrder = false,
+ startFromCenter = false,
+ showPlayer = true,
+ healPrediction = {
+ enable = false
+ },
+ colorOverride = "USE_DEFAULT",
+ width = 184,
+ height = 54,
+ groupSpacing = 0,
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ health = {
+ text_format = "[healthcolor][health:current-percent]",
+ position = "LEFT",
+ orientation = "HORIZONTAL",
+ attachTextTo = "Health",
+ frequentUpdates = false,
+ yOffset = 0,
+ xOffset = 2,
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = true,
+ text_format = "[powercolor][power:current]",
+ attachTextTo = "Health",
+ width = "fill",
+ height = 7,
+ offset = 0,
+ position = "RIGHT",
+ hideonnpc = false,
+ yOffset = 0,
+ xOffset = -2
+ },
+ infoPanel = {
+ enable = false,
+ height = 15,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ attachTextTo = "Health",
+ text_format = "[namecolor][name:medium] [difficultycolor][smartlevel]",
+ yOffset = 0,
+ xOffset = 0,
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = false,
+ perrow = 4,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "LEFT",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,TurtleBuffs", --Party Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = true,
+ perrow = 4,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "RIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,RaidDebuffs,CCDebuffs,Dispellable,Whitelist", --Party Debuffs
+ xOffset = 0,
+ yOffset = 0,
+ sizeOverride = 52
+ },
+ buffIndicator = {
+ enable = true,
+ size = 8,
+ fontSize = 10,
+ profileSpecific = false
+ },
+ rdebuffs = {
+ enable = false,
+ showDispellableDebuff = true,
+ onlyMatchSpellID = false,
+ fontSize = 10,
+ font = "Homespun",
+ fontOutline = "MONOCHROMEOUTLINE",
+ size = 26,
+ xOffset = 0,
+ yOffset = 0,
+ duration = {
+ position = "CENTER",
+ xOffset = 0,
+ yOffset = 0,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ },
+ stack = {
+ position = "BOTTOMRIGHT",
+ xOffset = 0,
+ yOffset = 2,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ }
+ },
+ castbar = {
+ enable = false,
+ width = 256,
+ height = 18,
+ icon = true,
+ format = "REMAINING",
+ spark = true,
+ iconSize = 32,
+ iconAttached = true,
+ insideInfoPanel = true,
+ iconAttachedTo = "Frame",
+ iconPosition = "LEFT",
+ iconXOffset = -10,
+ iconYOffset = 0,
+ timeToHold = 0,
+ strataAndLevel = {
+ useCustomStrata = false,
+ frameStrata = "LOW",
+ useCustomLevel = false,
+ frameLevel = 1
+ }
+ },
+ roleIcon = {
+ enable = true,
+ position = "TOPRIGHT",
+ attachTo = "Health",
+ xOffset = 0,
+ yOffset = 0,
+ size = 15,
+ tank = true,
+ healer = true,
+ damager = true,
+ combatHide = false
+ },
+ raidRoleIcons = {
+ enable = true,
+ position = "TOPLEFT"
+ },
+ petsGroup = {
+ enable = false,
+ width = 100,
+ height = 22,
+ anchorPoint = "TOPLEFT",
+ xOffset = -1,
+ yOffset = 0,
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:short]",
+ yOffset = 0,
+ xOffset = 0
+ }
+ },
+ targetsGroup = {
+ enable = false,
+ width = 100,
+ height = 22,
+ anchorPoint = "TOPLEFT",
+ xOffset = -1,
+ yOffset = 0,
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:short]",
+ yOffset = 0,
+ xOffset = 0
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ }
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ GPSArrow = {
+ enable = true,
+ size = 45,
+ xOffset = 0,
+ yOffset = 0,
+ onMouseOver = true,
+ outOfRange = true
+ },
+ readycheckIcon = {
+ enable = true,
+ size = 12,
+ attachTo = "Health",
+ position = "BOTTOM",
+ xOffset = 0,
+ yOffset = 2
+ },
+ resurrectIcon = {
+ enable = true,
+ size = 30,
+ attachTo = "CENTER",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 0
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ raid = {
+ enable = true,
+ threatStyle = "GLOW",
+ orientation = "MIDDLE",
+ visibility = "[@raid6,noexists][@raid26,exists] hide;show",
+ growthDirection = "RIGHT_DOWN",
+ horizontalSpacing = 3,
+ verticalSpacing = 3,
+ numGroups = 5,
+ groupsPerRowCol = 1,
+ groupBy = "GROUP",
+ sortDir = "ASC",
+ showPlayer = true,
+ healPrediction = {
+ enable = false
+ },
+ colorOverride = "USE_DEFAULT",
+ width = 80,
+ height = 44,
+ groupSpacing = 0,
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ health = {
+ text_format = "[healthcolor][health:deficit]",
+ position = "BOTTOM",
+ orientation = "HORIZONTAL",
+ attachTextTo = "Health",
+ frequentUpdates = false,
+ yOffset = 2,
+ xOffset = 0,
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = true,
+ text_format = "",
+ width = "fill",
+ height = 7,
+ offset = 0,
+ position = "BOTTOMRIGHT",
+ hideonnpc = false,
+ yOffset = 2,
+ xOffset = -2
+ },
+ infoPanel = {
+ enable = false,
+ height = 12,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ attachTextTo = "Health",
+ text_format = "[namecolor][name:short]",
+ yOffset = 0,
+ xOffset = 0
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = false,
+ perrow = 3,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "LEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,TurtleBuffs", --Raid Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = false,
+ perrow = 3,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "RIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,RaidDebuffs,CCDebuffs,Dispellable", --Raid Debuffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ buffIndicator = {
+ enable = true,
+ size = 8,
+ fontSize = 10,
+ profileSpecific = false
+ },
+ rdebuffs = {
+ enable = true,
+ showDispellableDebuff = true,
+ onlyMatchSpellID = false,
+ fontSize = 10,
+ font = "Homespun",
+ fontOutline = "MONOCHROMEOUTLINE",
+ size = 26,
+ xOffset = 0,
+ yOffset = 2,
+ duration = {
+ position = "CENTER",
+ xOffset = 0,
+ yOffset = 0,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ },
+ stack = {
+ position = "BOTTOMRIGHT",
+ xOffset = 0,
+ yOffset = 2,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ }
+ },
+ raidRoleIcons = {
+ enable = true,
+ position = "TOPLEFT"
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ GPSArrow = {
+ enable = true,
+ size = 40,
+ xOffset = 0,
+ yOffset = 0,
+ onMouseOver = true,
+ outOfRange = true
+ },
+ readycheckIcon = {
+ enable = true,
+ size = 12,
+ attachTo = "Health",
+ position = "BOTTOM",
+ xOffset = 0,
+ yOffset = 2
+ },
+ resurrectIcon = {
+ enable = true,
+ size = 30,
+ attachTo = "CENTER",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 0
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ raid40 = {
+ enable = true,
+ threatStyle = "GLOW",
+ orientation = "MIDDLE",
+ visibility = "[@raid26,noexists] hide;show",
+ growthDirection = "RIGHT_DOWN",
+ horizontalSpacing = 3,
+ verticalSpacing = 3,
+ numGroups = 8,
+ groupsPerRowCol = 1,
+ groupBy = "GROUP",
+ sortDir = "ASC",
+ showPlayer = true,
+ healPrediction = {
+ enable = false
+ },
+ colorOverride = "USE_DEFAULT",
+ width = 80,
+ height = 27,
+ groupSpacing = 0,
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ health = {
+ text_format = "[healthcolor][health:deficit]",
+ position = "BOTTOM",
+ orientation = "HORIZONTAL",
+ frequentUpdates = false,
+ attachTextTo = "Health",
+ yOffset = 2,
+ xOffset = 0,
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ power = {
+ enable = false,
+ text_format = "",
+ width = "fill",
+ height = 7,
+ offset = 0,
+ position = "BOTTOMRIGHT",
+ hideonnpc = false,
+ yOffset = 2,
+ xOffset = -2
+ },
+ infoPanel = {
+ enable = false,
+ height = 12,
+ transparent = false
+ },
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:short]",
+ yOffset = 0,
+ xOffset = 0,
+ attachTextTo = "Health"
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = false,
+ perrow = 3,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "LEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,TurtleBuffs", --Raid40 Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = false,
+ perrow = 3,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "RIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 300,
+ priority = "Blacklist,RaidDebuffs,CCDebuffs,Dispellable,Whitelist", --Raid40 Debuffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ rdebuffs = {
+ enable = false,
+ showDispellableDebuff = true,
+ onlyMatchSpellID = false,
+ fontSize = 10,
+ font = "Homespun",
+ fontOutline = "MONOCHROMEOUTLINE",
+ size = 22,
+ xOffset = 0,
+ yOffset = 0,
+ duration = {
+ position = "CENTER",
+ xOffset = 0,
+ yOffset = 0,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ },
+ stack = {
+ position = "BOTTOMRIGHT",
+ xOffset = 0,
+ yOffset = 2,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ }
+ },
+ raidRoleIcons = {
+ enable = true,
+ position = "TOPLEFT"
+ },
+ buffIndicator = {
+ enable = true,
+ size = 8,
+ fontSize = 10,
+ profileSpecific = false
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ GPSArrow = {
+ enable = true,
+ size = 45,
+ xOffset = 0,
+ yOffset = 0,
+ onMouseOver = true,
+ outOfRange = true
+ },
+ readycheckIcon = {
+ enable = true,
+ size = 12,
+ attachTo = "Health",
+ position = "BOTTOM",
+ xOffset = 0,
+ yOffset = 2
+ },
+ resurrectIcon = {
+ enable = true,
+ size = 30,
+ attachTo = "CENTER",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 0
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ raidpet = {
+ enable = false,
+ orientation = "MIDDLE",
+ threatStyle = "GLOW",
+ visibility = "[group:raid] show; hide",
+ growthDirection = "DOWN_RIGHT",
+ horizontalSpacing = 3,
+ verticalSpacing = 3,
+ numGroups = 2,
+ groupsPerRowCol = 1,
+ groupBy = "PETNAME",
+ sortDir = "ASC",
+ raidWideSorting = true,
+ invertGroupingOrder = false,
+ startFromCenter = false,
+ healPrediction = {
+ enable = true
+ },
+ colorOverride = "USE_DEFAULT",
+ width = 80,
+ height = 30,
+ groupSpacing = 0,
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ health = {
+ text_format = "[healthcolor][health:deficit]",
+ position = "BOTTOM",
+ orientation = "HORIZONTAL",
+ frequentUpdates = true,
+ yOffset = 2,
+ xOffset = 0,
+ attachTextTo = "Health",
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ name = {
+ position = "TOP",
+ text_format = "[namecolor][name:short]",
+ yOffset = -2,
+ xOffset = 0,
+ attachTextTo = "Health"
+ },
+ portrait = {
+ enable = false,
+ width = 45,
+ overlay = false,
+ fullOverlay = false,
+ style = "3D",
+ overlayAlpha = 0.35
+ },
+ buffs = {
+ enable = false,
+ perrow = 3,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "LEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,Personal,PlayerBuffs,blockNoDuration,nonPersonal", --RaidPet Buffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ debuffs = {
+ enable = false,
+ perrow = 3,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "RIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "Blacklist,Personal,Whitelist,RaidDebuffs,blockNoDuration,nonPersonal", --RaidPet Debuffs
+ xOffset = 0,
+ yOffset = 0
+ },
+ buffIndicator = {
+ enable = true,
+ size = 8,
+ fontSize = 10,
+ },
+ rdebuffs = {
+ enable = true,
+ showDispellableDebuff = true,
+ onlyMatchSpellID = false,
+ fontSize = 10,
+ font = "Homespun",
+ fontOutline = "MONOCHROMEOUTLINE",
+ size = 26,
+ xOffset = 0,
+ yOffset = 2,
+ duration = {
+ position = "CENTER",
+ xOffset = 0,
+ yOffset = 0,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ },
+ stack = {
+ position = "BOTTOMRIGHT",
+ xOffset = 0,
+ yOffset = 2,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ }
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ tank = {
+ enable = true,
+ orientation = "LEFT",
+ threatStyle = "GLOW",
+ colorOverride = "USE_DEFAULT",
+ width = 120,
+ height = 28,
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ disableDebuffHighlight = true,
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ yOffset = 0,
+ xOffset = 0,
+ attachTextTo = "Health"
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ buffs = {
+ enable = false,
+ perrow = 6,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "TOPLEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "",
+ xOffset = 0,
+ yOffset = 2
+ },
+ debuffs = {
+ enable = false,
+ perrow = 6,
+ numrows = 1,
+ attachTo = "BUFFS",
+ anchorPoint = "TOPRIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "",
+ xOffset = 0,
+ yOffset = 1
+ },
+ buffIndicator = {
+ enable = true,
+ size = 8,
+ fontSize = 10,
+ profileSpecific = false
+ },
+ rdebuffs = {
+ enable = true,
+ showDispellableDebuff = true,
+ onlyMatchSpellID = false,
+ fontSize = 10,
+ font = "Homespun",
+ fontOutline = "MONOCHROMEOUTLINE",
+ size = 26,
+ xOffset = 0,
+ yOffset = 0,
+ duration = {
+ position = "CENTER",
+ xOffset = 0,
+ yOffset = 0,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ },
+ stack = {
+ position = "BOTTOMRIGHT",
+ xOffset = 0,
+ yOffset = 2,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ }
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ targetsGroup = {
+ enable = true,
+ anchorPoint = "RIGHT",
+ xOffset = 1,
+ yOffset = 0,
+ width = 120,
+ height = 28,
+ colorOverride = "USE_DEFAULT",
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ yOffset = 0,
+ xOffset = 0,
+ attachTextTo = "Health"
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ }
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ },
+ assist = {
+ enable = true,
+ orientation = "LEFT",
+ threatStyle = "GLOW",
+ colorOverride = "USE_DEFAULT",
+ width = 120,
+ height = 28,
+ disableMouseoverGlow = false,
+ disableTargetGlow = false,
+ disableDebuffHighlight = true,
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ yOffset = 0,
+ xOffset = 0,
+ attachTextTo = "Health"
+ },
+ fader = {
+ enable = true,
+ range = true,
+ hover = false,
+ combat = false,
+ playertarget = false,
+ unittarget = false,
+ focus = false,
+ health = false,
+ power = false,
+ vehicle = false,
+ casting = false,
+ smooth = 0.33,
+ minAlpha = 0.35,
+ maxAlpha = 1,
+ delay = 0
+ },
+ buffs = {
+ enable = false,
+ perrow = 6,
+ numrows = 1,
+ attachTo = "FRAME",
+ anchorPoint = "TOPLEFT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "",
+ xOffset = 0,
+ yOffset = 2
+ },
+ debuffs = {
+ enable = false,
+ perrow = 6,
+ numrows = 1,
+ attachTo = "BUFFS",
+ anchorPoint = "TOPRIGHT",
+ countFont = "PT Sans Narrow",
+ countFontOutline = "OUTLINE",
+ countFontSize = 12,
+ durationPosition = "CENTER",
+ sortMethod = "TIME_REMAINING",
+ sortDirection = "DESCENDING",
+ clickThrough = false,
+ minDuration = 0,
+ maxDuration = 0,
+ priority = "",
+ xOffset = 0,
+ yOffset = 1
+ },
+ buffIndicator = {
+ enable = true,
+ size = 8,
+ fontSize = 10,
+ profileSpecific = false
+ },
+ rdebuffs = {
+ enable = true,
+ showDispellableDebuff = true,
+ onlyMatchSpellID = false,
+ fontSize = 10,
+ font = "Homespun",
+ fontOutline = "MONOCHROMEOUTLINE",
+ size = 26,
+ xOffset = 0,
+ yOffset = 0,
+ duration = {
+ position = "CENTER",
+ xOffset = 0,
+ yOffset = 0,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ },
+ stack = {
+ position = "BOTTOMRIGHT",
+ xOffset = 0,
+ yOffset = 2,
+ color = {r = 1, g = 0.9, b = 0, a = 1}
+ }
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ },
+ targetsGroup = {
+ enable = true,
+ anchorPoint = "RIGHT",
+ xOffset = 1,
+ yOffset = 0,
+ width = 120,
+ height = 28,
+ colorOverride = "USE_DEFAULT",
+ name = {
+ position = "CENTER",
+ text_format = "[namecolor][name:medium]",
+ yOffset = 0,
+ xOffset = 0,
+ attachTextTo = "Frame"
+ },
+ raidicon = {
+ enable = true,
+ size = 18,
+ attachTo = "TOP",
+ attachToObject = "Frame",
+ xOffset = 0,
+ yOffset = 8
+ }
+ },
+ cutaway = {
+ health = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ },
+ power = {
+ enabled = false,
+ fadeOutTime = 0.6,
+ lengthBeforeFade = 0.3,
+ forceBlankTexture = true
+ }
+ }
+ }
+ }
+}
+
+--Cooldown
+P.cooldown = {
+ enable = true,
+ threshold = 3,
+ expiringColor = {r = 1, g = 0, b = 0},
+ secondsColor = {r = 1, g = 1, b = 0},
+ minutesColor = {r = 1, g = 1, b = 1},
+ hoursColor = {r = 0.4, g = 1, b = 1},
+ daysColor = {r = 0.4, g = 0.4, b = 1},
+ expireIndicator = {r = 1, g = 1, b = 1},
+ secondsIndicator = {r = 1, g = 1, b = 1},
+ minutesIndicator = {r = 1, g = 1, b = 1},
+ hoursIndicator = {r = 1, g = 1, b = 1},
+ daysIndicator = {r = 1, g = 1, b = 1},
+ hhmmColorIndicator = {r = 1, g = 1, b = 1},
+ mmssColorIndicator = {r = 1, g = 1, b = 1},
+
+ checkSeconds = false,
+ hhmmColor = {r = 0.43, g = 0.43, b = 0.43},
+ mmssColor = {r = 0.56, g = 0.56, b = 0.56},
+ hhmmThreshold = -1,
+ mmssThreshold = -1,
+
+ fonts = {
+ enable = false,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 18
+ }
+}
+
+--Actionbar
+P.actionbar = {
+ font = "Homespun",
+ fontSize = 10,
+ fontOutline = "MONOCHROMEOUTLINE",
+ fontColor = {r = 1, g = 1, b = 1},
+
+ macrotext = false,
+ hotkeytext = true,
+
+ hotkeyTextPosition = "TOPRIGHT",
+ hotkeyTextXOffset = 0,
+ hotkeyTextYOffset = -3,
+
+ countTextPosition = "BOTTOMRIGHT",
+ countTextXOffset = 0,
+ countTextYOffset = 2,
+
+ keyDown = true,
+ movementModifier = "SHIFT",
+ transparentBackdrops = false,
+ transparentButtons = false,
+ globalFadeAlpha = 0,
+ lockActionBars = true,
+ rightClickSelfCast = false,
+ desaturateOnCooldown = false,
+
+ equippedItem = false,
+ equippedItemColor = {r = 0.4, g = 1.0, b = 0.4},
+
+ useRangeColorText = false,
+ noRangeColor = {r = 0.8, g = 0.1, b = 0.1},
+ noPowerColor = {r = 0.5, g = 0.5, b = 1},
+ usableColor = {r = 1, g = 1, b = 1},
+ notUsableColor = {r = 0.4, g = 0.4, b = 0.4},
+
+ cooldown = {
+ override = true,
+ threshold = 3,
+ expiringColor = {r = 1, g = 0, b = 0},
+ secondsColor = {r = 1, g = 1, b = 1},
+ minutesColor = {r = 1, g = 1, b = 1},
+ hoursColor = {r = 1, g = 1, b = 1},
+ daysColor = {r = 1, g = 1, b = 1},
+ expireIndicator = {r = 1, g = 1, b = 1},
+ secondsIndicator = {r = 1, g = 1, b = 1},
+ minutesIndicator = {r = 1, g = 1, b = 1},
+ hoursIndicator = {r = 1, g = 1, b = 1},
+ daysIndicator = {r = 1, g = 1, b = 1},
+ hhmmColorIndicator = {r = 1, g = 1, b = 1},
+ mmssColorIndicator = {r = 1, g = 1, b = 1},
+
+ checkSeconds = false,
+ hhmmColor = {r = 0.43, g = 0.43, b = 0.43},
+ mmssColor = {r = 0.56, g = 0.56, b = 0.56},
+ hhmmThreshold = -1,
+ mmssThreshold = -1,
+
+ fonts = {
+ enable = false,
+ font = "PT Sans Narrow",
+ fontOutline = "OUTLINE",
+ fontSize = 18
+ }
+ },
+
+ microbar = {
+ enabled = false,
+ mouseover = false,
+ buttonsPerRow = 10,
+ buttonSize = 20,
+ buttonSpacing = 2,
+ alpha = 1,
+ visibility = "show"
+ },
+ bar1 = {
+ enabled = true,
+ buttons = 12,
+ mouseover = false,
+ buttonsPerRow = 12,
+ point = "BOTTOMLEFT",
+ backdrop = false,
+ heightMult = 1,
+ widthMult = 1,
+ buttonsize = 32,
+ buttonspacing = 2,
+ backdropSpacing = 2,
+ alpha = 1,
+ inheritGlobalFade = false,
+ showGrid = true,
+ paging = {
+ HERO = "[bonusbar:1,nostealth] 7; [bonusbar:1,stealth] 8; [bonusbar:2] 8; [bonusbar:3] 9; [bonusbar:4] 10;",
+ },
+ visibility = ""
+ },
+ bar2 = {
+ enabled = false,
+ mouseover = false,
+ buttons = 12,
+ buttonsPerRow = 12,
+ point = "BOTTOMLEFT",
+ backdrop = false,
+ heightMult = 1,
+ widthMult = 1,
+ buttonsize = 32,
+ buttonspacing = 2,
+ backdropSpacing = 2,
+ alpha = 1,
+ inheritGlobalFade = false,
+ showGrid = true,
+ paging = {},
+ visibility = "[vehicleui] hide;show"
+ },
+ bar3 = {
+ enabled = true,
+ mouseover = false,
+ buttons = 6,
+ buttonsPerRow = 6,
+ point = "BOTTOMLEFT",
+ backdrop = false,
+ heightMult = 1,
+ widthMult = 1,
+ buttonsize = 32,
+ buttonspacing = 2,
+ backdropSpacing = 2,
+ alpha = 1,
+ inheritGlobalFade = false,
+ showGrid = true,
+ paging = {},
+ visibility = "[vehicleui] hide;show"
+ },
+ bar4 = {
+ enabled = true,
+ mouseover = false,
+ buttons = 12,
+ buttonsPerRow = 1,
+ point = "TOPRIGHT",
+ backdrop = true,
+ heightMult = 1,
+ widthMult = 1,
+ buttonsize = 32,
+ buttonspacing = 2,
+ backdropSpacing = 2,
+ alpha = 1,
+ inheritGlobalFade = false,
+ showGrid = true,
+ paging = {},
+ visibility = "[vehicleui] hide;show"
+ },
+ bar5 = {
+ enabled = true,
+ mouseover = false,
+ buttons = 6,
+ buttonsPerRow = 6,
+ point = "BOTTOMLEFT",
+ backdrop = false,
+ heightMult = 1,
+ widthMult = 1,
+ buttonsize = 32,
+ buttonspacing = 2,
+ backdropSpacing = 2,
+ alpha = 1,
+ inheritGlobalFade = false,
+ showGrid = true,
+ paging = {},
+ visibility = "[vehicleui] hide;show"
+ },
+ bar6 = {
+ enabled = false,
+ mouseover = false,
+ buttons = 12,
+ buttonsPerRow = 12,
+ point = "BOTTOMLEFT",
+ backdrop = false,
+ heightMult = 1,
+ widthMult = 1,
+ buttonsize = 32,
+ buttonspacing = 2,
+ backdropSpacing = 2,
+ alpha = 1,
+ inheritGlobalFade = false,
+ showGrid = true,
+ paging = {},
+ visibility = "[vehicleui] hide;show"
+ },
+ barPet = {
+ enabled = true,
+ mouseover = false,
+ buttons = NUM_PET_ACTION_SLOTS,
+ buttonsPerRow = 1,
+ point = "TOPRIGHT",
+ backdrop = true,
+ heightMult = 1,
+ widthMult = 1,
+ buttonsize = 32,
+ buttonspacing = 2,
+ backdropSpacing = 2,
+ alpha = 1,
+ inheritGlobalFade = false,
+ visibility = "[pet,novehicleui,nobonusbar:5] show;hide"
+ },
+ stanceBar = {
+ enabled = true,
+ style = "darkenInactive",
+ mouseover = false,
+ buttonsPerRow = NUM_SHAPESHIFT_SLOTS,
+ buttons = NUM_SHAPESHIFT_SLOTS,
+ point = "TOPLEFT",
+ backdrop = false,
+ heightMult = 1,
+ widthMult = 1,
+ buttonsize = 32,
+ buttonspacing = 2,
+ backdropSpacing = 2,
+ alpha = 1,
+ inheritGlobalFade = false,
+ visibility = "[vehicleui] hide;show"
+ },
+ barTotem = {
+ enabled = true,
+ mouseover = false,
+ flyoutDirection = "UP",
+ buttonsize = 32,
+ buttonspacing = 2,
+ flyoutSpacing = 2,
+ alpha = 1,
+ visibility = "[vehicleui] hide;show"
+ }
+}
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/ActionBars.lua b/ElvUI_OptionsUI/ActionBars.lua
new file mode 100644
index 0000000..0373db6
--- /dev/null
+++ b/ElvUI_OptionsUI/ActionBars.lua
@@ -0,0 +1,1133 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+local AB = E:GetModule("ActionBars")
+local group
+
+local _G = _G
+local pairs = pairs
+
+local SetCVar = SetCVar
+local GameTooltip = _G.GameTooltip
+
+local points = {
+ TOPLEFT = L["Top Left"],
+ TOPRIGHT = L["Top Right"],
+ BOTTOMLEFT = L["Bottom Left"],
+ BOTTOMRIGHT = L["Bottom Right"]
+}
+
+local textPoints = {
+ TOP = L["Top"],
+ BOTTOM = L["Bottom"],
+ TOPLEFT = L["Top Left"],
+ TOPRIGHT = L["Top Right"],
+ BOTTOMLEFT = L["Bottom Left"],
+ BOTTOMRIGHT = L["Bottom Right"]
+}
+
+local ACD = E.Libs.AceConfigDialog
+
+local function BuildABConfig()
+ group.general = {
+ order = 1,
+ type = "group",
+ name = L["General Options"],
+ childGroups = "tab",
+ disabled = function() return not E.ActionBars.Initialized end,
+ args = {
+ info = {
+ order = 1,
+ type = "header",
+ name = L["General Options"]
+ },
+ toggleKeybind = {
+ order = 2,
+ type = "execute",
+ name = L["Keybind Mode"],
+ func = function() AB:ActivateBindMode() E:ToggleOptionsUI() GameTooltip:Hide() end,
+ disabled = function() return not E.private.actionbar.enable end
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ macrotext = {
+ order = 4,
+ type = "toggle",
+ name = L["Macro Text"],
+ desc = L["Display macro names on action buttons."],
+ disabled = function() return not E.private.actionbar.enable end
+ },
+ hotkeytext = {
+ order = 5,
+ type = "toggle",
+ name = L["Keybind Text"],
+ desc = L["Display bind names on action buttons."],
+ disabled = function() return not E.private.actionbar.enable end
+ },
+ useRangeColorText = {
+ order = 6,
+ type = "toggle",
+ name = L["Color Keybind Text"],
+ desc = L["Color Keybind Text when Out of Range, instead of the button."]
+ },
+ rightClickSelfCast = {
+ order = 7,
+ type = "toggle",
+ name = L["RightClick Self-Cast"],
+ set = function(info, value)
+ E.db.actionbar.rightClickSelfCast = value
+ for _, bar in pairs(AB.handledBars) do
+ AB:UpdateButtonConfig(bar, bar.bindButtons)
+ end
+ end
+ },
+ keyDown = {
+ order = 8,
+ type = "toggle",
+ name = L["Key Down"],
+ desc = L["OPTION_TOOLTIP_ACTION_BUTTON_USE_KEY_DOWN"],
+ disabled = function() return not E.private.actionbar.enable end
+ },
+ lockActionBars = {
+ order = 9,
+ type = "toggle",
+ name = L["LOCK_ACTIONBAR_TEXT"],
+ desc = L["If you unlock actionbars then trying to move a spell might instantly cast it if you cast spells on key press instead of key release."],
+ set = function(info, value)
+ E.db.actionbar[info[#info]] = value
+ AB:UpdateButtonSettings()
+
+ --Make it work for PetBar too
+ SetCVar("lockActionBars", (value == true and 1 or 0))
+ LOCK_ACTIONBAR = (value == true and "1" or "0")
+ end
+ },
+ desaturateOnCooldown = {
+ order = 10,
+ type = "toggle",
+ name = L["Desaturate Cooldowns"],
+ set = function(info, value)
+ E.db.actionbar.desaturateOnCooldown = value
+ AB:ToggleDesaturation(value)
+ end
+ },
+ transparentBackdrops = {
+ order = 11,
+ type = "toggle",
+ name = L["Transparent Backdrops"],
+ set = function(info, value)
+ E.db.actionbar.transparentBackdrops = value
+ E:StaticPopup_Show("CONFIG_RL")
+ end
+ },
+ transparentButtons = {
+ order = 12,
+ type = "toggle",
+ name = L["Transparent Buttons"],
+ set = function(info, value)
+ E.db.actionbar.transparentButtons = value
+ E:StaticPopup_Show("CONFIG_RL")
+ end
+ },
+ movementModifier = {
+ order = 13,
+ type = "select",
+ name = L["Pick Up Action Key"],
+ desc = L["The button you must hold down in order to drag an ability to another action button."],
+ disabled = function() return (not E.private.actionbar.enable or not E.db.actionbar.lockActionBars) end,
+ values = {
+ ["NONE"] = L["NONE"],
+ ["SHIFT"] = L["SHIFT_KEY"],
+ ["ALT"] = L["ALT_KEY_TEXT"],
+ ["CTRL"] = L["CTRL_KEY"]
+ }
+ },
+ globalFadeAlpha = {
+ order = 14,
+ type = "range",
+ name = L["Global Fade Transparency"],
+ desc = L["Transparency level when not in combat, no target exists, full health, not casting, and no focus target exists."],
+ min = 0, max = 1, step = 0.01,
+ isPercent = true,
+ set = function(info, value) E.db.actionbar[info[#info]] = value AB.fadeParent:SetAlpha(1-value) end
+ },
+ equippedItem = {
+ order = 15,
+ type = "toggle",
+ name = L["Equipped Item"],
+ get = function(info) return E.db.actionbar[info[#info]] end,
+ set = function(info, value) E.db.actionbar[info[#info]] = value AB:UpdateButtonSettings() end
+ },
+ equippedItemColor = {
+ order = 16,
+ type = "color",
+ name = L["Equipped Item Color"],
+ get = function(info)
+ local t = E.db.actionbar[info[#info]]
+ local d = P.actionbar[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.actionbar[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ AB:UpdateButtonSettings()
+ end,
+ disabled = function() return not E.db.actionbar.equippedItem end
+ },
+ colorGroup = {
+ order = 17,
+ type = "group",
+ name = L["COLORS"],
+ guiInline = true,
+ get = function(info)
+ local t = E.db.actionbar[info[#info]]
+ local d = P.actionbar[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.actionbar[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ AB:UpdateButtonSettings()
+ end,
+ args = {
+ noRangeColor = {
+ order = 1,
+ type = "color",
+ name = L["Out of Range"],
+ desc = L["Color of the actionbutton when out of range."]
+ },
+ noPowerColor = {
+ order = 2,
+ type = "color",
+ name = L["Out of Power"],
+ desc = L["Color of the actionbutton when out of power (Mana, Rage)."]
+ },
+ usableColor = {
+ order = 3,
+ type = "color",
+ name = L["Usable"],
+ desc = L["Color of the actionbutton when usable."]
+ },
+ notUsableColor = {
+ order = 4,
+ type = "color",
+ name = L["Not Usable"],
+ desc = L["Color of the actionbutton when not usable."]
+ }
+ }
+ },
+ fontGroup = {
+ order = 18,
+ type = "group",
+ name = L["Fonts"],
+ guiInline = true,
+ disabled = function() return not E.private.actionbar.enable end,
+ args = {
+ font = {
+ order = 1,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontSize = {
+ order = 2,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 32, step = 1
+ },
+ fontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ },
+ fontColor = {
+ order = 4,
+ type = "color",
+ name = L["COLOR"],
+ width = "full",
+ get = function(info)
+ local t = E.db.actionbar[info[#info]]
+ local d = P.actionbar[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.actionbar[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ AB:UpdateButtonSettings()
+ end
+ },
+ textPosition = {
+ order = 5,
+ type = "group",
+ name = L["Text Position"],
+ guiInline = true,
+ args = {
+ countTextPosition = {
+ order = 1,
+ type = "select",
+ name = L["Stack Text Position"],
+ values = textPoints
+ },
+ countTextXOffset = {
+ order = 2,
+ type = "range",
+ name = L["Stack Text X-Offset"],
+ min = -10, max = 10, step = 1
+ },
+ countTextYOffset = {
+ order = 3,
+ type = "range",
+ name = L["Stack Text Y-Offset"],
+ min = -10, max = 10, step = 1
+ },
+ hotkeyTextPosition = {
+ order = 4,
+ type = "select",
+ name = L["Keybind Text Position"],
+ values = textPoints
+ },
+ hotkeyTextXOffset = {
+ order = 5,
+ type = "range",
+ name = L["Keybind Text X-Offset"],
+ min = -10, max = 10, step = 1
+ },
+ hotkeyTextYOffset = {
+ order = 6,
+ type = "range",
+ name = L["Keybind Text Y-Offset"],
+ min = -10, max = 10, step = 1
+ }
+ }
+ }
+ }
+ },
+ lbf = {
+ order = 19,
+ type = "group",
+ guiInline = true,
+ name = L["LBF Support"],
+ get = function(info) return E.private.actionbar.lbf[info[#info]] end,
+ set = function(info, value) E.private.actionbar.lbf[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end,
+ disabled = function() return not E.private.actionbar.enable end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Allow LBF to handle the skinning of this element."]
+ }
+ }
+ }
+ }
+ }
+
+ group.barTotem = {
+ order = 2,
+ type = "group",
+ name = L["TUTORIAL_TITLE47"],
+ guiInline = false,
+ disabled = function() return not E.ActionBars.Initialized end,
+ get = function(info) return E.db.actionbar.barTotem[info[#info]] end,
+ set = function(info, value) E.db.actionbar.barTotem[info[#info]] = value AB:PositionAndSizeBarTotem() end,
+ args = {
+ info = {
+ order = 1,
+ type = "header",
+ name = L["TUTORIAL_TITLE47"]
+ },
+ enabled = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value) E.db.actionbar.barTotem[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ restorePosition = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Bar"],
+ desc = L["Restore the actionbars default settings"],
+ func = function() E:CopyTable(E.db.actionbar.barTotem, P.actionbar.barTotem) E:ResetMovers(TUTORIAL_TITLE47) AB:PositionAndSizeBarTotem() end,
+ disabled = function() return not E.db.actionbar.barTotem.enabled end
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ mouseover = {
+ order = 5,
+ type = "toggle",
+ name = L["Mouse Over"],
+ desc = L["The frame is not shown unless you mouse over the frame."],
+ disabled = function() return not E.db.actionbar.barTotem.enabled end
+ },
+ flyoutDirection = {
+ order = 6,
+ type = "select",
+ name = L["Flyout Direction"],
+ values = {
+ ["UP"] = L["Up"],
+ ["DOWN"] = L["Down"]
+ },
+ disabled = function() return not E.db.actionbar.barTotem.enabled end
+ },
+ buttonsize = {
+ order = 7,
+ type = "range",
+ name = L["Button Size"],
+ desc = L["The size of the action buttons."],
+ min = 15, max = 60, step = 1,
+ disabled = function() return not E.db.actionbar.barTotem.enabled end
+ },
+ buttonspacing = {
+ order = 8,
+ type = "range",
+ name = L["Button Spacing"],
+ desc = L["The spacing between buttons."],
+ min = -3, max = 40, step = 1,
+ disabled = function() return not E.db.actionbar.barTotem.enabled end
+ },
+ flyoutSpacing = {
+ order = 9,
+ type = "range",
+ name = L["Flyout Spacing"],
+ desc = L["The spacing between buttons."],
+ min = -3, max = 40, step = 1,
+ disabled = function() return not E.db.actionbar.barTotem.enabled end
+ },
+ alpha = {
+ order = 10,
+ type = "range",
+ name = L["Alpha"],
+ isPercent = true,
+ min = 0, max = 1, step = 0.01,
+ disabled = function() return not E.db.actionbar.barTotem.enabled end
+ },
+ visibility = {
+ order = 11,
+ type = "input",
+ name = L["Visibility State"],
+ desc = L["This works like a macro, you can run different situations to get the actionbar to show/hide differently.\n Example: '[combat] show;hide'"],
+ width = "full",
+ multiline = true,
+ set = function(info, value)
+ if value and value:match("[\n\r]") then
+ value = value:gsub("[\n\r]","")
+ end
+ E.db.actionbar.barTotem[info[#info]] = value
+ AB:PositionAndSizeBarTotem()
+ end,
+ disabled = function() return not E.db.actionbar.barTotem.enabled end
+ }
+ }
+ }
+
+ group.barPet = {
+ order = 3,
+ type = "group",
+ name = L["Pet Bar"],
+ guiInline = false,
+ disabled = function() return not E.ActionBars.Initialized end,
+ get = function(info) return E.db.actionbar.barPet[info[#info]] end,
+ set = function(info, value) E.db.actionbar.barPet[info[#info]] = value AB:PositionAndSizeBarPet() end,
+ args = {
+ info = {
+ order = 1,
+ type = "header",
+ name = L["Pet Bar"]
+ },
+ enabled = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ restorePosition = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Bar"],
+ desc = L["Restore the actionbars default settings"],
+ func = function() E:CopyTable(E.db.actionbar.barPet, P.actionbar.barPet) E:ResetMovers("Pet Bar") AB:PositionAndSizeBarPet() end,
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ backdrop = {
+ order = 5,
+ type = "toggle",
+ name = L["Backdrop"],
+ desc = L["Toggles the display of the actionbars backdrop."],
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ mouseover = {
+ order = 6,
+ type = "toggle",
+ name = L["Mouse Over"],
+ desc = L["The frame is not shown unless you mouse over the frame."],
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ inheritGlobalFade = {
+ order = 7,
+ type = "toggle",
+ name = L["Inherit Global Fade"],
+ desc = L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."],
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ point = {
+ order = 8,
+ type = "select",
+ name = L["Anchor Point"],
+ desc = L["The first button anchors itself to this point on the bar."],
+ values = points,
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ buttons = {
+ order = 9,
+ type = "range",
+ name = L["Buttons"],
+ desc = L["The amount of buttons to display."],
+ min = 1, max = NUM_PET_ACTION_SLOTS, step = 1,
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ buttonsPerRow = {
+ order = 10,
+ type = "range",
+ name = L["Buttons Per Row"],
+ desc = L["The amount of buttons to display per row."],
+ min = 1, max = NUM_PET_ACTION_SLOTS, step = 1,
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ buttonsize = {
+ order = 11,
+ type = "range",
+ name = L["Button Size"],
+ desc = L["The size of the action buttons."],
+ min = 15, max = 60, step = 1,
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ buttonspacing = {
+ order = 12,
+ type = "range",
+ name = L["Button Spacing"],
+ desc = L["The spacing between buttons."],
+ min = -3, max = 20, step = 1,
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ backdropSpacing = {
+ order = 13,
+ type = "range",
+ name = L["Backdrop Spacing"],
+ desc = L["The spacing between the backdrop and the buttons."],
+ min = 0, max = 10, step = 1,
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ heightMult = {
+ order = 14,
+ type = "range",
+ name = L["Height Multiplier"],
+ desc = L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."],
+ min = 1, max = 5, step = 1,
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ widthMult = {
+ order = 15,
+ type = "range",
+ name = L["Width Multiplier"],
+ desc = L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."],
+ min = 1, max = 5, step = 1,
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ alpha = {
+ order = 16,
+ type = "range",
+ name = L["Alpha"],
+ isPercent = true,
+ min = 0, max = 1, step = 0.01,
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ },
+ visibility = {
+ order = 17,
+ type = "input",
+ name = L["Visibility State"],
+ desc = L["This works like a macro, you can run different situations to get the actionbar to show/hide differently.\n Example: '[combat] show;hide'"],
+ width = "full",
+ multiline = true,
+ set = function(info, value)
+ if value and value:match("[\n\r]") then
+ value = value:gsub("[\n\r]", "")
+ end
+ E.db.actionbar.barPet.visibility = value
+ AB:UpdateButtonSettings()
+ end,
+ disabled = function() return not E.db.actionbar.barPet.enabled end
+ }
+ }
+ }
+ group.stanceBar = {
+ order = 4,
+ type = "group",
+ name = L["Stance Bar"],
+ guiInline = false,
+ disabled = function() return not E.ActionBars.Initialized end,
+ get = function(info) return E.db.actionbar.stanceBar[info[#info]] end,
+ set = function(info, value) E.db.actionbar.stanceBar[info[#info]] = value AB:PositionAndSizeBarShapeShift() end,
+ args = {
+ info = {
+ order = 1,
+ type = "header",
+ name = L["Stance Bar"]
+ },
+ enabled = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ restorePosition = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Bar"],
+ desc = L["Restore the actionbars default settings"],
+ func = function() E:CopyTable(E.db.actionbar.stanceBar, P.actionbar.stanceBar) E:ResetMovers(L["Stance Bar"]) AB:PositionAndSizeBarShapeShift() end,
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ backdrop = {
+ order = 5,
+ type = "toggle",
+ name = L["Backdrop"],
+ desc = L["Toggles the display of the actionbars backdrop."],
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ mouseover = {
+ order = 6,
+ type = "toggle",
+ name = L["Mouse Over"],
+ desc = L["The frame is not shown unless you mouse over the frame."],
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ inheritGlobalFade = {
+ order = 8,
+ type = "toggle",
+ name = L["Inherit Global Fade"],
+ desc = L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."],
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ point = {
+ order = 9,
+ type = "select",
+ name = L["Anchor Point"],
+ desc = L["The first button anchors itself to this point on the bar."],
+ values = textPoints,
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ buttons = {
+ order = 10,
+ type = "range",
+ name = L["Buttons"],
+ desc = L["The amount of buttons to display."],
+ min = 1, max = NUM_PET_ACTION_SLOTS, step = 1,
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ buttonsPerRow = {
+ order = 11,
+ type = "range",
+ name = L["Buttons Per Row"],
+ desc = L["The amount of buttons to display per row."],
+ min = 1, max = NUM_PET_ACTION_SLOTS, step = 1,
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ buttonsize = {
+ order = 12,
+ type = "range",
+ name = L["Button Size"],
+ desc = L["The size of the action buttons."],
+ min = 15, max = 60, step = 1,
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ buttonspacing = {
+ order = 13,
+ type = "range",
+ name = L["Button Spacing"],
+ desc = L["The spacing between buttons."],
+ min = -1, max = 10, step = 1,
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ backdropSpacing = {
+ order = 14,
+ type = "range",
+ name = L["Backdrop Spacing"],
+ desc = L["The spacing between the backdrop and the buttons."],
+ min = 0, max = 10, step = 1,
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ heightMult = {
+ order = 15,
+ type = "range",
+ name = L["Height Multiplier"],
+ desc = L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."],
+ min = 1, max = 5, step = 1,
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ widthMult = {
+ order = 16,
+ type = "range",
+ name = L["Width Multiplier"],
+ desc = L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."],
+ min = 1, max = 5, step = 1,
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ alpha = {
+ order = 17,
+ type = "range",
+ name = L["Alpha"],
+ isPercent = true,
+ min = 0, max = 1, step = 0.01,
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ style = {
+ order = 18,
+ type = "select",
+ name = L["Style"],
+ desc = L["This setting will be updated upon changing stances."],
+ values = {
+ ["darkenInactive"] = L["Darken Inactive"],
+ ["classic"] = L["Classic"]
+ },
+ disabled = function() return not E.db.actionbar.stanceBar.enabled end
+ },
+ visibility = {
+ order = 19,
+ type = "input",
+ name = L["Visibility State"],
+ desc = L["This works like a macro, you can run different situations to get the actionbar to show/hide differently.\n Example: '[combat] show;hide'"],
+ width = "full",
+ multiline = true,
+ set = function(info, value)
+ if value and value:match("[\n\r]") then
+ value = value:gsub("[\n\r]", "")
+ end
+ E.db.actionbar.stanceBar.visibility = value
+ AB:UpdateButtonSettings()
+ end
+ }
+ }
+ }
+ group.microbar = {
+ order = 5,
+ type = "group",
+ name = L["Micro Bar"],
+ disabled = function() return not E.ActionBars.Initialized end,
+ get = function(info) return E.db.actionbar.microbar[info[#info]] end,
+ set = function(info, value) E.db.actionbar.microbar[info[#info]] = value AB:UpdateMicroPositionDimensions() end,
+ args = {
+ info = {
+ order = 1,
+ type = "header",
+ name = L["Micro Bar"]
+ },
+ enabled = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ restoreMicrobar = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Bar"],
+ desc = L["Restore the actionbars default settings"],
+ func = function() E:CopyTable(E.db.actionbar.microbar, P.actionbar.microbar) E:ResetMovers(L["Micro Bar"]) AB:UpdateMicroPositionDimensions() end,
+ disabled = function() return not E.db.actionbar.microbar.enabled end
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ mouseover = {
+ order = 5,
+ type = "toggle",
+ name = L["Mouse Over"],
+ desc = L["The frame is not shown unless you mouse over the frame."],
+ disabled = function() return not E.db.actionbar.microbar.enabled end
+ },
+ buttonSize = {
+ order = 6,
+ type = "range",
+ name = L["Button Size"],
+ desc = L["The size of the action buttons."],
+ min = 15, max = 60, step = 1,
+ disabled = function() return not E.db.actionbar.microbar.enabled end
+ },
+ buttonSpacing = {
+ order = 7,
+ type = "range",
+ name = L["Button Spacing"],
+ desc = L["The spacing between buttons."],
+ min = -1, max = 20, step = 1,
+ disabled = function() return not E.db.actionbar.microbar.enabled end
+ },
+ buttonsPerRow = {
+ order = 8,
+ type = "range",
+ name = L["Buttons Per Row"],
+ desc = L["The amount of buttons to display per row."],
+ min = 1, max = 10, step = 1,
+ disabled = function() return not E.db.actionbar.microbar.enabled end
+ },
+ alpha = {
+ order = 9,
+ type = "range",
+ name = L["Alpha"],
+ isPercent = true,
+ desc = L["Change the alpha level of the frame."],
+ min = 0, max = 1, step = 0.1,
+ disabled = function() return not E.db.actionbar.microbar.enabled end
+ },
+ visibility = {
+ order = 10,
+ type = "input",
+ name = L["Visibility State"],
+ desc = L["This works like a macro, you can run different situations to get the actionbar to show/hide differently.\n Example: '[combat] show;hide'"],
+ width = "full",
+ multiline = true,
+ set = function(info, value)
+ if value and value:match("[\n\r]") then
+ value = value:gsub("[\n\r]","")
+ end
+ E.db.actionbar.microbar.visibility = value
+ AB:UpdateMicroPositionDimensions()
+ end,
+ disabled = function() return not E.db.actionbar.microbar.enabled end
+ }
+ }
+ }
+ for i = 1, 6 do
+ local name = L["Bar "]..i
+ group["bar"..i] = {
+ order = 7 + i,
+ type = "group",
+ name = name,
+ guiInline = false,
+ disabled = function() return not E.ActionBars.Initialized end,
+ get = function(info) return E.db.actionbar["bar"..i][info[#info]] end,
+ set = function(info, value) E.db.actionbar["bar"..i][info[#info]] = value AB:PositionAndSizeBar("bar"..i) end,
+ args = {
+ info = {
+ order = 1,
+ type = "header",
+ name = name
+ },
+ enabled = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value)
+ E.db.actionbar["bar"..i][info[#info]] = value
+ AB:PositionAndSizeBar("bar"..i)
+ end
+ },
+ restorePosition = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Bar"],
+ desc = L["Restore the actionbars default settings"],
+ func = function() E:CopyTable(E.db.actionbar["bar"..i], P.actionbar["bar"..i]) E:ResetMovers("Bar "..i) AB:PositionAndSizeBar("bar"..i) end,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ backdrop = {
+ order = 5,
+ type = "toggle",
+ name = L["Backdrop"],
+ desc = L["Toggles the display of the actionbars backdrop."],
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ showGrid = {
+ order = 6,
+ type = "toggle",
+ name = L["Show Empty Buttons"],
+ set = function(info, value) E.db.actionbar["bar"..i][info[#info]] = value AB:UpdateButtonSettingsForBar("bar"..i) end,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ mouseover = {
+ order = 7,
+ type = "toggle",
+ name = L["Mouse Over"],
+ desc = L["The frame is not shown unless you mouse over the frame."],
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ inheritGlobalFade = {
+ order = 8,
+ type = "toggle",
+ name = L["Inherit Global Fade"],
+ desc = L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."],
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ point = {
+ order = 9,
+ type = "select",
+ name = L["Anchor Point"],
+ desc = L["The first button anchors itself to this point on the bar."],
+ values = points,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ buttons = {
+ order = 11,
+ type = "range",
+ name = L["Buttons"],
+ desc = L["The amount of buttons to display."],
+ min = 1, max = NUM_ACTIONBAR_BUTTONS, step = 1,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ buttonsPerRow = {
+ order = 12,
+ type = "range",
+ name = L["Buttons Per Row"],
+ desc = L["The amount of buttons to display per row."],
+ min = 1, max = NUM_ACTIONBAR_BUTTONS, step = 1,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ buttonsize = {
+ order = 13,
+ type = "range",
+ name = L["Button Size"],
+ desc = L["The size of the action buttons."],
+ min = 15, max = 60, step = 1,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ buttonspacing = {
+ order = 14,
+ type = "range",
+ name = L["Button Spacing"],
+ desc = L["The spacing between buttons."],
+ min = -3, max = 20, step = 1,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ backdropSpacing = {
+ order = 15,
+ type = "range",
+ name = L["Backdrop Spacing"],
+ desc = L["The spacing between the backdrop and the buttons."],
+ min = 0, max = 10, step = 1,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ heightMult = {
+ order = 16,
+ type = "range",
+ name = L["Height Multiplier"],
+ desc = L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."],
+ min = 1, max = 5, step = 1,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ widthMult = {
+ order = 17,
+ type = "range",
+ name = L["Width Multiplier"],
+ desc = L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."],
+ min = 1, max = 5, step = 1,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ alpha = {
+ order = 18,
+ type = "range",
+ name = L["Alpha"],
+ isPercent = true,
+ min = 0, max = 1, step = 0.01,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ paging = {
+ order = 19,
+ type = "input",
+ name = L["Action Paging"],
+ desc = L["This works like a macro, you can run different situations to get the actionbar to page differently.\n Example: '[combat] 2;'"],
+ width = "full",
+ multiline = true,
+ get = function(info) return E.db.actionbar["bar"..i].paging[E.myclass] end,
+ set = function(info, value)
+ if value and value:match("[\n\r]") then
+ value = value:gsub("[\n\r]","")
+ end
+
+ if not E.db.actionbar["bar"..i].paging[E.myclass] then
+ E.db.actionbar["bar"..i].paging[E.myclass] = {}
+ end
+
+ E.db.actionbar["bar"..i].paging[E.myclass] = value
+ AB:UpdateButtonSettings()
+ end,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ },
+ visibility = {
+ order = 20,
+ type = "input",
+ name = L["Visibility State"],
+ desc = L["This works like a macro, you can run different situations to get the actionbar to show/hide differently.\n Example: '[combat] show;hide'"],
+ width = "full",
+ multiline = true,
+ set = function(info, value)
+ if value and value:match("[\n\r]") then
+ value = value:gsub("[\n\r]","")
+ end
+ E.db.actionbar["bar"..i].visibility = value
+ AB:UpdateButtonSettings()
+ end,
+ disabled = function() return not E.db.actionbar["bar"..i].enabled end
+ }
+ }
+ }
+
+ if i == 6 then
+ group["bar"..i].args.enabled.set = function(info, value)
+ E.db.actionbar["bar"..i].enabled = value
+ AB:PositionAndSizeBar("bar6")
+
+ --Update Bar 1 paging when Bar 6 is enabled/disabled
+ AB:UpdateBar1Paging()
+ AB:PositionAndSizeBar("bar1")
+ end
+ end
+ end
+end
+
+E.Options.args.actionbar = {
+ type = "group",
+ name = L["ActionBars"],
+ childGroups = "tree",
+ get = function(info) return E.db.actionbar[info[#info]] end,
+ set = function(info, value) E.db.actionbar[info[#info]] = value AB:UpdateButtonSettings() end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.private.actionbar[info[#info]] end,
+ set = function(info, value) E.private.actionbar[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ intro = {
+ order = 2,
+ type = "description",
+ name = L["ACTIONBARS_DESC"]
+ },
+ header = {
+ order = 3,
+ type = "header",
+ name = L["Shortcuts"]
+ },
+ spacer1 = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ generalShortcut = {
+ order = 5,
+ type = "execute",
+ name = L["General"],
+ func = function() ACD:SelectGroup("ElvUI", "actionbar", "general") end,
+ disabled = function() return not E.ActionBars.Initialized end
+ },
+ cooldownTextShortcut = {
+ order = 6,
+ type = "execute",
+ name = L["Cooldowns"],
+ func = function() ACD:SelectGroup("ElvUI", "cooldown", "actionbar") end
+ },
+ petBarShortcut = {
+ order = 7,
+ type = "execute",
+ name = L["Pet Bar"],
+ func = function() ACD:SelectGroup("ElvUI", "actionbar", "barPet") end,
+ disabled = function() return not E.ActionBars.Initialized end
+ },
+ stanceBarShortcut = {
+ order = 8,
+ type = "execute",
+ name = L["Stance Bar"],
+ func = function() ACD:SelectGroup("ElvUI", "actionbar", "stanceBar") end,
+ disabled = function() return not E.ActionBars.Initialized end
+ },
+ spacer2 = {
+ order = 9,
+ type = "description",
+ name = " "
+ },
+ totemBarShortcut = {
+ order = 10,
+ type = "execute",
+ name = L["TUTORIAL_TITLE47"],
+ func = function() ACD:SelectGroup("ElvUI", "actionbar", "barTotem") end,
+ disabled = function() return not E.ActionBars.Initialized end,
+ hidden = false
+ },
+ microbarShortcut = {
+ order = 11,
+ type = "execute",
+ name = L["Micro Bar"],
+ func = function() ACD:SelectGroup("ElvUI", "actionbar", "microbar") end,
+ disabled = function() return not E.ActionBars.Initialized end
+ },
+ bar1Shortcut = {
+ order = 13,
+ type = "execute",
+ name = L["Bar "]..1,
+ func = function() ACD:SelectGroup("ElvUI", "actionbar", "bar1") end,
+ disabled = function() return not E.ActionBars.Initialized end
+ },
+ bar2Shortcut = {
+ order = 14,
+ type = "execute",
+ name = L["Bar "]..2,
+ func = function() ACD:SelectGroup("ElvUI", "actionbar", "bar2") end,
+ disabled = function() return not E.ActionBars.Initialized end
+ },
+ spacer3 = {
+ order = 15,
+ type = "description",
+ name = " "
+ },
+ bar3Shortcut = {
+ order = 16,
+ type = "execute",
+ name = L["Bar "]..3,
+ func = function() ACD:SelectGroup("ElvUI", "actionbar", "bar3") end,
+ disabled = function() return not E.ActionBars.Initialized end
+ },
+ bar4Shortcut = {
+ order = 17,
+ type = "execute",
+ name = L["Bar "]..4,
+ func = function() ACD:SelectGroup("ElvUI", "actionbar", "bar4") end,
+ disabled = function() return not E.ActionBars.Initialized end
+ },
+ bar5Shortcut = {
+ order = 18,
+ type = "execute",
+ name = L["Bar "]..5,
+ func = function() ACD:SelectGroup("ElvUI", "actionbar", "bar5") end,
+ disabled = function() return not E.ActionBars.Initialized end
+ },
+ bar6Shortcut = {
+ order = 19,
+ type = "execute",
+ name = L["Bar "]..6,
+ func = function() ACD:SelectGroup("ElvUI", "actionbar", "bar6") end,
+ disabled = function() return not E.ActionBars.Initialized end
+ }
+ }
+}
+group = E.Options.args.actionbar.args
+BuildABConfig()
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Auras.lua b/ElvUI_OptionsUI/Auras.lua
new file mode 100644
index 0000000..310e388
--- /dev/null
+++ b/ElvUI_OptionsUI/Auras.lua
@@ -0,0 +1,413 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+local A = E:GetModule("Auras")
+local RB = E:GetModule("ReminderBuffs")
+local M = E:GetModule("Minimap")
+
+local format = string.format
+
+local function GetAuraOptions(headerName)
+ local auraOptions = {
+ header = {
+ order = 1,
+ type = "header",
+ name = headerName
+ },
+ size = {
+ order = 2,
+ type = "range",
+ name = L["Size"],
+ desc = L["Set the size of the individual auras."],
+ min = 16, max = 60, step = 2
+ },
+ durationFontSize = {
+ order = 3,
+ type = "range",
+ name = L["Duration Font Size"],
+ min = 4, max = 32, step = 1,
+ },
+ countFontSize = {
+ order = 4,
+ type = "range",
+ name = L["Count Font Size"],
+ min = 4, max = 32, step = 1,
+ },
+ growthDirection = {
+ order = 5,
+ type = "select",
+ name = L["Growth Direction"],
+ desc = L["The direction the auras will grow and then the direction they will grow after they reach the wrap after limit."],
+ values = {
+ DOWN_RIGHT = format(L["%s and then %s"], L["Down"], L["Right"]),
+ DOWN_LEFT = format(L["%s and then %s"], L["Down"], L["Left"]),
+ UP_RIGHT = format(L["%s and then %s"], L["Up"], L["Right"]),
+ UP_LEFT = format(L["%s and then %s"], L["Up"], L["Left"]),
+ RIGHT_DOWN = format(L["%s and then %s"], L["Right"], L["Down"]),
+ RIGHT_UP = format(L["%s and then %s"], L["Right"], L["Up"]),
+ LEFT_DOWN = format(L["%s and then %s"], L["Left"], L["Down"]),
+ LEFT_UP = format(L["%s and then %s"], L["Left"], L["Up"])
+ }
+ },
+ wrapAfter = {
+ order = 6,
+ type = "range",
+ name = L["Wrap After"],
+ desc = L["Begin a new row or column after this many auras."],
+ min = 1, max = 32, step = 1
+ },
+ maxWraps = {
+ order = 7,
+ type = "range",
+ name = L["Max Wraps"],
+ desc = L["Limit the number of rows or columns."],
+ min = 1, max = 32, step = 1
+ },
+ horizontalSpacing = {
+ order = 8,
+ type = "range",
+ name = L["Horizontal Spacing"],
+ min = 0, max = 50, step = 1
+ },
+ verticalSpacing = {
+ order = 9,
+ type = "range",
+ name = L["Vertical Spacing"],
+ min = 0, max = 50, step = 1
+ },
+ sortMethod = {
+ order = 10,
+ type = "select",
+ name = L["Sort Method"],
+ desc = L["Defines how the group is sorted."],
+ values = {
+ ["INDEX"] = L["Index"],
+ ["TIME"] = L["Time"],
+ ["NAME"] = L["NAME"]
+ }
+ },
+ sortDir = {
+ order = 11,
+ type = "select",
+ name = L["Sort Direction"],
+ desc = L["Defines the sort order of the selected sort method."],
+ values = {
+ ["+"] = L["Ascending"],
+ ["-"] = L["Descending"]
+ }
+ },
+ seperateOwn = {
+ order = 12,
+ type = "select",
+ name = L["Seperate"],
+ desc = L["Indicate whether buffs you cast yourself should be separated before or after."],
+ values = {
+ [-1] = L["Other's First"],
+ [0] = L["No Sorting"],
+ [1] = L["Your Auras First"]
+ }
+ }
+ }
+
+ return auraOptions
+end
+
+E.Options.args.auras = {
+ type = "group",
+ name = L["BUFFOPTIONS_LABEL"],
+ childGroups = "tab",
+ get = function(info) return E.db.auras[info[#info]] end,
+ set = function(info, value) E.db.auras[info[#info]] = value A:UpdateHeader(ElvUIPlayerBuffs) A:UpdateHeader(ElvUIPlayerDebuffs) end,
+ args = {
+ intro = {
+ order = 1,
+ type = "description",
+ name = L["AURAS_DESC"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.private.auras[info[#info]] end,
+ set = function(info, value)
+ E.private.auras[info[#info]] = value
+ E:StaticPopup_Show("PRIVATE_RL")
+ end
+ },
+ disableBlizzard = {
+ order = 3,
+ type = "toggle",
+ name = L["Disabled Blizzard"],
+ get = function(info) return E.private.auras[info[#info]] end,
+ set = function(info, value)
+ E.private.auras[info[#info]] = value
+ E:StaticPopup_Show("PRIVATE_RL")
+ end
+ },
+ general = {
+ order = 4,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ fadeThreshold = {
+ order = 2,
+ type = "range",
+ name = L["Fade Threshold"],
+ desc = L["Threshold before the icon will fade out and back in. Set to -1 to disable."],
+ min = -1, max = 30, step = 1
+ },
+ showDuration = {
+ order = 3,
+ type = "toggle",
+ name = L["Duration Enable"]
+ },
+ font = {
+ order = 4,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontOutline = {
+ order = 5,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ },
+ timeXOffset = {
+ order = 6,
+ type = "range",
+ name = L["Time xOffset"],
+ min = -60, max = 60, step = 1
+ },
+ timeYOffset = {
+ order = 7,
+ type = "range",
+ name = L["Time yOffset"],
+ min = -60, max = 60, step = 1
+ },
+ countXOffset = {
+ order = 8,
+ type = "range",
+ name = L["Count xOffset"],
+ min = -60, max = 60, step = 1
+ },
+ countYOffset = {
+ order = 9,
+ type = "range",
+ name = L["Count yOffset"],
+ min = -60, max = 60, step = 1
+ },
+ statusBar = {
+ order = 10,
+ type = "group",
+ name = L["Statusbar"],
+ guiInline = true,
+ get = function(info) return E.db.auras[info[#info]] end,
+ set = function(info, value) E.db.auras[info[#info]] = value; A:UpdateHeader(ElvUIPlayerBuffs); A:UpdateHeader(ElvUIPlayerDebuffs) end,
+ args = {
+ barShow = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ },
+ barNoDuration = {
+ order = 2,
+ type = "toggle",
+ name = L["No Duration"],
+ },
+ barTexture = {
+ order = 3,
+ type = "select", dialogControl = "LSM30_Statusbar",
+ name = L["Texture"],
+ values = _G.AceGUIWidgetLSMlists.statusbar,
+ },
+ barColor = {
+ type = "color",
+ order = 4,
+ name = L.COLOR,
+ hasAlpha = false,
+ disabled = function() return not E.db.auras.barShow or (E.db.auras.barColorGradient or not E.db.auras.barShow) end,
+ get = function(info)
+ local t = E.db.auras.barColor
+ local d = P.auras.barColor
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.auras.barColor
+ t.r, t.g, t.b = r, g, b
+ end,
+ },
+ barColorGradient = {
+ order = 5,
+ type = "toggle",
+ name = L["Color by Value"],
+ disabled = function() return not E.db.auras.barShow end,
+ },
+ barWidth = {
+ order = 6,
+ type = "range",
+ name = L["Width"],
+ min = 1, max = 10, step = 1,
+ disabled = function() return not E.db.auras.barShow end,
+ },
+ barHeight = {
+ order = 7,
+ type = "range",
+ name = L["Height"],
+ min = 1, max = 10, step = 1,
+ disabled = function() return not E.db.auras.barShow end,
+ },
+ barSpacing = {
+ order = 8,
+ type = "range",
+ name = L["Spacing"],
+ min = -10, max = 10, step = 1,
+ disabled = function() return not E.db.auras.barShow end,
+ },
+ barPosition = {
+ order = 9,
+ type = "select",
+ name = L["Position"],
+ disabled = function() return not E.db.auras.barShow end,
+ values = {
+ ["TOP"] = L["Top"],
+ ["BOTTOM"] = L["Bottom"],
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"],
+ },
+ },
+ },
+ },
+ lbf = {
+ order = 11,
+ type = "group",
+ guiInline = true,
+ name = L["LBF Support"],
+ get = function(info) return E.private.auras.lbf[info[#info]] end,
+ set = function(info, value) E.private.auras.lbf[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end,
+ disabled = function() return not E.private.auras.enable end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Allow LBF to handle the skinning of this element."]
+ }
+ }
+ }
+ }
+ },
+ buffs = {
+ order = 5,
+ type = "group",
+ name = L["Buffs"],
+ get = function(info) return E.db.auras.buffs[info[#info]] end,
+ set = function(info, value) E.db.auras.buffs[info[#info]] = value A:UpdateHeader(ElvUIPlayerBuffs) end,
+ args = GetAuraOptions(L["Buffs"])
+ },
+ debuffs = {
+ order = 6,
+ type = "group",
+ name = L["Debuffs"],
+ get = function(info) return E.db.auras.debuffs[info[#info]] end,
+ set = function(info, value) E.db.auras.debuffs[info[#info]] = value A:UpdateHeader(ElvUIPlayerDebuffs) end,
+ args = GetAuraOptions(L["Debuffs"])
+ },
+ reminder = {
+ order = 7,
+ type = "group",
+ name = L["Reminder"],
+ get = function(info) return E.db.general.reminder[info[#info]] end,
+ set = function(info, value) E.db.general.reminder[info[#info]] = value RB:UpdateSettings() end,
+ disabled = function() return not E.private.general.minimap.enable end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Reminder"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Display reminder bar on the minimap."],
+ set = function(info, value) E.db.general.reminder[info[#info]] = value M:UpdateSettings() end
+ },
+ generalGroup = {
+ order = 3,
+ type = "group",
+ guiInline = true,
+ name = L["General"],
+ disabled = function() return not E.db.general.reminder.enable end,
+ args = {
+ durations = {
+ order = 1,
+ type = "toggle",
+ name = L["Remaining Time"]
+ },
+ reverse = {
+ order = 2,
+ type = "toggle",
+ name = L["Reverse Style"],
+ desc = L["When enabled active buff icons will light up instead of becoming darker, while inactive buff icons will become darker instead of being lit up."]
+ },
+ position = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ set = function(info, value) E.db.general.reminder[info[#info]] = value RB:UpdatePosition() end,
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"]
+ }
+ },
+ classtype = {
+ order = 4,
+ type = "select",
+ name = L["Class Type"],
+ get = function(info) return E.private.general.reminder[info[#info]] end,
+ set = function(info, value) E.private.general.reminder[info[#info]] = value RB:UpdateSettings() end,
+ values = {
+ ["Caster"] = L["Caster"],
+ ["Attack"] = L["Attack"]
+ }
+ }
+ }
+ },
+ fontGroup = {
+ order = 4,
+ type = "group",
+ guiInline = true,
+ name = L["Font"],
+ disabled = function() return not E.db.general.reminder.enable or not E.db.general.reminder.durations end,
+ args = {
+ font = {
+ order = 1,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontSize = {
+ order = 2,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 6, max = 22, step = 1
+ },
+ fontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Bags.lua b/ElvUI_OptionsUI/Bags.lua
new file mode 100644
index 0000000..10296d6
--- /dev/null
+++ b/ElvUI_OptionsUI/Bags.lua
@@ -0,0 +1,838 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+local B = E:GetModule("Bags")
+
+local _G = _G
+local gsub, match = string.gsub, string.match
+
+local GameTooltip = _G["GameTooltip"]
+
+E.Options.args.bags = {
+ type = "group",
+ name = L["BAGSLOT"],
+ childGroups = "tab",
+ get = function(info) return E.db.bags[info[#info]] end,
+ set = function(info, value) E.db.bags[info[#info]] = value end,
+ args = {
+ intro = {
+ order = 1,
+ type = "description",
+ name = L["BAGS_DESC"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Enable/Disable the all-in-one bag."],
+ get = function(info) return E.private.bags.enable end,
+ set = function(info, value) E.private.bags.enable = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ general = {
+ order = 3,
+ type = "group",
+ name = L["General"],
+ disabled = function() return not E.Bags.Initialized end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"],
+ },
+ strata = {
+ order = 2,
+ type = "select",
+ name = L["Frame Strata"],
+ set = function(info, value) E.db.bags[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end,
+ values = {
+ ["BACKGROUND"] = "BACKGROUND",
+ ["LOW"] = "LOW",
+ ["MEDIUM"] = "MEDIUM",
+ ["HIGH"] = "HIGH",
+ ["DIALOG"] = "DIALOG",
+ ["TOOLTIP"] = "TOOLTIP"
+ }
+ },
+ currencyFormat = {
+ order = 3,
+ type = "select",
+ name = L["Currency Format"],
+ desc = L["The display format of the currency icons that get displayed below the main bag. (You have to be watching a currency for this to display)"],
+ values = {
+ ["ICON"] = L["Icons Only"],
+ ["ICON_TEXT"] = L["Icons and Text"],
+ ["ICON_TEXT_ABBR"] = L["Icons and Text (Short)"]
+ },
+ set = function(info, value) E.db.bags[info[#info]] = value B:UpdateTokens() end
+ },
+ moneyFormat = {
+ order = 4,
+ type = "select",
+ name = L["Money Format"],
+ desc = L["The display format of the money text that is shown at the top of the main bag."],
+ values = {
+ ["SMART"] = L["Smart"],
+ ["FULL"] = L["Full"],
+ ["SHORT"] = L["SHORT"],
+ ["SHORTINT"] = L["Short (Whole Numbers)"],
+ ["CONDENSED"] = L["Condensed"],
+ ["BLIZZARD"] = L["Blizzard Style"]
+ },
+ set = function(info, value) E.db.bags[info[#info]] = value B:UpdateGoldText() end
+ },
+ moneyCoins = {
+ order = 5,
+ type = "toggle",
+ name = L["Show Coins"],
+ desc = L["Use coin icons instead of colored text."],
+ set = function(info, value) E.db.bags[info[#info]] = value B:UpdateGoldText() end
+ },
+ transparent = {
+ order = 6,
+ type = "toggle",
+ name = L["Transparent Buttons"],
+ set = function(info, value) E.db.bags[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ questIcon = {
+ order = 7,
+ type = "toggle",
+ name = L["Show Quest Icon"],
+ desc = L["Display an exclamation mark on items that starts a quest."],
+ set = function(info, value) E.db.bags[info[#info]] = value B:UpdateAllBagSlots() end
+ },
+ junkIcon = {
+ order = 8,
+ type = "toggle",
+ name = L["Show Junk Icon"],
+ desc = L["Display the junk icon on all grey items that can be vendored."],
+ set = function(info, value) E.db.bags[info[#info]] = value B:UpdateAllBagSlots() end
+ },
+ junkDesaturate = {
+ order = 9,
+ type = "toggle",
+ name = L["Desaturate Junk Items"],
+ set = function(info, value) E.db.bags[info[#info]] = value B:UpdateAllBagSlots() end,
+ },
+ qualityColors = {
+ order = 10,
+ type = "toggle",
+ name = L["Show Quality Color"],
+ desc = L["Colors the border according to the Quality of the Item."],
+ set = function(info, value) E.db.bags[info[#info]] = value B:UpdateAllBagSlots() end
+ },
+ showBindType = {
+ order = 11,
+ type = "toggle",
+ name = L["Show Bind on Equip/Use Text"],
+ set = function(info, value) E.db.bags[info[#info]] = value B:UpdateAllBagSlots() end
+ },
+ clearSearchOnClose = {
+ order = 12,
+ type = "toggle",
+ name = L["Clear Search On Close"],
+ set = function(info, value) E.db.bags[info[#info]] = value end
+ },
+ reverseSlots = {
+ order = 13,
+ type = "toggle",
+ name = L["Reverse Bag Slots"],
+ set = function(info, value) E.db.bags[info[#info]] = value B:UpdateAll() B:UpdateTokens() end
+ },
+ disableBagSort = {
+ order = 14,
+ type = "toggle",
+ name = L["Disable Bag Sort"],
+ set = function(info, value) E.db.bags[info[#info]] = value B:ToggleSortButtonState(false) end
+ },
+ disableBankSort = {
+ order = 15,
+ type = "toggle",
+ name = L["Disable Bank Sort"],
+ set = function(info, value) E.db.bags[info[#info]] = value B:ToggleSortButtonState(true) end
+ },
+ countGroup = {
+ order = 16,
+ type = "group",
+ name = L["Item Count Font"],
+ guiInline = true,
+ args = {
+ countFont = {
+ order = 1,
+ type = "select",
+ dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font,
+ set = function(info, value) E.db.bags.countFont = value B:UpdateCountDisplay() end
+ },
+ countFontSize = {
+ order = 2,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 33, step = 1,
+ set = function(info, value) E.db.bags.countFontSize = value B:UpdateCountDisplay() end,
+ },
+ countFontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ set = function(info, value) E.db.bags.countFontOutline = value B:UpdateCountDisplay() end,
+ values = C.Values.FontFlags
+ },
+ countFontColor = {
+ order = 4,
+ type = "color",
+ name = L["COLOR"],
+ get = function(info)
+ local t = E.db.bags[info[#info]]
+ local d = P.bags[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.bags[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ B:UpdateCountDisplay()
+ end
+ }
+ }
+ },
+ itemLevelGroup = {
+ order = 17,
+ type = "group",
+ name = L["Item Level"],
+ guiInline = true,
+ args = {
+ itemLevel = {
+ order = 1,
+ type = "toggle",
+ name = L["Display Item Level"],
+ desc = L["Displays item level on equippable items."],
+ set = function(info, value) E.db.bags.itemLevel = value B:UpdateItemLevelDisplay() end
+ },
+ itemLevelCustomColorEnable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable Custom Color"],
+ disabled = function() return not E.db.bags.itemLevel end,
+ set = function(info, value) E.db.bags.itemLevelCustomColorEnable = value B:UpdateItemLevelDisplay() end
+ },
+ itemLevelCustomColor = {
+ order = 3,
+ type = "color",
+ name = L["Custom Color"],
+ disabled = function() return not E.db.bags.itemLevel or not E.db.bags.itemLevelCustomColorEnable end,
+ get = function(info)
+ local t = E.db.bags.itemLevelCustomColor
+ local d = P.bags.itemLevelCustomColor
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.bags.itemLevelCustomColor
+ t.r, t.g, t.b = r, g, b
+ B:UpdateItemLevelDisplay()
+ end
+ },
+ itemLevelThreshold = {
+ order = 4,
+ type = "range",
+ name = L["Item Level Threshold"],
+ desc = L["The minimum item level required for it to be shown."],
+ min = 1, max = 1000, step = 1,
+ disabled = function() return not E.db.bags.itemLevel end,
+ set = function(info, value) E.db.bags.itemLevelThreshold = value B:UpdateItemLevelDisplay() end
+ },
+ itemLevelFont = {
+ order = 5,
+ type = "select",
+ dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font,
+ disabled = function() return not E.db.bags.itemLevel end,
+ set = function(info, value) E.db.bags.itemLevelFont = value B:UpdateItemLevelDisplay() end
+ },
+ itemLevelFontSize = {
+ order = 6,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 33, step = 1,
+ disabled = function() return not E.db.bags.itemLevel end,
+ set = function(info, value) E.db.bags.itemLevelFontSize = value B:UpdateItemLevelDisplay() end
+ },
+ itemLevelFontOutline = {
+ order = 7,
+ type = "select",
+ name = L["Font Outline"],
+ disabled = function() return not E.db.bags.itemLevel end,
+ set = function(info, value) E.db.bags.itemLevelFontOutline = value B:UpdateItemLevelDisplay() end,
+ values = C.Values.FontFlags
+ }
+ }
+ }
+ }
+ },
+ sizeGroup = {
+ order = 4,
+ type = "group",
+ name = L["Size"],
+ disabled = function() return not E.Bags.Initialized end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Size"],
+ },
+ bagSize = {
+ order = 2,
+ type = "range",
+ name = L["Button Size (Bag)"],
+ desc = L["The size of the individual buttons on the bag frame."],
+ min = 15, max = 60, step = 1,
+ set = function(info, value) E.db.bags[info[#info]] = value B:Layout() end
+ },
+ bankSize = {
+ order = 3,
+ type = "range",
+ name = L["Button Size (Bank)"],
+ desc = L["The size of the individual buttons on the bank frame."],
+ min = 15, max = 60, step = 1,
+ set = function(info, value) E.db.bags[info[#info]] = value B:Layout(true) end
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = ""
+ },
+ bagWidth = {
+ order = 5,
+ type = "range",
+ name = L["Panel Width (Bags)"],
+ desc = L["Adjust the width of the bag frame."],
+ min = 150, max = 1400, step = 1,
+ set = function(info, value) E.db.bags[info[#info]] = value B:Layout() end
+ },
+ bankWidth = {
+ order = 6,
+ type = "range",
+ name = L["Panel Width (Bank)"],
+ desc = L["Adjust the width of the bank frame."],
+ min = 150, max = 1400, step = 1,
+ set = function(info, value) E.db.bags[info[#info]] = value B:Layout(true) end
+ }
+ }
+ },
+ colorGroup = {
+ order = 5,
+ type = "group",
+ name = L["COLORS"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["COLORS"]
+ },
+ profession = {
+ order = 2,
+ type = "group",
+ name = L["Profession Bags"],
+ guiInline = true,
+ get = function(info)
+ local t = E.db.bags.colors.profession[info[#info]]
+ local d = P.bags.colors.profession[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.bags.colors.profession[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ if not E.Bags.Initialized then return end
+ B:UpdateBagColors("ProfessionColors", info[#info], r, g, b)
+ B:UpdateAllBagSlots()
+ end,
+ args = {
+ professionBagColors = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.db.bags[info[#info]] end,
+ set = function(info, value)
+ E.db.bags[info[#info]] = value
+ if not E.Bags.Initialized then return end
+ B:UpdateAllBagSlots()
+ end
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = ""
+ },
+ quiver = {
+ order = 3,
+ type = "color",
+ name = L["Quiver"],
+ disabled = function() return not E.db.bags.professionBagColors end
+ },
+ ammoPouch = {
+ order = 4,
+ type = "color",
+ name = L["Ammo Pouch"],
+ disabled = function() return not E.db.bags.professionBagColors end
+ },
+ soulBag = {
+ order = 5,
+ type = "color",
+ name = L["Soul Bag"],
+ disabled = function() return not E.db.bags.professionBagColors end
+ },
+ leatherworking = {
+ order = 6,
+ type = "color",
+ name = L["Leatherworking"],
+ disabled = function() return not E.db.bags.professionBagColors end
+ },
+ inscription = {
+ order = 7,
+ type = "color",
+ name = L["INSCRIPTION"],
+ disabled = function() return not E.db.bags.professionBagColors end
+ },
+ herbs = {
+ order = 8,
+ type = "color",
+ name = L["Herbalism"],
+ disabled = function() return not E.db.bags.professionBagColors end
+ },
+ enchanting = {
+ order = 9,
+ type = "color",
+ name = L["Enchanting"],
+ disabled = function() return not E.db.bags.professionBagColors end
+ },
+ engineering = {
+ order = 10,
+ type = "color",
+ name = L["Engineering"],
+ disabled = function() return not E.db.bags.professionBagColors end
+ },
+ gems = {
+ order = 11,
+ type = "color",
+ name = L["Gems"],
+ disabled = function() return not E.db.bags.professionBagColors end
+ },
+ mining = {
+ order = 12,
+ type = "color",
+ name = L["Mining"],
+ disabled = function() return not E.db.bags.professionBagColors end
+ }
+ }
+ },
+ items = {
+ order = 3,
+ type = "group",
+ name = L["ITEMS"],
+ guiInline = true,
+ get = function(info)
+ local t = E.db.bags.colors.items[info[#info]]
+ local d = P.bags.colors.items[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.bags.colors.items[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ if not E.Bags.Initialized then return end
+ B:UpdateQuestColors("QuestColors", info[#info], r, g, b)
+ B:UpdateAllBagSlots()
+ end,
+ args = {
+ questItemColors = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.db.bags[info[#info]] end,
+ set = function(info, value)
+ E.db.bags[info[#info]] = value
+ if not E.Bags.Initialized then return end
+ B:UpdateAllBagSlots()
+ end
+ },
+ questStarter = {
+ order = 2,
+ type = "color",
+ name = L["Quest Starter"],
+ disabled = function() return not E.db.bags.questItemColors end
+ },
+ questItem = {
+ order = 3,
+ type = "color",
+ name = L["ITEM_BIND_QUEST"],
+ disabled = function() return not E.db.bags.questItemColors end
+ }
+ }
+ }
+ }
+ },
+ bagBar = {
+ order = 6,
+ type = "group",
+ name = L["Bag-Bar"],
+ get = function(info) return E.db.bags.bagBar[info[#info]] end,
+ set = function(info, value) E.db.bags.bagBar[info[#info]] = value B:SizeAndPositionBagBar() end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Bag-Bar"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Enable/Disable the Bag-Bar."],
+ get = function(info) return E.private.bags.bagBar end,
+ set = function(info, value) E.private.bags.bagBar = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ showBackdrop = {
+ order = 3,
+ type = "toggle",
+ name = L["Backdrop"],
+ disabled = function() return not E.private.bags.bagBar end
+ },
+ mouseover = {
+ order = 4,
+ type = "toggle",
+ name = L["Mouse Over"],
+ desc = L["The frame is not shown unless you mouse over the frame."],
+ disabled = function() return not E.private.bags.bagBar end
+ },
+ size = {
+ order = 5,
+ type = "range",
+ name = L["Button Size"],
+ desc = L["Set the size of your bag buttons."],
+ min = 24, max = 60, step = 1,
+ disabled = function() return not E.private.bags.bagBar end
+ },
+ spacing = {
+ order = 6,
+ type = "range",
+ name = L["Button Spacing"],
+ desc = L["The spacing between buttons."],
+ min = -1, max = 10, step = 1,
+ disabled = function() return not E.private.bags.bagBar end
+ },
+ backdropSpacing = {
+ order = 7,
+ type = "range",
+ name = L["Backdrop Spacing"],
+ desc = L["The spacing between the backdrop and the buttons."],
+ min = 0, max = 10, step = 1,
+ disabled = function() return not E.private.bags.bagBar end
+ },
+ sortDirection = {
+ order = 8,
+ type = "select",
+ name = L["Sort Direction"],
+ desc = L["The direction that the bag frames will grow from the anchor."],
+ values = {
+ ["ASCENDING"] = L["Ascending"],
+ ["DESCENDING"] = L["Descending"]
+ },
+ disabled = function() return not E.private.bags.bagBar end
+ },
+ growthDirection = {
+ order = 9,
+ type = "select",
+ name = L["Bar Direction"],
+ desc = L["The direction that the bag frames be (Horizontal or Vertical)."],
+ values = {
+ ["VERTICAL"] = L["Vertical"],
+ ["HORIZONTAL"] = L["Horizontal"]
+ },
+ disabled = function() return not E.private.bags.bagBar end
+ },
+ visibility = {
+ order = 10,
+ type = "input",
+ name = L["Visibility State"],
+ desc = L["This works like a macro, you can run different situations to get the actionbar to show/hide differently.\n Example: '[combat] show;hide'"],
+ width = "full",
+ multiline = true,
+ set = function(info, value)
+ if value and value:match("[\n\r]") then
+ value = value:gsub("[\n\r]","")
+ end
+ E.db.bags.bagBar.visibility = value
+ B:SizeAndPositionBagBar()
+ end,
+ disabled = function() return not E.private.bags.bagBar end
+ }
+ }
+ },
+ split = {
+ order = 7,
+ type = "group",
+ name = L["Split"],
+ get = function(info) return E.db.bags.split[info[#info]] end,
+ set = function(info, value) E.db.bags.split[info[#info]] = value B:UpdateAll() end,
+ disabled = function() return not E.Bags.Initialized end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Split"]
+ },
+ bagSpacing = {
+ order = 2,
+ type = "range",
+ name = L["Bag Spacing"],
+ min = 0, max = 20, step = 1
+ },
+ player = {
+ order = 3,
+ type = "toggle",
+ name = L["Bag"],
+ set = function(info, value) E.db.bags.split[info[#info]] = value B:Layout() end
+ },
+ bank = {
+ order = 4,
+ type = "toggle",
+ name = L["Bank"],
+ set = function(info, value) E.db.bags.split[info[#info]] = value B:Layout(true) end
+ },
+ splitbags = {
+ order = 5,
+ type = "group",
+ name = L["PLAYER"],
+ get = function(info) return E.db.bags.split[info[#info]] end,
+ set = function(info, value) E.db.bags.split[info[#info]] = value B:Layout() end,
+ disabled = function() return not E.db.bags.split.player end,
+ guiInline = true,
+ args = {
+ bag1 = {
+ order = 2,
+ type = "toggle",
+ name = L["Bag 1"]
+ },
+ bag2 = {
+ order = 3,
+ type = "toggle",
+ name = L["Bag 2"]
+ },
+ bag3 = {
+ order = 4,
+ type = "toggle",
+ name = L["Bag 3"]
+ },
+ bag4 = {
+ order = 5,
+ type = "toggle",
+ name = L["Bag 4"]
+ }
+ }
+ },
+ splitbank = {
+ order = 6,
+ type = "group",
+ name = L["Bank"],
+ get = function(info) return E.db.bags.split[info[#info]] end,
+ set = function(info, value) E.db.bags.split[info[#info]] = value B:Layout(true) end,
+ disabled = function() return not E.db.bags.split.bank end,
+ guiInline = true,
+ args = {
+ bag5 = {
+ order = 2,
+ type = "toggle",
+ name = L["Bank 1"]
+ },
+ bag6 = {
+ order = 3,
+ type = "toggle",
+ name = L["Bank 2"]
+ },
+ bag7 = {
+ order = 4,
+ type = "toggle",
+ name = L["Bank 3"]
+ },
+ bag8 = {
+ order = 5,
+ type = "toggle",
+ name = L["Bank 4"]
+ },
+ bag9 = {
+ order = 6,
+ type = "toggle",
+ name = L["Bank 5"]
+ },
+ bag10 = {
+ order = 7,
+ type = "toggle",
+ name = L["Bank 6"]
+ },
+ bag11 = {
+ order = 8,
+ type = "toggle",
+ name = L["Bank 7"]
+ }
+ }
+ }
+ }
+ },
+ vendorGrays = {
+ order = 8,
+ type = "group",
+ name = L["Vendor Grays"],
+ get = function(info) return E.db.bags.vendorGrays[info[#info]] end,
+ set = function(info, value) E.db.bags.vendorGrays[info[#info]] = value B:UpdateSellFrameSettings() end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Vendor Grays"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Automatically vendor gray items when visiting a vendor."]
+ },
+ interval = {
+ order = 3,
+ type = "range",
+ name = L["Sell Interval"],
+ desc = L["Will attempt to sell another item in set interval after previous one was sold."],
+ min = 0.1, max = 1, step = 0.1,
+ disabled = function() return not E.db.bags.vendorGrays.enable end
+ },
+ details = {
+ order = 4,
+ type = "toggle",
+ name = L["Vendor Gray Detailed Report"],
+ desc = L["Displays a detailed report of every item sold when enabled."],
+ disabled = function() return not E.db.bags.vendorGrays.enable end
+ },
+ progressBar = {
+ order = 5,
+ type = "toggle",
+ name = L["Progress Bar"],
+ disabled = function() return not E.db.bags.vendorGrays.enable end
+ }
+ }
+ },
+ bagSortingGroup = {
+ order = 9,
+ type = "group",
+ name = L["Bag Sorting"],
+ disabled = function() return not E.Bags.Initialized end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Bag Sorting"]
+ },
+ sortInverted = {
+ order = 2,
+ type = "toggle",
+ name = L["Sort Inverted"],
+ desc = L["Direction the bag sorting will use to allocate the items."]
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = " "
+ },
+ description = {
+ order = 4,
+ type = "description",
+ name = L["Here you can add items or search terms that you want to be excluded from sorting. To remove an item just click on its name in the list."]
+ },
+ addEntryGroup = {
+ order = 5,
+ type = "group",
+ name = L["Add Item or Search Syntax"],
+ guiInline = true,
+ args = {
+ addEntryProfile = {
+ order = 1,
+ type = "input",
+ name = L["Profile"],
+ desc = L["Add an item or search syntax to the ignored list. Items matching the search syntax will be ignored."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if value == "" or gsub(value, "%s+", "") == "" then return end --Don't allow empty entries
+ --Store by itemID if possible
+ local itemID = match(value, "item:(%d+)")
+ E.db.bags.ignoredItems[(itemID or value)] = value
+ end
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = " ",
+ width = "normal"
+ },
+ addEntryGlobal = {
+ order = 3,
+ type = "input",
+ name = L["Global"],
+ desc = L["Add an item or search syntax to the ignored list. Items matching the search syntax will be ignored."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if value == "" or gsub(value, "%s+", "") == "" then return end --Don't allow empty entries
+ --Store by itemID if possible
+ local itemID = match(value, "item:(%d+)")
+ E.global.bags.ignoredItems[(itemID or value)] = value
+ --Remove from profile list if we just added the same item to global list
+ if E.db.bags.ignoredItems[(itemID or value)] then
+ E.db.bags.ignoredItems[(itemID or value)] = nil
+ end
+ end
+ }
+ }
+ },
+ ignoredEntriesProfile = {
+ order = 6,
+ type = "multiselect",
+ name = L["Ignored Items and Search Syntax (Profile)"],
+ values = function() return E.db.bags.ignoredItems end,
+ get = function(info, value) return E.db.bags.ignoredItems[value] end,
+ set = function(info, value)
+ E.db.bags.ignoredItems[value] = nil
+ GameTooltip:Hide()--Make sure tooltip is properly hidden
+ end
+ },
+ ignoredEntriesGlobal = {
+ order = 7,
+ type = "multiselect",
+ name = L["Ignored Items and Search Syntax (Global)"],
+ values = function() return E.global.bags.ignoredItems end,
+ get = function(info, value) return E.global.bags.ignoredItems[value] end,
+ set = function(info, value)
+ E.global.bags.ignoredItems[value] = nil
+ GameTooltip:Hide()--Make sure tooltip is properly hidden
+ end
+ }
+ }
+ },
+ search_syntax = {
+ order = 10,
+ type = "group",
+ name = L["Search Syntax"],
+ disabled = function() return not E.Bags.Initialized end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Search Syntax"]
+ },
+ text = {
+ order = 2,
+ type = "input",
+ multiline = 26,
+ width = "full",
+ name = "",
+ get = function(info) return L["SEARCH_SYNTAX_DESC"] end,
+ set = E.noop
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Chat.lua b/ElvUI_OptionsUI/Chat.lua
new file mode 100644
index 0000000..12d9920
--- /dev/null
+++ b/ElvUI_OptionsUI/Chat.lua
@@ -0,0 +1,718 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+local CH = E:GetModule("Chat")
+local Bags = E:GetModule("Bags")
+local Layout = E:GetModule("Layout")
+
+local gsub, strlower = string.gsub, string.lower
+
+local tabSelectorTable = {}
+
+E.Options.args.chat = {
+ type = "group",
+ name = L["Chat"],
+ childGroups = "tab",
+ get = function(info) return E.db.chat[info[#info]] end,
+ set = function(info, value) E.db.chat[info[#info]] = value end,
+ args = {
+ intro = {
+ order = 1,
+ type = "description",
+ name = L["CHAT_DESC"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.private.chat.enable end,
+ set = function(info, value) E.private.chat.enable = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ general = {
+ order = 3,
+ type = "group",
+ name = L["General"],
+ disabled = function() return not E.Chat.Initialized end,
+ args = {
+ url = {
+ order = 1,
+ type = "toggle",
+ name = L["URL Links"],
+ desc = L["Attempt to create URL links inside the chat."]
+ },
+ shortChannels = {
+ order = 2,
+ type = "toggle",
+ name = L["Short Channels"],
+ desc = L["Shorten the channel names in chat."]
+ },
+ hyperlinkHover = {
+ order = 3,
+ type = "toggle",
+ name = L["Hyperlink Hover"],
+ desc = L["Display the hyperlink tooltip while hovering over a hyperlink."],
+ set = function(info, value)
+ E.db.chat[info[#info]] = value
+ CH:ToggleHyperlink(value)
+ end
+ },
+ sticky = {
+ order = 4,
+ type = "toggle",
+ name = L["Sticky Chat"],
+ desc = L["When opening the Chat Editbox to type a message having this option set means it will retain the last channel you spoke in. If this option is turned off opening the Chat Editbox should always default to the SAY channel."]
+ },
+ emotionIcons = {
+ order = 5,
+ type = "toggle",
+ name = L["Emotion Icons"],
+ desc = L["Display emotion icons in chat."]
+ },
+ fadeUndockedTabs = {
+ order = 6,
+ type = "toggle",
+ name = L["Fade Undocked Tabs"],
+ desc = L["Fades the text on chat tabs that are not docked at the left or right chat panel."],
+ set = function(info, value)
+ E.db.chat.fadeUndockedTabs = value
+ CH:UpdateChatTabs()
+ end
+ },
+ fadeTabsNoBackdrop = {
+ order = 7,
+ type = "toggle",
+ name = L["Fade Tabs No Backdrop"],
+ desc = L["Fades the text on chat tabs that are docked in a panel where the backdrop is disabled."],
+ set = function(info, value)
+ E.db.chat.fadeTabsNoBackdrop = value
+ CH:UpdateChatTabs()
+ end
+ },
+ useAltKey = {
+ order = 8,
+ type = "toggle",
+ name = L["Use Alt Key"],
+ desc = L["Require holding the Alt key down to move cursor or cycle through messages in the editbox."],
+ set = function(info, value)
+ E.db.chat.useAltKey = value
+ CH:UpdateSettings()
+ end
+ },
+ fadeChatToggles = {
+ order = 9,
+ type = "toggle",
+ name = L["Fade Chat Toggles"],
+ desc = L["Fades the buttons that toggle chat windows when that window has been toggled off."],
+ set = function(info, value)
+ E.db.chat.fadeChatToggles = value
+ CH:RefreshToggleButtons()
+ end
+ },
+ spacer = {
+ order = 10,
+ type = "description",
+ name = ""
+ },
+ numAllowedCombatRepeat = {
+ order = 11,
+ type = "range",
+ name = L["Allowed Combat Repeat"],
+ desc = L["Number of repeat characters while in combat before the chat editbox is automatically closed. Set to 0 to disable."],
+ min = 0, max = 10, step = 1,
+ set = function(info, value)
+ if value == 1 then
+ value = 0
+ end
+ E.db.chat[info[#info]] = value
+ end
+ },
+ throttleInterval = {
+ order = 12,
+ type = "range",
+ name = L["Spam Interval"],
+ desc = L["Prevent the same messages from displaying in chat more than once within this set amount of seconds, set to zero to disable."],
+ min = 0, max = 120, step = 1,
+ set = function(info, value)
+ E.db.chat[info[#info]] = value
+ if value == 0 then
+ CH:DisableChatThrottle()
+ end
+ end
+ },
+ scrollDownInterval = {
+ order = 13,
+ type = "range",
+ name = L["Scroll Interval"],
+ desc = L["Number of time in seconds to scroll down to the bottom of the chat window if you are not scrolled down completely."],
+ min = 0, max = 120, step = 5
+ },
+ numScrollMessages = {
+ order = 14,
+ type = "range",
+ name = L["Scroll Messages"],
+ desc = L["Number of messages you scroll for each step."],
+ min = 1, max = 10, step = 1,
+ },
+ maxLines = {
+ order = 15,
+ type = "range",
+ name = L["Max Lines"],
+ min = 10, max = 5000, step = 1,
+ set = function(info, value) E.db.chat[info[#info]] = value CH:SetupChat() end
+ },
+ editboxHistorySize = {
+ order = 16,
+ type = "range",
+ name = L["Editbox History Size"],
+ min = 5, max = 50, step = 1
+ },
+ resetHistory = {
+ order = 17,
+ type = "execute",
+ name = L["Reset Editbox History"],
+ func = function() CH:ResetEditboxHistory() end
+ },
+ historyGroup = {
+ order = 18,
+ type = "group",
+ name = L["History"],
+ set = function(info, value) E.db.chat[info[#info]] = value end,
+ args = {
+ chatHistory = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Log the main chat frames history. So when you reloadui or log in and out you see the history from your last session."]
+ },
+ resetHistory = {
+ order = 2,
+ type = "execute",
+ name = L["Reset History"],
+ func = function() CH:ResetHistory() end,
+ disabled = function() return not E.db.chat.chatHistory end
+ },
+ historySize = {
+ order = 3,
+ type = "range",
+ name = L["History Size"],
+ min = 10, max = 500, step = 1,
+ disabled = function() return not E.db.chat.chatHistory end
+ },
+ historyTypes = {
+ order = 4,
+ type = "multiselect",
+ name = L["Display Types"],
+ get = function(info, key) return
+ E.db.chat.showHistory[key]
+ end,
+ set = function(info, key, value)
+ E.db.chat.showHistory[key] = value
+ end,
+ disabled = function() return not E.db.chat.chatHistory end,
+ values = {
+ WHISPER = L["WHISPER"],
+ GUILD = L["GUILD"],
+ OFFICER = L["OFFICER"],
+ PARTY = L["PARTY"],
+ RAID = L["RAID"],
+ BATTLEGROUND = L["BATTLEGROUND"],
+ CHANNEL = L["CHANNEL"],
+ SAY = L["SAY"],
+ YELL = L["YELL"],
+ EMOTE = L["EMOTE"]
+ }
+ }
+ }
+ },
+ tabSelection = {
+ order = 19,
+ type = "group",
+ name = L["Tab Selector"],
+ set = function(info, value)
+ E.db.chat[info[#info]] = value
+ CH:UpdateChatTabColors()
+ end,
+ args = {
+ tabSelectedTextEnabled = {
+ order = 1,
+ type = "toggle",
+ name = L["Colorize Selected Text"]
+ },
+ tabSelectedTextColor = {
+ order = 2,
+ type = "color",
+ hasAlpha = false,
+ name = L["Selected Text Color"],
+ disabled = function() return not E.db.chat.tabSelectedTextEnabled end,
+ get = function(info)
+ local t = E.db.chat.tabSelectedTextColor
+ local d = P.chat.tabSelectedTextColor
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.chat.tabSelectedTextColor
+ t.r, t.g, t.b = r, g, b
+ CH:UpdateChatTabColors()
+ end
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ tabSelector = {
+ order = 4,
+ type = 'select',
+ name = L["Selector Style"],
+ values = function()
+ wipe(tabSelectorTable)
+
+ for key, value in pairs(CH.TabStyles) do
+ if key == "NONE" then
+ tabSelectorTable[key] = L[key]
+ else
+ local color = E.db.chat.tabSelectorColor
+ local hexColor = E:RGBToHex(color.r, color.g, color.b)
+ local selectedColor = E.media.hexvaluecolor
+
+ if E.db.chat.tabSelectedTextEnabled then
+ color = E.db.chat.tabSelectedTextColor
+ selectedColor = E:RGBToHex(color.r, color.g, color.b)
+ end
+
+ tabSelectorTable[key] = format(value, hexColor, format("%sName|r", selectedColor), hexColor)
+ end
+ end
+
+ return tabSelectorTable
+ end
+ },
+ tabSelectorColor = {
+ order = 5,
+ type = "color",
+ hasAlpha = false,
+ name = L["Selector Color"],
+ disabled = function() return E.db.chat.tabSelector == "NONE" end,
+ get = function(info)
+ local t = E.db.chat.tabSelectorColor
+ local d = P.chat.tabSelectorColor
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.chat.tabSelectorColor
+ t.r, t.g, t.b = r, g, b
+ E:UpdateMedia()
+ end
+ }
+ }
+ },
+ fadingGroup = {
+ order = 20,
+ type = "group",
+ name = L["Text Fade"],
+ disabled = function() return not E.Chat.Initialized end,
+ set = function(info, value) E.db.chat[info[#info]] = value CH:UpdateFading() end,
+ args = {
+ fade = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Fade the chat text when there is no activity."]
+ },
+ inactivityTimer = {
+ order = 2,
+ type = "range",
+ name = L["Inactivity Timer"],
+ desc = L["Controls how many seconds of inactivity has to pass before chat is faded."],
+ disabled = function() return not E.db.chat.fade end,
+ min = 5, softMax = 120, step = 1
+ }
+ }
+ },
+ fontGroup = {
+ order = 21,
+ type = "group",
+ name = L["Fonts"],
+ set = function(info, value) E.db.chat[info[#info]] = value CH:SetupChat() end,
+ disabled = function() return not E.Chat.Initialized end,
+ args = {
+ font = {
+ order = 1,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontOutline = {
+ order = 2,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ tabFont = {
+ order = 4,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Tab Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ tabFontSize = {
+ order = 5,
+ type = "range",
+ name = L["Tab Font Size"],
+ min = 4, max = 22, step = 1
+ },
+ tabFontOutline = {
+ order = 6,
+ type = "select",
+ name = L["Tab Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ }
+ }
+ },
+ alerts = {
+ order = 22,
+ type = "group",
+ name = L["Alerts"],
+ disabled = function() return not E.Chat.Initialized end,
+ args = {
+ noAlertInCombat = {
+ order = 1,
+ type = "toggle",
+ name = L["No Alert In Combat"]
+ },
+ keywordAlerts = {
+ order = 2,
+ type = "group",
+ name = L["Keyword Alert"],
+ guiInline = true,
+ args = {
+ keywordSound = {
+ order = 1,
+ type = "select", dialogControl = "LSM30_Sound",
+ name = L["Keyword Alert"],
+ width = "double",
+ values = AceGUIWidgetLSMlists.sound,
+ },
+ keywords = {
+ order = 2,
+ type = "input",
+ name = L["Keywords"],
+ desc = L["List of words to color in chat if found in a message. If you wish to add multiple words you must seperate the word with a comma. To search for your current name you can use %MYNAME%.\n\nExample:\n%MYNAME%, ElvUI, RBGs, Tank"],
+ width = "full",
+ set = function(info, value) E.db.chat[info[#info]] = value CH:UpdateChatKeywords() end
+ }
+ }
+ },
+ channelAlerts = {
+ order = 3,
+ type = "group",
+ name = L["Channel Alerts"],
+ guiInline = true,
+ get = function(info) return E.db.chat.channelAlerts[info[#info]] end,
+ set = function(info, value) E.db.chat.channelAlerts[info[#info]] = value end,
+ args = {
+ GUILD = {
+ type = "select", dialogControl = "LSM30_Sound",
+ name = L["GUILD"],
+ width = "double",
+ values = AceGUIWidgetLSMlists.sound
+ },
+ OFFICER = {
+ type = "select", dialogControl = "LSM30_Sound",
+ name = L["OFFICER"],
+ width = "double",
+ values = AceGUIWidgetLSMlists.sound
+ },
+ BATTLEGROUND = {
+ type = "select", dialogControl = "LSM30_Sound",
+ name = L["BATTLEGROUND"],
+ width = "double",
+ values = AceGUIWidgetLSMlists.sound
+ },
+ PARTY = {
+ type = "select", dialogControl = "LSM30_Sound",
+ name = L["PARTY"],
+ width = "double",
+ values = AceGUIWidgetLSMlists.sound
+ },
+ RAID = {
+ type = "select", dialogControl = "LSM30_Sound",
+ name = L["RAID"],
+ width = "double",
+ values = AceGUIWidgetLSMlists.sound
+ },
+ WHISPER = {
+ type = "select", dialogControl = "LSM30_Sound",
+ name = L["WHISPER"],
+ width = "double",
+ values = AceGUIWidgetLSMlists.sound
+ }
+ }
+ }
+ }
+ },
+ timestampGroup = {
+ order = 23,
+ type = "group",
+ name = L["TIMESTAMPS_LABEL"],
+ args = {
+ useCustomTimeColor = {
+ order = 1,
+ type = "toggle",
+ name = L["Custom Timestamp Color"],
+ disabled = function() return not E.db.chat.timeStampFormat == "NONE" end
+ },
+ customTimeColor = {
+ order = 2,
+ type = "color",
+ hasAlpha = false,
+ name = L["Timestamp Color"],
+ disabled = function() return (not E.db.chat.timeStampFormat == "NONE" or not E.db.chat.useCustomTimeColor) end,
+ get = function(info)
+ local t = E.db.chat.customTimeColor
+ local d = P.chat.customTimeColor
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.chat.customTimeColor
+ t.r, t.g, t.b = r, g, b
+ end
+ },
+ timeStampFormat = {
+ order = 3,
+ type = "select",
+ name = L["TIMESTAMPS_LABEL"],
+ desc = L["OPTION_TOOLTIP_TIMESTAMPS"],
+ values = {
+ ["NONE"] = L["NONE"],
+ ["%I:%M"] = "03:27",
+ ["%I:%M:%S"] = "03:27:32",
+ ["%I:%M %p"] = "03:27 PM",
+ ["%I:%M:%S %p"] = "03:27:32 PM",
+ ["%H:%M"] = "15:27",
+ ["%H:%M:%S"] = "15:27:32"
+ }
+ }
+ }
+ },
+ classColorMentionGroup = {
+ order = 24,
+ type = "group",
+ name = L["Class Color Mentions"],
+ args = {
+ classColorMentionsChat = {
+ order = 1,
+ type = "toggle",
+ name = L["Chat"],
+ desc = L["Use class color for the names of players when they are mentioned."],
+ get = function(info) return E.db.chat.classColorMentionsChat end,
+ set = function(info, value) E.db.chat.classColorMentionsChat = value end,
+ disabled = function() return not E.private.chat.enable end
+ },
+ classColorMentionsSpeech = {
+ order = 2,
+ type = "toggle",
+ name = L["Chat Bubbles"],
+ desc = L["Use class color for the names of players when they are mentioned."],
+ get = function(info) return E.private.general.classColorMentionsSpeech end,
+ set = function(info, value) E.private.general.classColorMentionsSpeech = value E:StaticPopup_Show("PRIVATE_RL") end,
+ disabled = function() return (E.private.general.chatBubbles == "disabled" or not E.private.chat.enable) end
+ },
+ classColorMentionExcludeName = {
+ order = 3,
+ type = "input",
+ name = L["Exclude Name"],
+ desc = L["Excluded names will not be class colored."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if value == "" or gsub(value, "%s+", "") == "" then return end
+ E.global.chat.classColorMentionExcludedNames[strlower(value)] = value
+ end
+ },
+ classColorMentionExcludedNames = {
+ order = 4,
+ type = "multiselect",
+ name = L["Excluded Names"],
+ values = function() return E.global.chat.classColorMentionExcludedNames end,
+ get = function(info, value) return E.global.chat.classColorMentionExcludedNames[value] end,
+ set = function(info, value)
+ E.global.chat.classColorMentionExcludedNames[value] = nil
+ GameTooltip:Hide()
+ end
+ }
+ }
+ }
+ }
+ },
+ panels = {
+ order = 5,
+ type = "group",
+ name = L["Panels"],
+ disabled = function() return not E.Chat.Initialized end,
+ args = {
+ lockPositions = {
+ order = 1,
+ type = "toggle",
+ name = L["Lock Positions"],
+ desc = L["Attempt to lock the left and right chat frame positions. Disabling this option will allow you to move the main chat frame anywhere you wish."],
+ set = function(info, value)
+ E.db.chat[info[#info]] = value
+ CH:UpdateDockState()
+ if value then
+ CH:PositionChat(true)
+ end
+ end
+ },
+ panelTabBackdrop = {
+ order = 2,
+ type = "toggle",
+ name = L["Tab Panel"],
+ desc = L["Toggle the chat tab panel backdrop."],
+ set = function(info, value) E.db.chat.panelTabBackdrop = value Layout:ToggleChatPanels() end
+ },
+ panelTabTransparency = {
+ order = 3,
+ type = "toggle",
+ name = L["Tab Panel Transparency"],
+ set = function(info, value) E.db.chat.panelTabTransparency = value Layout:SetChatTabStyle() end,
+ disabled = function() return not E.db.chat.panelTabBackdrop end
+ },
+ editBoxPosition = {
+ order = 4,
+ type = "select",
+ name = L["Chat EditBox Position"],
+ desc = L["Position of the Chat EditBox, if datatexts are disabled this will be forced to be above chat."],
+ values = {
+ ["BELOW_CHAT"] = L["Below Chat"],
+ ["ABOVE_CHAT"] = L["Above Chat"]
+ },
+ set = function(info, value) E.db.chat[info[#info]] = value CH:UpdateAnchors() end
+ },
+ panelBackdrop = {
+ order = 5,
+ type = "select",
+ name = L["Panel Backdrop"],
+ desc = L["Toggle showing of the left and right chat panels."],
+ set = function(info, value) E.db.chat.panelBackdrop = value Layout:ToggleChatPanels() CH:PositionChat(true) CH:UpdateAnchors() end,
+ values = {
+ ["HIDEBOTH"] = L["Hide Both"],
+ ["SHOWBOTH"] = L["Show Both"],
+ ["LEFT"] = L["Left Only"],
+ ["RIGHT"] = L["Right Only"]
+ }
+ },
+ separateSizes = {
+ order = 6,
+ type = "toggle",
+ name = L["Separate Panel Sizes"],
+ desc = L["Enable the use of separate size options for the right chat panel."],
+ set = function(info, value)
+ E.db.chat.separateSizes = value
+ CH:PositionChat(true)
+ Bags:Layout()
+ end
+ },
+ spacer1 = {
+ order = 7,
+ type = "description",
+ name = ""
+ },
+ panelHeight = {
+ order = 8,
+ type = "range",
+ name = L["Panel Height"],
+ desc = L["PANEL_DESC"],
+ set = function(info, value) E.db.chat.panelHeight = value CH:PositionChat(true) end,
+ min = 50, max = 600, step = 1
+ },
+ panelWidth = {
+ order = 9,
+ type = "range",
+ name = L["Panel Width"],
+ desc = L["PANEL_DESC"],
+ set = function(info, value)
+ E.db.chat.panelWidth = value
+ CH:PositionChat(true)
+ if not E.db.chat.separateSizes then
+ Bags:Layout()
+ end
+ Bags:Layout(true)
+ end,
+ min = 50, max = 1000, step = 1
+ },
+ panelColor = {
+ order = 10,
+ type = "color",
+ name = L["Backdrop Color"],
+ hasAlpha = true,
+ get = function(info)
+ local t = E.db.chat.panelColor
+ local d = P.chat.panelColor
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.db.chat.panelColor
+ t.r, t.g, t.b, t.a = r, g, b, a
+ CH:Panels_ColorUpdate()
+ end
+ },
+ spacer2 = {
+ order = 11,
+ type = "description",
+ name = ""
+ },
+ panelHeightRight = {
+ order = 12,
+ type = "range",
+ name = L["Right Panel Height"],
+ desc = L["Adjust the height of your right chat panel."],
+ disabled = function() return not E.db.chat.separateSizes end,
+ hidden = function() return not E.db.chat.separateSizes end,
+ set = function(info, value) E.db.chat.panelHeightRight = value CH:PositionChat(true) end,
+ min = 50, max = 600, step = 1
+ },
+ panelWidthRight = {
+ order = 13,
+ type = "range",
+ name = L["Right Panel Width"],
+ desc = L["Adjust the width of your right chat panel."],
+ disabled = function() return not E.db.chat.separateSizes end,
+ hidden = function() return not E.db.chat.separateSizes end,
+ set = function(info, value)
+ E.db.chat.panelWidthRight = value
+ CH:PositionChat(true)
+ Bags:Layout()
+ end,
+ min = 50, max = 1000, step = 1
+ },
+ panelBackdropNameLeft = {
+ order = 14,
+ type = "input",
+ width = "full",
+ name = L["Panel Texture (Left)"],
+ desc = L["Specify a filename located inside the World of Warcraft directory. Textures folder that you wish to have set as a panel background.\n\nPlease Note:\n-The image size recommended is 256x128\n-You must do a complete game restart after adding a file to the folder.\n-The file type must be tga format.\n\nExample: Interface\\AddOns\\ElvUI\\Media\\Textures\\Copy\n\nOr for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here."],
+ set = function(info, value)
+ E.db.chat[info[#info]] = value
+ E:UpdateMedia()
+ end
+ },
+ panelBackdropNameRight = {
+ order = 15,
+ type = "input",
+ width = "full",
+ name = L["Panel Texture (Right)"],
+ desc = L["Specify a filename located inside the World of Warcraft directory. Textures folder that you wish to have set as a panel background.\n\nPlease Note:\n-The image size recommended is 256x128\n-You must do a complete game restart after adding a file to the folder.\n-The file type must be tga format.\n\nExample: Interface\\AddOns\\ElvUI\\Media\\Textures\\Copy\n\nOr for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here."],
+ set = function(info, value)
+ E.db.chat[info[#info]] = value
+ E:UpdateMedia()
+ end
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Cooldown.lua b/ElvUI_OptionsUI/Cooldown.lua
new file mode 100644
index 0000000..9eb45de
--- /dev/null
+++ b/ElvUI_OptionsUI/Cooldown.lua
@@ -0,0 +1,317 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+
+local pairs = pairs
+
+local function profile(db)
+ return (db == "global" and E.db.cooldown) or E.db[db].cooldown
+end
+
+local function private(db)
+ return (db == "global" and P.cooldown) or P[db].cooldown
+end
+
+local function group(order, db, label)
+ E.Options.args.cooldown.args[db] = {
+ order = order,
+ type = "group",
+ name = label,
+ get = function(info)
+ local t = (profile(db))[info[#info]]
+ local d = (private(db))[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = (profile(db))[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ E:UpdateCooldownSettings(db)
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = label
+ },
+ reverse = {
+ order = 2,
+ type = "toggle",
+ name = L["Reverse Toggle"],
+ desc = L["Reverse Toggle will enable Cooldown Text on this module when the global setting is disabled and disable them when the global setting is enabled."],
+ get = function(info) return (profile(db))[info[#info]] end,
+ set = function(info, value) (profile(db))[info[#info]] = value; E:UpdateCooldownSettings(db) end
+ },
+ secondsGroup = {
+ order = 5,
+ type = "group",
+ name = L["Text Threshold"],
+ guiInline = true,
+ get = function(info) return (profile(db))[info[#info]] end,
+ set = function(info, value) (profile(db))[info[#info]] = value; E:UpdateCooldownSettings(db) end,
+ args = {
+ checkSeconds = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["This will override the global cooldown settings."],
+ disabled = E.noop
+ },
+ threshold = {
+ order = 2,
+ type = "range",
+ name = L["Low Threshold"],
+ desc = L["Threshold before text turns red and is in decimal form. Set to -1 for it to never turn red"],
+ min = -1, max = 20, step = 1,
+ disabled = function() return not (profile(db)).override end,
+ get = function(info) return (profile(db))[info[#info]] end,
+ set = function(info, value) (profile(db))[info[#info]] = value; E:UpdateCooldownSettings(db) end,
+ },
+ mmssThreshold = {
+ order = 3,
+ type = "range",
+ name = L["MM:SS Threshold"],
+ desc = L["Threshold (in seconds) before text is shown in the MM:SS format. Set to -1 to never change to this format."],
+ min = -1, max = 10800, step = 1,
+ disabled = function() return not (profile(db)).checkSeconds end
+ },
+ hhmmThreshold = {
+ order = 4,
+ type = "range",
+ name = L["HH:MM Threshold"],
+ desc = L["Threshold (in minutes) before text is shown in the HH:MM format. Set to -1 to never change to this format."],
+ min = -1, max = 1440, step = 1,
+ disabled = function() return not (profile(db)).checkSeconds end
+ }
+ }
+ },
+ colorGroup = {
+ order = 10,
+ type = "group",
+ name = L["Color Override"],
+ guiInline = true,
+ args = {
+ override = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["This will override the global cooldown settings."],
+ get = function(info) return (profile(db))[info[#info]] end,
+ set = function(info, value) (profile(db))[info[#info]] = value; E:UpdateCooldownSettings(db) end,
+ },
+ spacer1 = {
+ order = 2,
+ type = "description",
+ name = " "
+ },
+ expiringColor = {
+ order = 3,
+ type = "color",
+ name = L["Expiring"],
+ desc = L["Color when the text is about to expire"],
+ disabled = function() return not (profile(db)).override end,
+ },
+ secondsColor = {
+ order = 4,
+ type = "color",
+ name = L["Seconds"],
+ desc = L["Color when the text is in the seconds format."],
+ disabled = function() return not (profile(db)).override end,
+ },
+ minutesColor = {
+ order = 5,
+ type = "color",
+ name = L["Minutes"],
+ desc = L["Color when the text is in the minutes format."],
+ disabled = function() return not (profile(db)).override end,
+ },
+ hoursColor = {
+ order = 6,
+ type = "color",
+ name = L["Hours"],
+ desc = L["Color when the text is in the hours format."],
+ disabled = function() return not (profile(db)).override end,
+ },
+ daysColor = {
+ order = 7,
+ type = "color",
+ name = L["Days"],
+ desc = L["Color when the text is in the days format."],
+ disabled = function() return not (profile(db)).override end,
+ },
+ mmssColor = {
+ order = 8,
+ type = "color",
+ name = L["MM:SS"],
+ disabled = function() return not (profile(db)).override end,
+ },
+ hhmmColor = {
+ order = 9,
+ type = "color",
+ name = L["HH:MM"],
+ disabled = function() return not (profile(db)).override end,
+ },
+ spacer3 = {
+ order = 10,
+ type = "header",
+ name = L["Time Indicator Colors"]
+ },
+ useIndicatorColor = {
+ order = 11,
+ type = "toggle",
+ name = L["Use Indicator Color"],
+ get = function(info) return (profile(db))[info[#info]] end,
+ set = function(info, value) (profile(db))[info[#info]] = value; E:UpdateCooldownSettings(db) end,
+ disabled = function() return not (profile(db)).override end,
+ },
+ spacer4 = {
+ order = 12,
+ type = "description",
+ name = " "
+ },
+ expireIndicator = {
+ order = 13,
+ type = "color",
+ name = L["Expiring"],
+ desc = L["Color when the text is about to expire"],
+ disabled = function() return not (profile(db)).override end,
+ },
+ secondsIndicator = {
+ order = 14,
+ type = "color",
+ name = L["Seconds"],
+ desc = L["Color when the text is in the seconds format."],
+ disabled = function() return not (profile(db)).override end,
+ },
+ minutesIndicator = {
+ order = 15,
+ type = "color",
+ name = L["Minutes"],
+ desc = L["Color when the text is in the minutes format."],
+ disabled = function() return not (profile(db)).override end,
+ },
+ hoursIndicator = {
+ order = 16,
+ type = "color",
+ name = L["Hours"],
+ desc = L["Color when the text is in the hours format."],
+ disabled = function() return not (profile(db)).override end,
+ },
+ daysIndicator = {
+ order = 17,
+ type = "color",
+ name = L["Days"],
+ desc = L["Color when the text is in the days format."],
+ disabled = function() return not (profile(db)).override end,
+ },
+ hhmmColorIndicator = {
+ order = 18,
+ type = "color",
+ name = L["MM:SS"],
+ disabled = function() return not (profile(db)).override end,
+ },
+ mmssColorIndicator = {
+ order = 19,
+ type = "color",
+ name = L["HH:MM"],
+ disabled = function() return not (profile(db)).override end,
+ },
+ }
+ },
+ fontGroup = {
+ order = 20, -- keep this at the bottom
+ type = "group",
+ name = L["Fonts"],
+ guiInline = true,
+ get = function(info) return (profile(db)).fonts[info[#info]] end,
+ set = function(info, value) (profile(db)).fonts[info[#info]] = value; E:UpdateCooldownSettings(db) end,
+ disabled = function() return not (profile(db)).fonts.enable end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["This will override the global cooldown settings."],
+ disabled = E.noop
+ },
+ spacer1 = {
+ order = 2,
+ type = "description",
+ name = " "
+ },
+ fontSize = {
+ order = 3,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 10, max = 32, step = 1
+ },
+ font = {
+ order = 4,
+ type = "select",
+ name = L["Font"],
+ dialogControl = "LSM30_Font",
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontOutline = {
+ order = 5,
+ type = "select",
+ name = L["Font Outline"],
+ values = C.Values.FontFlags
+ }
+ }
+ }
+ }
+ }
+
+ if db == "global" then
+ -- clean up the main one
+ E.Options.args.cooldown.args[db].args.reverse = nil
+ E.Options.args.cooldown.args[db].args.secondsGroup.args.threshold.disabled = nil
+ E.Options.args.cooldown.args[db].args.colorGroup.args.override = nil
+ E.Options.args.cooldown.args[db].args.colorGroup.args.spacer1 = nil
+
+ -- remove disables
+ for _, x in pairs(E.Options.args.cooldown.args[db].args.colorGroup.args) do
+ if x.disabled then x.disabled = nil end
+ end
+
+ -- rename the tab
+ E.Options.args.cooldown.args[db].args.colorGroup.name = L["COLORS"]
+ else
+ E.Options.args.cooldown.args[db].args.colorGroup.args.spacer2 = nil
+ end
+
+ if db == "auras" or db == "nameplates" then
+ -- even though the top auras can support hiding the text don't allow this to be a setting to prevent confusion
+ E.Options.args.cooldown.args[db].args.reverse = nil
+
+ -- this is basically creates a second way to change font, we only really need one
+ E.Options.args.cooldown.args[db].args.fontGroup = nil
+ end
+end
+
+E.Options.args.cooldown = {
+ type = "group",
+ name = L["Cooldown Text"],
+ childGroups = "tab",
+ get = function(info) return E.db.cooldown[info[#info]] end,
+ set = function(info, value) E.db.cooldown[info[#info]] = value; E:UpdateCooldownSettings("global") end,
+ args = {
+ intro = {
+ order = 1,
+ type = "description",
+ name = L["COOLDOWN_DESC"],
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Display cooldown text on anything with the cooldown spiral."]
+ }
+ }
+}
+
+group(5, "global", L["Global"])
+group(6, "auras", L["BUFFOPTIONS_LABEL"])
+group(7, "actionbar", L["ActionBars"])
+group(8, "bags", L["Bags"])
+group(9, "nameplates", L["NamePlates"])
+group(10, "unitframe", L["UnitFrames"])
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Core.lua b/ElvUI_OptionsUI/Core.lua
new file mode 100644
index 0000000..bc46a1f
--- /dev/null
+++ b/ElvUI_OptionsUI/Core.lua
@@ -0,0 +1,491 @@
+local E = unpack(ElvUI) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local D = E:GetModule("Distributor")
+
+local _, Engine = ...
+Engine[1] = {}
+Engine[2] = E.Libs.ACL:GetLocale("ElvUI", E.global.general.locale or "enUS")
+local C, L = Engine[1], Engine[2]
+
+local format = string.format
+
+C.Values = {
+ FontFlags = {
+ ["NONE"] = L["NONE"],
+ ["OUTLINE"] = "OUTLINE",
+ ["MONOCHROMEOUTLINE"] = "MONOCROMEOUTLINE",
+ ["THICKOUTLINE"] = "THICKOUTLINE"
+ }
+}
+
+E:AddLib("AceGUI", "AceGUI-3.0")
+E:AddLib("AceConfig", "AceConfig-3.0-ElvUI")
+E:AddLib("AceConfigDialog", "AceConfigDialog-3.0-ElvUI")
+E:AddLib("AceConfigRegistry", "AceConfigRegistry-3.0-ElvUI")
+E:AddLib("AceDBOptions", "AceDBOptions-3.0")
+
+local UnitName = UnitName
+local UnitExists = UnitExists
+local UnitIsUnit = UnitIsUnit
+local UnitIsFriend = UnitIsFriend
+local UnitIsPlayer = UnitIsPlayer
+local GameTooltip_Hide = GameTooltip_Hide
+local GameFontHighlightSmall = _G.GameFontHighlightSmall
+
+--Function we can call on profile change to update GUI
+function E:RefreshGUI()
+ E:RefreshCustomTextsConfigs()
+ E.Libs.AceConfigRegistry:NotifyChange("ElvUI")
+end
+
+E.Libs.AceConfig:RegisterOptionsTable("ElvUI", E.Options)
+E.Libs.AceConfigDialog:SetDefaultSize("ElvUI", E:GetConfigDefaultSize())
+
+E.Options.args = {
+ ElvUI_Header = {
+ order = 1,
+ type = "header",
+ name = format("%s: |cff99ff33%s|r", L["Version"], E.version),
+ width = "full"
+ },
+ RepositionWindow = {
+ order = 2,
+ type = "execute",
+ name = L["Reposition Window"],
+ desc = L["Reset the size and position of this frame."],
+ customWidth = 175,
+ func = function()
+ E:UpdateConfigSize(true)
+ end
+ },
+ ToggleTutorial = {
+ order = 3,
+ type = "execute",
+ name = L["Toggle Tutorials"],
+ customWidth = 150,
+ func = function()
+ E:Tutorials(true)
+ E:ToggleOptionsUI()
+ end
+ },
+ Install = {
+ order = 4,
+ type = "execute",
+ name = L["Install"],
+ customWidth = 100,
+ desc = L["Run the installation process."],
+ func = function()
+ E:Install()
+ E:ToggleOptionsUI()
+ end
+ },
+ ResetAllMovers = {
+ order = 5,
+ type = "execute",
+ name = L["Reset Anchors"],
+ customWidth = 150,
+ desc = L["Reset all frames to their original positions."],
+ func = function()
+ E:ResetUI()
+ end
+ },
+ ToggleAnchors = {
+ order = 6,
+ type = "execute",
+ name = L["Toggle Anchors"],
+ customWidth = 150,
+ desc = L["Unlock various elements of the UI to be repositioned."],
+ func = function()
+ E:ToggleMoveMode()
+ end
+ },
+ LoginMessage = {
+ order = 7,
+ type = "toggle",
+ name = L["Login Message"],
+ customWidth = 150,
+ get = function(info)
+ return E.db.general.loginmessage
+ end,
+ set = function(info, value)
+ E.db.general.loginmessage = value
+ end
+ }
+}
+
+local DEVELOPERS = {
+ "Tukz",
+ "Haste",
+ "Nightcracker",
+ "Omega1970",
+ "Hydrazine",
+ "Blazeflack",
+ "NihilisticPandemonium",
+ "|cffff7d0aMerathilis|r",
+ "|cFF8866ccSimpy|r",
+ "|cFF0070DEAzilroka|r"
+}
+local TESTERS = {
+}
+local DONATORS = {
+}
+
+do
+ local DEVELOPER_STRING
+ local TESTER_STRING
+ local DONATOR_STRING
+
+ if #DEVELOPERS > 0 then
+ table.sort(DEVELOPERS)
+ DEVELOPER_STRING = table.concat(DEVELOPERS, "\n")
+ end
+ if #TESTERS > 0 then
+ table.sort(TESTERS)
+ TESTER_STRING = table.concat(TESTERS, "\n")
+ end
+ if #DONATORS > 0 then
+ table.sort(DONATORS)
+ DONATOR_STRING = table.concat(DONATORS, "\n")
+ end
+
+ local CREDITS_STRING = format("%s%s%s%s",
+ L["ELVUI_CREDITS"],
+ (DEVELOPER_STRING and format("\n\n %s\n%s", L["Coding:"], DEVELOPER_STRING) or ""),
+ (TESTER_STRING and format("\n\n %s\n%s", L["Testing:"], TESTER_STRING) or ""),
+ (DONATOR_STRING and format("\n\n %s\n%s", L["Donations:"], DONATOR_STRING) or "")
+ )
+
+ E.Options.args.credits = {
+ order = -1,
+ type = "group",
+ name = L["Credits"],
+ args = {
+ text = {
+ order = 1,
+ type = "description",
+ name = CREDITS_STRING
+ }
+ }
+ }
+end
+
+local profileTypeItems = {
+ ["profile"] = L["Profile"],
+ ["private"] = L["Private (Character Settings)"],
+ ["global"] = L["Global (Account Settings)"],
+ ["filters"] = L["Aura Filters"],
+ ["styleFilters"] = L["NamePlate Style Filters"]
+}
+local profileTypeListOrder = {
+ "profile",
+ "private",
+ "global",
+ "filters",
+ "styleFilters"
+}
+local exportTypeItems = {
+ ["text"] = L["Text"],
+ ["luaTable"] = L["Table"],
+ ["luaPlugin"] = L["Plugin"]
+}
+local exportTypeListOrder = {
+ "text",
+ "luaTable",
+ "luaPlugin"
+}
+
+local exportString = ""
+local function ExportImport_Open(mode)
+ local Frame = E.Libs.AceGUI:Create("Frame")
+ Frame:SetTitle(" ")
+ Frame:EnableResize(false)
+ Frame:SetWidth(800)
+ Frame:SetHeight(600)
+ Frame.frame:SetFrameStrata("FULLSCREEN_DIALOG")
+ Frame:SetLayout("flow")
+
+ local Box = E.Libs.AceGUI:Create("MultiLineEditBox")
+ Box:SetNumLines(30)
+ Box:DisableButton(true)
+ Box:SetWidth(800)
+ Box:SetLabel(" ")
+ Frame:AddChild(Box)
+ --Save original script so we can restore it later
+ Box.editBox.OnTextChangedOrig = Box.editBox:GetScript("OnTextChanged")
+ Box.editBox.OnCursorChangedOrig = Box.editBox:GetScript("OnCursorChanged")
+ --Remove OnCursorChanged script as it causes weird behaviour with long text
+ Box.editBox:SetScript("OnCursorChanged", nil)
+
+ local Label1 = E.Libs.AceGUI:Create("Label")
+ local font = GameFontHighlightSmall:GetFont()
+ Label1:SetFont(font, 14)
+ Label1:SetText(" ") --Set temporary text so height is set correctly
+ Label1:SetWidth(800)
+ Frame:AddChild(Label1)
+
+ local Label2 = E.Libs.AceGUI:Create("Label")
+ font = GameFontHighlightSmall:GetFont()
+ Label2:SetFont(font, 14)
+ Label2:SetText(" \n ")
+ Label2:SetWidth(800)
+ Frame:AddChild(Label2)
+
+ if mode == "export" then
+ Frame:SetTitle(L["Export Profile"])
+
+ local ProfileTypeDropdown = E.Libs.AceGUI:Create("Dropdown")
+ ProfileTypeDropdown:SetMultiselect(false)
+ ProfileTypeDropdown:SetLabel(L["Choose What To Export"])
+ ProfileTypeDropdown:SetList(profileTypeItems, profileTypeListOrder)
+ ProfileTypeDropdown:SetValue("profile") --Default export
+ Frame:AddChild(ProfileTypeDropdown)
+
+ local ExportFormatDropdown = E.Libs.AceGUI:Create("Dropdown")
+ ExportFormatDropdown:SetMultiselect(false)
+ ExportFormatDropdown:SetLabel(L["Choose Export Format"])
+ ExportFormatDropdown:SetList(exportTypeItems, exportTypeListOrder)
+ ExportFormatDropdown:SetValue("text") --Default format
+ ExportFormatDropdown:SetWidth(150)
+ Frame:AddChild(ExportFormatDropdown)
+
+ local exportButton = E.Libs.AceGUI:Create("Button")
+ exportButton:SetText(L["Export Now"])
+ exportButton:SetAutoWidth(true)
+ local function OnClick(self)
+ --Clear labels
+ Label1:SetText(" ")
+ Label2:SetText(" ")
+
+ local profileType, exportFormat = ProfileTypeDropdown:GetValue(), ExportFormatDropdown:GetValue()
+ local profileKey, profileExport = D:ExportProfile(profileType, exportFormat)
+ if not profileKey or not profileExport then
+ Label1:SetText(L["Error exporting profile!"])
+ else
+ Label1:SetText(
+ format("%s: %s%s|r", L["Exported"], E.media.hexvaluecolor, profileTypeItems[profileType])
+ )
+ if profileType == "profile" then
+ Label2:SetText(format("%s: %s%s|r", L["Profile Name"], E.media.hexvaluecolor, profileKey))
+ end
+ end
+ Box:SetText(profileExport)
+ Box.editBox:HighlightText()
+ Box:SetFocus()
+ exportString = profileExport
+ end
+ exportButton:SetCallback("OnClick", OnClick)
+ Frame:AddChild(exportButton)
+
+ --Set scripts
+ Box.editBox:SetScript("OnChar", function()
+ Box:SetText(exportString)
+ Box.editBox:HighlightText()
+ end)
+ Box.editBox:SetScript("OnTextChanged", function(self, userInput)
+ if userInput then
+ --Prevent user from changing export string
+ Box:SetText(exportString)
+ Box.editBox:HighlightText()
+ end
+ end)
+ elseif mode == "import" then
+ Frame:SetTitle(L["Import Profile"])
+ local importButton = E.Libs.AceGUI:Create("Button-ElvUI") --This version changes text color on SetDisabled
+ importButton:SetDisabled(true)
+ importButton:SetText(L["Import Now"])
+ importButton:SetAutoWidth(true)
+ importButton:SetCallback("OnClick", function()
+ --Clear labels
+ Label1:SetText(" ")
+ Label2:SetText(" ")
+
+ local text
+ local success = D:ImportProfile(Box:GetText())
+ if success then
+ text = L["Profile imported successfully!"]
+ else
+ text = L["Error decoding data. Import string may be corrupted!"]
+ end
+ Label1:SetText(text)
+ end)
+ Frame:AddChild(importButton)
+
+ local decodeButton = E.Libs.AceGUI:Create("Button-ElvUI")
+ decodeButton:SetDisabled(true)
+ decodeButton:SetText(L["Decode Text"])
+ decodeButton:SetAutoWidth(true)
+ decodeButton:SetCallback("OnClick", function()
+ --Clear labels
+ Label1:SetText(" ")
+ Label2:SetText(" ")
+ local decodedText
+ local profileType, profileKey, profileData = D:Decode(Box:GetText())
+ if profileData then
+ decodedText = E:TableToLuaString(profileData)
+ end
+ local importText = D:CreateProfileExport(decodedText, profileType, profileKey)
+ Box:SetText(importText)
+ end)
+ Frame:AddChild(decodeButton)
+
+ local oldText = ""
+ local function OnTextChanged()
+ local text = Box:GetText()
+ if text == "" then
+ Label1:SetText(" ")
+ Label2:SetText(" ")
+ importButton:SetDisabled(true)
+ decodeButton:SetDisabled(true)
+ elseif oldText ~= text then
+ local stringType = D:GetImportStringType(text)
+ if stringType == "Base64" then
+ decodeButton:SetDisabled(false)
+ else
+ decodeButton:SetDisabled(true)
+ end
+
+ local profileType, profileKey = D:Decode(text)
+ if not profileType or (profileType and profileType == "profile" and not profileKey) then
+ Label1:SetText(L["Error decoding data. Import string may be corrupted!"])
+ Label2:SetText(" ")
+ importButton:SetDisabled(true)
+ decodeButton:SetDisabled(true)
+ else
+ Label1:SetText(
+ format("%s: %s%s|r", L["Importing"], E.media.hexvaluecolor, profileTypeItems[profileType] or "")
+ )
+ if profileType == "profile" then
+ Label2:SetText(format("%s: %s%s|r", L["Profile Name"], E.media.hexvaluecolor, profileKey))
+ end
+ importButton:SetDisabled(false)
+ end
+
+ --Scroll frame doesn't scroll to the bottom by itself, so let's do that now
+ Box.scrollFrame:UpdateScrollChildRect()
+ Box.scrollFrame:SetVerticalScroll(Box.scrollFrame:GetVerticalScrollRange())
+
+ oldText = text
+ end
+ end
+
+ Box.editBox:SetFocus()
+ --Set scripts
+ Box.editBox:SetScript("OnChar", nil)
+ Box.editBox:SetScript("OnTextChanged", OnTextChanged)
+ end
+
+ Frame:SetCallback("OnClose", function(widget)
+ --Restore changed scripts
+ Box.editBox:SetScript("OnChar", nil)
+ Box.editBox:SetScript("OnTextChanged", Box.editBox.OnTextChangedOrig)
+ Box.editBox:SetScript("OnCursorChanged", Box.editBox.OnCursorChangedOrig)
+ Box.editBox.OnTextChangedOrig = nil
+ Box.editBox.OnCursorChangedOrig = nil
+
+ --Clear stored export string
+ exportString = ""
+
+ E.Libs.AceGUI:Release(widget)
+ E.Libs.AceConfigDialog:Open("ElvUI")
+ end)
+
+ --Clear default text
+ Label1:SetText(" ")
+ Label2:SetText(" ")
+
+ --Close ElvUI OptionsUI
+ E.Libs.AceConfigDialog:Close("ElvUI")
+
+ GameTooltip_Hide() --The tooltip from the Export/Import button stays on screen, so hide it
+end
+
+--Create Profiles Table
+E.Options.args.profiles = E.Libs.AceDBOptions:GetOptionsTable(E.data)
+E.Libs.AceConfig:RegisterOptionsTable("ElvProfiles", E.Options.args.profiles)
+E.Options.args.profiles.order = -10
+
+E.Libs.DualSpec:EnhanceOptions(E.Options.args.profiles, E.data)
+
+if not E.Options.args.profiles.plugins then
+ E.Options.args.profiles.plugins = {}
+end
+
+E.Options.args.profiles.plugins.ElvUI = {
+ spacer = {
+ order = 89,
+ type = "description",
+ name = "\n\n"
+ },
+ desc = {
+ order = 90,
+ type = "description",
+ name = L["This feature will allow you to transfer settings to other characters."]
+ },
+ distributeProfile = {
+ order = 91,
+ type = "execute",
+ name = L["Share Current Profile"],
+ desc = L["Sends your current profile to your target."],
+ func = function()
+ if not UnitExists("target") or not UnitIsPlayer("target")
+ or not UnitIsFriend("player", "target") or UnitIsUnit("player", "target") then
+ E:Print(L["You must be targeting a player."])
+ return
+ end
+
+ local name, server = UnitName("target")
+ if name and (not server or server == "") then
+ D:Distribute(name)
+ elseif server then
+ D:Distribute(name, true)
+ end
+ end
+ },
+ distributeGlobal = {
+ order = 92,
+ type = "execute",
+ name = L["Share Filters"],
+ desc = L["Sends your filter settings to your target."],
+ func = function()
+ if not UnitExists("target") or not UnitIsPlayer("target")
+ or not UnitIsFriend("player", "target") or UnitIsUnit("player", "target") then
+ E:Print(L["You must be targeting a player."])
+ return
+ end
+
+ local name, server = UnitName("target")
+ if name and (not server or server == "") then
+ D:Distribute(name, false, true)
+ elseif server then
+ D:Distribute(name, true, true)
+ end
+ end
+ },
+ spacer2 = {
+ order = 93,
+ type = "description",
+ name = ""
+ },
+ exportProfile = {
+ order = 94,
+ type = "execute",
+ name = L["Export Profile"],
+ func = function()
+ ExportImport_Open("export")
+ end
+ },
+ importProfile = {
+ order = 95,
+ type = "execute",
+ name = L["Import Profile"],
+ func = function()
+ ExportImport_Open("import")
+ end
+ }
+}
+
+do
+ local _, _, enabled = GetAddOnInfo("ElvUI_Config")
+ if enabled then
+ E:StaticPopup_Show("ELVUI_CONFIG_FOUND")
+ end
+end
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/DataBars.lua b/ElvUI_OptionsUI/DataBars.lua
new file mode 100644
index 0000000..bbff74b
--- /dev/null
+++ b/ElvUI_OptionsUI/DataBars.lua
@@ -0,0 +1,227 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+local mod = E:GetModule("DataBars")
+
+E.Options.args.databars = {
+ type = "group",
+ name = L["DataBars"],
+ childGroups = "tab",
+ get = function(info) return E.db.databars[info[#info]] end,
+ set = function(info, value) E.db.databars[info[#info]] = value end,
+ args = {
+ intro = {
+ order = 1,
+ type = "description",
+ name = L["DATABAR_DESC"]
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = ""
+ },
+ experience = {
+ order = 3,
+ type = "group",
+ name = L["XPBAR_LABEL"],
+ get = function(info) return mod.db.experience[info[#info]] end,
+ set = function(info, value) mod.db.experience[info[#info]] = value mod:UpdateExperienceDimensions() end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["XPBAR_LABEL"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value) mod.db.experience[info[#info]] = value mod:EnableDisable_ExperienceBar() end
+ },
+ mouseover = {
+ order = 3,
+ type = "toggle",
+ name = L["Mouseover"]
+ },
+ hideAtMaxLevel = {
+ order = 4,
+ type = "toggle",
+ name = L["Hide At Max Level"],
+ set = function(info, value) mod.db.experience[info[#info]] = value mod:UpdateExperience() end
+ },
+ hideInVehicle = {
+ order = 5,
+ type = "toggle",
+ name = L["Hide In Vehicle"],
+ set = function(info, value) mod.db.experience[info[#info]] = value mod:UpdateExperience() end
+ },
+ hideInCombat = {
+ order = 6,
+ type = "toggle",
+ name = L["Hide In Combat"],
+ set = function(info, value) mod.db.experience[info[#info]] = value mod:UpdateExperience() end
+ },
+ spacer = {
+ order = 7,
+ type = "description",
+ name = " "
+ },
+ orientation = {
+ order = 8,
+ type = "select",
+ name = L["Statusbar Fill Orientation"],
+ desc = L["Direction the bar moves on gains/losses"],
+ values = {
+ ["HORIZONTAL"] = L["Horizontal"],
+ ["VERTICAL"] = L["Vertical"]
+ }
+ },
+ width = {
+ order = 9,
+ type = "range",
+ name = L["Width"],
+ min = 5, max = ceil(GetScreenWidth() or 800), step = 1
+ },
+ height = {
+ order = 10,
+ type = "range",
+ name = L["Height"],
+ min = 5, max = ceil(GetScreenHeight() or 800), step = 1
+ },
+ font = {
+ order = 11,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ textSize = {
+ order = 12,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 6, max = 22, step = 1
+ },
+ fontOutline = {
+ order = 13,
+ type = "select",
+ name = L["Font Outline"],
+ values = C.Values.FontFlags
+ },
+ textFormat = {
+ order = 14,
+ type = "select",
+ name = L["Text Format"],
+ width = "double",
+ values = {
+ NONE = L["NONE"],
+ CUR = L["Current"],
+ REM = L["Remaining"],
+ PERCENT = L["Percent"],
+ CURMAX = L["Current - Max"],
+ CURPERC = L["Current - Percent"],
+ CURREM = L["Current - Remaining"],
+ CURPERCREM = L["Current - Percent (Remaining)"],
+ },
+ set = function(info, value) mod.db.experience[info[#info]] = value mod:UpdateExperience() end
+ }
+ }
+ },
+ reputation = {
+ order = 4,
+ type = "group",
+ name = L["REPUTATION"],
+ get = function(info) return mod.db.reputation[info[#info]] end,
+ set = function(info, value) mod.db.reputation[info[#info]] = value mod:UpdateReputationDimensions() end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["REPUTATION"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value) mod.db.reputation[info[#info]] = value mod:EnableDisable_ReputationBar() end
+ },
+ mouseover = {
+ order = 3,
+ type = "toggle",
+ name = L["Mouseover"]
+ },
+ hideInVehicle = {
+ order = 4,
+ type = "toggle",
+ name = L["Hide In Vehicle"],
+ set = function(info, value) mod.db.reputation[info[#info]] = value mod:UpdateReputation() end
+ },
+ hideInCombat = {
+ order = 5,
+ type = "toggle",
+ name = L["Hide In Combat"],
+ set = function(info, value) mod.db.reputation[info[#info]] = value mod:UpdateReputation() end
+ },
+ spacer = {
+ order = 6,
+ type = "description",
+ name = " "
+ },
+ orientation = {
+ order = 7,
+ type = "select",
+ name = L["Statusbar Fill Orientation"],
+ desc = L["Direction the bar moves on gains/losses"],
+ values = {
+ ["HORIZONTAL"] = L["Horizontal"],
+ ["VERTICAL"] = L["Vertical"]
+ }
+ },
+ width = {
+ order = 8,
+ type = "range",
+ name = L["Width"],
+ min = 5, max = ceil(GetScreenWidth() or 800), step = 1
+ },
+ height = {
+ order = 9,
+ type = "range",
+ name = L["Height"],
+ min = 5, max = ceil(GetScreenHeight() or 800), step = 1
+ },
+ font = {
+ order = 10,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ textSize = {
+ order = 11,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 6, max = 22, step = 1
+ },
+ fontOutline = {
+ order = 12,
+ type = "select",
+ name = L["Font Outline"],
+ values = C.Values.FontFlags
+ },
+ textFormat = {
+ order = 13,
+ type = "select",
+ name = L["Text Format"],
+ width = "double",
+ values = {
+ NONE = L["NONE"],
+ CUR = L["Current"],
+ REM = L["Remaining"],
+ PERCENT = L["Percent"],
+ CURMAX = L["Current - Max"],
+ CURPERC = L["Current - Percent"],
+ CURREM = L["Current - Remaining"],
+ CURPERCREM = L["Current - Percent (Remaining)"],
+ },
+ set = function(info, value) mod.db.reputation[info[#info]] = value mod:UpdateReputation() end
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/DataTexts.lua b/ElvUI_OptionsUI/DataTexts.lua
new file mode 100644
index 0000000..86aa3b6
--- /dev/null
+++ b/ElvUI_OptionsUI/DataTexts.lua
@@ -0,0 +1,389 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+local DT = E:GetModule("DataTexts")
+local Layout = E:GetModule("Layout")
+local Chat = E:GetModule("Chat")
+local Minimap = E:GetModule("Minimap")
+
+local _G = _G
+local pairs = pairs
+
+local HideLeftChat = HideLeftChat
+local HideRightChat = HideRightChat
+
+local datatexts = {}
+
+function DT:PanelLayoutOptions()
+ for name, data in pairs(DT.RegisteredDataTexts) do
+ datatexts[name] = data.localizedName or L[name]
+ end
+ datatexts[""] = L["NONE"]
+
+ local order
+ local table = E.Options.args.datatexts.args.panels.args
+ for pointLoc, tab in pairs(P.datatexts.panels) do
+ if not _G[pointLoc] then table[pointLoc] = nil return end
+ if type(tab) == "table" then
+ if pointLoc:find("Chat") then
+ order = 15
+ else
+ order = 20
+ end
+ table[pointLoc] = {
+ order = order,
+ type = "group",
+ name = L[pointLoc] or pointLoc,
+ args = {}
+ }
+ for option in pairs(tab) do
+ table[pointLoc].args[option] = {
+ type = "select",
+ name = L[option] or option:upper(),
+ values = datatexts,
+ get = function(info) return E.db.datatexts.panels[pointLoc][info[#info]] end,
+ set = function(info, value) E.db.datatexts.panels[pointLoc][info[#info]] = value DT:LoadDataTexts() end
+ }
+ end
+ elseif type(tab) == "string" then
+ table.smallPanels.args[pointLoc] = {
+ type = "select",
+ name = L[pointLoc] or pointLoc,
+ values = datatexts,
+ get = function(info) return E.db.datatexts.panels[pointLoc] end,
+ set = function(info, value) E.db.datatexts.panels[pointLoc] = value DT:LoadDataTexts() end
+ }
+ end
+ end
+end
+
+E.Options.args.datatexts = {
+ type = "group",
+ name = L["DataTexts"],
+ childGroups = "tab",
+ get = function(info) return E.db.datatexts[info[#info]] end,
+ set = function(info, value) E.db.datatexts[info[#info]] = value DT:LoadDataTexts() end,
+ args = {
+ intro = {
+ order = 1,
+ type = "description",
+ name = L["DATATEXT_DESC"]
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = ""
+ },
+ general = {
+ order = 3,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ generalGroup = {
+ order = 2,
+ type = "group",
+ guiInline = true,
+ name = L["General"],
+ args = {
+ battleground = {
+ order = 1,
+ type = "toggle",
+ name = L["Battleground Texts"],
+ desc = L["When inside a battleground display personal scoreboard information on the main datatext bars."]
+ },
+ panelTransparency = {
+ order = 2,
+ name = L["Panel Transparency"],
+ type = "toggle",
+ set = function(info, value)
+ E.db.datatexts[info[#info]] = value
+ Layout:SetDataPanelStyle()
+ end
+ },
+ panelBackdrop = {
+ order = 3,
+ type = "toggle",
+ name = L["Backdrop"],
+ set = function(info, value)
+ E.db.datatexts[info[#info]] = value
+ Layout:SetDataPanelStyle()
+ end
+ },
+ noCombatClick = {
+ order = 4,
+ type = "toggle",
+ name = L["Block Combat Click"],
+ desc = L["Blocks all click events while in combat."]
+ },
+ noCombatHover = {
+ order = 5,
+ type = "toggle",
+ name = L["Block Combat Hover"],
+ desc = L["Blocks datatext tooltip from showing in combat."]
+ },
+ goldFormat = {
+ order = 6,
+ type = "select",
+ name = L["Gold Format"],
+ desc = L["The display format of the money text that is shown in the gold datatext and its tooltip."],
+ values = {
+ ["SMART"] = L["Smart"],
+ ["FULL"] = L["Full"],
+ ["SHORT"] = L["SHORT"],
+ ["SHORTINT"] = L["Short (Whole Numbers)"],
+ ["CONDENSED"] = L["Condensed"],
+ ["BLIZZARD"] = L["Blizzard Style"]
+ }
+ },
+ goldCoins = {
+ order = 7,
+ type = "toggle",
+ name = L["Show Coins"],
+ desc = L["Use coin icons instead of colored text."]
+ }
+ }
+ },
+ fontGroup = {
+ order = 3,
+ type = "group",
+ guiInline = true,
+ name = L["Fonts"],
+ args = {
+ font = {
+ order = 1,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontSize = {
+ order = 2,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 22, step = 1
+ },
+ fontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ },
+ wordWrap = {
+ order = 4,
+ type = "toggle",
+ name = L["Word Wrap"]
+ }
+ }
+ }
+ }
+ },
+ panels = {
+ type = "group",
+ name = L["Panels"],
+ order = 4,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Panels"]
+ },
+ leftChatPanel = {
+ order = 2,
+ type = "toggle",
+ name = L["Datatext Panel (Left)"],
+ desc = L["Display data panels below the chat, used for datatexts."],
+ set = function(info, value)
+ E.db.datatexts[info[#info]] = value
+ if E.db.LeftChatPanelFaded then
+ E.db.LeftChatPanelFaded = true
+ HideLeftChat()
+ end
+ Chat:UpdateAnchors()
+ Layout:ToggleChatPanels()
+ end
+ },
+ rightChatPanel = {
+ order = 3,
+ type = "toggle",
+ name = L["Datatext Panel (Right)"],
+ desc = L["Display data panels below the chat, used for datatexts."],
+ set = function(info, value)
+ E.db.datatexts[info[#info]] = value
+ if E.db.RightChatPanelFaded then
+ E.db.RightChatPanelFaded = true
+ HideRightChat()
+ end
+ Chat:UpdateAnchors()
+ Layout:ToggleChatPanels()
+ end
+ },
+ minimapPanels = {
+ order = 4,
+ type = "toggle",
+ name = L["Minimap Panels"],
+ desc = L["Display minimap panels below the minimap, used for datatexts."],
+ set = function(info, value)
+ E.db.datatexts[info[#info]] = value
+ Minimap:UpdateSettings()
+ end
+ },
+ minimapTop = {
+ order = 5,
+ type = "toggle",
+ name = L["TopMiniPanel"],
+ set = function(info, value)
+ E.db.datatexts[info[#info]] = value
+ Minimap:UpdateSettings()
+ end
+ },
+ minimapTopLeft = {
+ order = 6,
+ type = "toggle",
+ name = L["TopLeftMiniPanel"],
+ set = function(info, value)
+ E.db.datatexts[info[#info]] = value
+ Minimap:UpdateSettings()
+ end
+ },
+ minimapTopRight = {
+ order = 7,
+ type = "toggle",
+ name = L["TopRightMiniPanel"],
+ set = function(info, value)
+ E.db.datatexts[info[#info]] = value
+ Minimap:UpdateSettings()
+ end
+ },
+ minimapBottom = {
+ order = 8,
+ type = "toggle",
+ name = L["BottomMiniPanel"],
+ set = function(info, value)
+ E.db.datatexts[info[#info]] = value
+ Minimap:UpdateSettings()
+ end
+ },
+ minimapBottomLeft = {
+ order = 9,
+ type = "toggle",
+ name = L["BottomLeftMiniPanel"],
+ set = function(info, value)
+ E.db.datatexts[info[#info]] = value
+ Minimap:UpdateSettings()
+ end
+ },
+ minimapBottomRight = {
+ order = 10,
+ type = "toggle",
+ name = L["BottomRightMiniPanel"],
+ set = function(info, value)
+ E.db.datatexts[info[#info]] = value
+ Minimap:UpdateSettings()
+ end
+ },
+ spacer = {
+ order = 11,
+ type = "description",
+ name = "\n"
+ },
+ smallPanels = {
+ order = 12,
+ type = "group",
+ name = L["Small Panels"],
+ args = {}
+ }
+ }
+ },
+ time = {
+ order = 5,
+ type = "group",
+ name = L["Time"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Time"],
+ },
+ timeFormat = {
+ order = 2,
+ type = "select",
+ name = L["Time Format"],
+ values = {
+ [""] = L["NONE"],
+ ["%I:%M"] = "03:27",
+ ["%I:%M:%S"] = "03:27:32",
+ ["%I:%M %p"] = "03:27 PM",
+ ["%I:%M:%S %p"] = "03:27:32 PM",
+ ["%H:%M"] = "15:27",
+ ["%H:%M:%S"] = "15:27:32"
+ }
+ },
+ dateFormat = {
+ order = 3,
+ type = "select",
+ name = L["Date Format"],
+ values = {
+ [""] = L["NONE"],
+ ["%d/%m/%y "] = "DD/MM/YY",
+ ["%m/%d/%y "] = "MM/DD/YY",
+ ["%y/%m/%d "] = "YY/MM/DD",
+ ["%d.%m.%y "] = "DD.MM.YY",
+ ["%m.%d.%y "] = "MM.DD.YY",
+ ["%y.%m.%d "] = "YY.MM.DD"
+ }
+ },
+ realmTime = {
+ order = 4,
+ type = "toggle",
+ name = L["Realm Time"],
+ desc = L["Displayed server time."]
+ }
+ }
+ },
+ friends = {
+ order = 6,
+ type = "group",
+ name = L["FRIENDS"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["FRIENDS"]
+ },
+ description = {
+ order = 2,
+ type = "description",
+ name = L["Hide specific sections in the datatext tooltip."]
+ },
+ hideGroup = {
+ order = 3,
+ type = "group",
+ guiInline = true,
+ name = L["HIDE"],
+ args = {
+ hideAFK = {
+ order = 1,
+ type = "toggle",
+ name = L["AFK"],
+ get = function(info) return E.db.datatexts.friends.hideAFK end,
+ set = function(info, value) E.db.datatexts.friends.hideAFK = value DT:LoadDataTexts() end
+ },
+ hideDND = {
+ order = 2,
+ type = "toggle",
+ name = L["DND"],
+ get = function(info) return E.db.datatexts.friends.hideDND end,
+ set = function(info, value) E.db.datatexts.friends.hideDND = value DT:LoadDataTexts() end
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+DT:PanelLayoutOptions()
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/ElvUI_OptionsUI.toc b/ElvUI_OptionsUI/ElvUI_OptionsUI.toc
new file mode 100644
index 0000000..ab9669d
--- /dev/null
+++ b/ElvUI_OptionsUI/ElvUI_OptionsUI.toc
@@ -0,0 +1,27 @@
+## Interface: 30300
+## Author: Elv, Bunny
+## Version: 1.06
+## Title: |cff1784d1E|r|cffe5e3e3lvUI|r |cff1784d1O|r|cffe5e3e3ptionsUI|r
+## Notes: Options for ElvUI.
+## RequiredDeps: ElvUI
+## LoadOnDemand: 1
+
+Libraries\Load_Libraries.xml
+Locales\Load_locales.xml
+Core.lua
+General.lua
+ActionBars.lua
+Auras.lua
+Bags.lua
+Chat.lua
+Cooldown.lua
+DataTexts.lua
+Filters.lua
+Nameplates.lua
+Skins.lua
+Tooltip.lua
+UnitFrames.lua
+DataBars.lua
+Maps.lua
+ModuleControl.lua
+Tags.lua
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Filters.lua b/ElvUI_OptionsUI/Filters.lua
new file mode 100644
index 0000000..883a8e8
--- /dev/null
+++ b/ElvUI_OptionsUI/Filters.lua
@@ -0,0 +1,1461 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local _, L = unpack(select(2, ...))
+local UF = E:GetModule("UnitFrames")
+
+local type, pairs, tonumber, tostring = type, pairs, tonumber, tostring
+local gsub, match, format = string.gsub, string.match, string.format
+
+local GetSpellInfo = GetSpellInfo
+
+local quickSearchText, selectedSpell, selectedFilter = ""
+
+local function filterMatch(s,v)
+ local m1, m2, m3, m4 = "^"..v.."$", "^"..v..",", ","..v.."$", ","..v..","
+ return (match(s, m1) and m1) or (match(s, m2) and m2) or (match(s, m3) and m3) or (match(s, m4) and v..",")
+end
+
+local function removePriority(value)
+ if not value then return end
+ local x,y,z = E.db.unitframe.units,E.db.nameplates.units
+ for n, t in pairs(x) do
+ if t and t.buffs and t.buffs.priority and t.buffs.priority ~= "" then
+ z = filterMatch(t.buffs.priority, E:EscapeString(value))
+ if z then E.db.unitframe.units[n].buffs.priority = gsub(t.buffs.priority, z, "") end
+ end
+ if t and t.debuffs and t.debuffs.priority and t.debuffs.priority ~= "" then
+ z = filterMatch(t.debuffs.priority, E:EscapeString(value))
+ if z then E.db.unitframe.units[n].debuffs.priority = gsub(t.debuffs.priority, z, "") end
+ end
+ if t and t.aurabar and t.aurabar.priority and t.aurabar.priority ~= "" then
+ z = filterMatch(t.aurabar.priority, E:EscapeString(value))
+ if z then E.db.unitframe.units[n].aurabar.priority = gsub(t.aurabar.priority, z, "") end
+ end
+ end
+ for n, t in pairs(y) do
+ if t and t.buffs and t.buffs.priority and t.buffs.priority ~= "" then
+ z = filterMatch(t.buffs.priority, E:EscapeString(value))
+ if z then E.db.nameplates.units[n].buffs.priority = gsub(t.buffs.priority, z, "") end
+ end
+ if t and t.debuffs and t.debuffs.priority and t.debuffs.priority ~= "" then
+ z = filterMatch(t.debuffs.priority, E:EscapeString(value))
+ if z then E.db.nameplates.units[n].debuffs.priority = gsub(t.debuffs.priority, z, "") end
+ end
+ end
+end
+
+local FilterResetState = {}
+
+local function UpdateFilterGroup()
+ --Prevent errors when choosing a new filter, by doing a reset of the groups
+ E.Options.args.filters.args.filterGroup = nil
+ E.Options.args.filters.args.spellGroup = nil
+ E.Options.args.filters.args.resetGroup = nil
+ E.Options.args.filters.childGroups = nil
+
+ if selectedFilter == "Debuff Highlight" then
+ E.Options.args.filters.args.filterGroup = {
+ order = 10,
+ type = "group",
+ name = selectedFilter,
+ guiInline = true,
+ args = {
+ addSpell = {
+ order = 1,
+ type = "input",
+ name = L["Add Spell ID or Name"],
+ desc = L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if tonumber(value) then value = tonumber(value) end
+ E.global.unitframe.DebuffHighlightColors[value] = {enable = true, style = "GLOW", color = {r = 0.8, g = 0, b = 0, a = 0.85}}
+ UpdateFilterGroup()
+ UF:Update_AllFrames()
+ end
+ },
+ removeSpell = {
+ order = 2,
+ type = "execute",
+ name = L["Remove Spell"],
+ desc = L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."],
+ func = function()
+ local value = selectedSpell:match(" %((%d+)%)$") or selectedSpell
+ if tonumber(value) then value = tonumber(value) end
+ E.global.unitframe.DebuffHighlightColors[value] = nil
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:Update_AllFrames()
+ end,
+ disabled = function() return not (selectedSpell and selectedSpell ~= "") end
+ },
+ quickSearch = {
+ order = 3,
+ type = "input",
+ name = L["Filter Search"],
+ desc = L["Search for a spell name inside of a filter."],
+ get = function() return quickSearchText end,
+ set = function(info,value) quickSearchText = value end
+ },
+ selectSpell = {
+ order = 10,
+ type = "select",
+ name = L["Select Spell"],
+ width = "double",
+ guiInline = true,
+ get = function(info) return selectedSpell end,
+ set = function(info, value) selectedSpell = value UpdateFilterGroup() end,
+ values = function()
+ local filters = {}
+ local list = E.global.unitframe.DebuffHighlightColors
+ if not list then return end
+ local searchText = quickSearchText:lower()
+ for filter in pairs(list) do
+ if tonumber(filter) then
+ local spellName = GetSpellInfo(filter)
+ if spellName then
+ filter = format("%s (%s)", spellName, filter)
+ else
+ filter = tostring(filter)
+ end
+ end
+ if filter:lower():find(searchText) then filters[filter] = filter end
+ end
+ if not next(filters) then filters[""] = L["NONE"] end
+ return filters
+ end
+ }
+ }
+ }
+
+ E.Options.args.filters.args.resetGroup = {
+ order = 25,
+ type = "group",
+ name = L["Reset Filter"],
+ guiInline = true,
+ args = {
+ enableReset = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return FilterResetState[selectedFilter] end,
+ set = function(info, value)
+ FilterResetState[selectedFilter] = value
+ E.Options.args.filters.args.resetGroup.args.resetFilter.disabled = (not value)
+ end
+ },
+ resetFilter = {
+ order = 2,
+ type = "execute",
+ name = L["Reset Filter"],
+ desc = L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."],
+ disabled = function() return not FilterResetState[selectedFilter] end,
+ func = function(info)
+ E.global.unitframe.DebuffHighlightColors = E:CopyTable({}, G.unitframe.DebuffHighlightColors)
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:Update_AllFrames()
+ end
+ }
+ }
+ }
+
+ local spellID = selectedSpell and match(selectedSpell, "(%d+)")
+ if spellID then spellID = tonumber(spellID) end
+
+ if not selectedSpell or E.global.unitframe.DebuffHighlightColors[(spellID or selectedSpell)] == nil then
+ E.Options.args.filters.args.spellGroup = nil
+ return
+ end
+
+ E.Options.args.filters.args.spellGroup = {
+ order = 15,
+ type = "group",
+ name = selectedSpell,
+ guiInline = true,
+ args = {
+ enabled = {
+ order = 0,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info)
+ return E.global.unitframe.DebuffHighlightColors[(spellID or selectedSpell)].enable
+ end,
+ set = function(info, value)
+ E.global.unitframe.DebuffHighlightColors[(spellID or selectedSpell)].enable = value
+ UF:Update_AllFrames()
+ end
+ },
+ style = {
+ order = 3,
+ type = "select",
+ name = L["Style"],
+ values = {
+ ["GLOW"] = L["Glow"],
+ ["FILL"] = L["Fill"]
+ },
+ get = function(info)
+ return E.global.unitframe.DebuffHighlightColors[(spellID or selectedSpell)].style
+ end,
+ set = function(info, value)
+ E.global.unitframe.DebuffHighlightColors[(spellID or selectedSpell)].style = value
+ UF:Update_AllFrames()
+ end
+ },
+ color = {
+ order = 1,
+ type = "color",
+ name = L["COLOR"],
+ hasAlpha = true,
+ get = function(info)
+ local t = E.global.unitframe.DebuffHighlightColors[(spellID or selectedSpell)].color
+ return t.r, t.g, t.b, t.a
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.global.unitframe.DebuffHighlightColors[(spellID or selectedSpell)].color
+ t.r, t.g, t.b, t.a = r, g, b, a
+ UF:Update_AllFrames()
+ end
+ }
+ }
+ }
+ elseif selectedFilter == "AuraBar Colors" then
+ E.Options.args.filters.args.filterGroup = {
+ order = 10,
+ type = "group",
+ name = selectedFilter,
+ guiInline = true,
+ args = {
+ addSpell = {
+ order = 1,
+ type = "input",
+ name = L["Add Spell ID or Name"],
+ desc = L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if tonumber(value) then value = tonumber(value) end
+ if not E.global.unitframe.AuraBarColors[value] then
+ E.global.unitframe.AuraBarColors[value] = false
+ end
+ UpdateFilterGroup()
+ UF:CreateAndUpdateUF("player")
+ UF:CreateAndUpdateUF("target")
+ UF:CreateAndUpdateUF("focus")
+ end
+ },
+ removeSpell = {
+ order = 2,
+ type = "execute",
+ name = L["Remove Spell"],
+ desc = L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."],
+ func = function()
+ local value = selectedSpell:match(" %((%d+)%)$") or selectedSpell
+ if tonumber(value) then value = tonumber(value) end
+ if G.unitframe.AuraBarColors[value] then
+ E.global.unitframe.AuraBarColors[value] = false
+ E:Print(L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."])
+ else
+ E.global.unitframe.AuraBarColors[value] = nil
+ end
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:CreateAndUpdateUF("player")
+ UF:CreateAndUpdateUF("target")
+ UF:CreateAndUpdateUF("focus")
+ end,
+ disabled = function() return not (selectedSpell and selectedSpell ~= "") end
+ },
+ quickSearch = {
+ order = 3,
+ type = "input",
+ name = L["Filter Search"],
+ desc = L["Search for a spell name inside of a filter."],
+ get = function() return quickSearchText end,
+ set = function(info,value) quickSearchText = value end
+ },
+ selectSpell = {
+ order = 10,
+ type = "select",
+ name = L["Select Spell"],
+ width = "double",
+ guiInline = true,
+ get = function(info) return selectedSpell end,
+ set = function(info, value)
+ selectedSpell = value
+ UpdateFilterGroup()
+ end,
+ values = function()
+ local filters = {}
+ local list = E.global.unitframe.AuraBarColors
+ if not list then return end
+ local searchText = quickSearchText:lower()
+ for filter in pairs(list) do
+ if tonumber(filter) then
+ local spellName = GetSpellInfo(filter)
+ if spellName then
+ filter = format("%s (%s)", spellName, filter)
+ else
+ filter = tostring(filter)
+ end
+ end
+ if filter:lower():find(searchText) then filters[filter] = filter end
+ end
+ if not next(filters) then filters[""] = L["NONE"] end
+ return filters
+ end
+ }
+ }
+ }
+
+ E.Options.args.filters.args.resetGroup = {
+ order = 25,
+ type = "group",
+ name = L["Reset Filter"],
+ guiInline = true,
+ args = {
+ enableReset = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return FilterResetState[selectedFilter] end,
+ set = function(info, value)
+ FilterResetState[selectedFilter] = value
+ E.Options.args.filters.args.resetGroup.args.resetFilter.disabled = (not value)
+ end
+ },
+ resetFilter = {
+ order = 2,
+ type = "execute",
+ name = L["Reset Filter"],
+ desc = L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."],
+ disabled = function() return not FilterResetState[selectedFilter] end,
+ func = function(info)
+ E.global.unitframe.AuraBarColors = E:CopyTable({}, G.unitframe.AuraBarColors)
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:Update_AllFrames()
+ end
+ }
+ }
+ }
+
+ local spellID = selectedSpell and match(selectedSpell, "(%d+)")
+ if spellID then spellID = tonumber(spellID) end
+
+ if not selectedSpell or E.global.unitframe.AuraBarColors[(spellID or selectedSpell)] == nil then
+ E.Options.args.filters.args.spellGroup = nil
+ return
+ end
+
+ E.Options.args.filters.args.spellGroup = {
+ order = 15,
+ type = "group",
+ name = selectedSpell,
+ guiInline = true,
+ args = {
+ color = {
+ order = 1,
+ type = "color",
+ name = L["COLOR"],
+ get = function(info)
+ local t = E.global.unitframe.AuraBarColors[(spellID or selectedSpell)]
+ if type(t) == "boolean" then
+ return 0, 0, 0, 1
+ else
+ return t.r, t.g, t.b, t.a
+ end
+ end,
+ set = function(info, r, g, b)
+ local spell = (spellID or selectedSpell)
+ if type(E.global.unitframe.AuraBarColors[spell]) ~= "table" then
+ E.global.unitframe.AuraBarColors[spell] = {}
+ end
+ local t = E.global.unitframe.AuraBarColors[spell]
+ t.r, t.g, t.b = r, g, b
+ UF:CreateAndUpdateUF("player")
+ UF:CreateAndUpdateUF("target")
+ UF:CreateAndUpdateUF("focus")
+ end
+ },
+ removeColor = {
+ order = 2,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info)
+ E.global.unitframe.AuraBarColors[(spellID or selectedSpell)] = false
+ UF:CreateAndUpdateUF("player")
+ UF:CreateAndUpdateUF("target")
+ UF:CreateAndUpdateUF("focus")
+ end
+ }
+ }
+ }
+ elseif selectedFilter == "Buff Indicator (Pet)" then
+ if not E.global.unitframe.buffwatch.PET then
+ E.global.unitframe.buffwatch.PET = {}
+ end
+
+ E.Options.args.filters.args.filterGroup = {
+ order = 15,
+ type = "group",
+ name = selectedFilter,
+ guiInline = true,
+ childGroups = "select",
+ args = {
+ addSpellID = {
+ order = 1,
+ type = "input",
+ name = L["Add SpellID"],
+ desc = L["Add a spell to the filter."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if not tonumber(value) then
+ E:Print(L["Value must be a number"])
+ elseif not GetSpellInfo(value) then
+ E:Print(L["Not valid spell id"])
+ else
+ E.global.unitframe.buffwatch.PET[tonumber(value)] = {["enabled"] = true, ["id"] = tonumber(value), ["point"] = "TOPRIGHT", ["color"] = {["r"] = 1, ["g"] = 0, ["b"] = 0}, ["anyUnit"] = true, ["style"] = "coloredIcon", ["xOffset"] = 0, ["yOffset"] = 0}
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:CreateAndUpdateUF("pet")
+ end
+ end
+ },
+ removeSpellID = {
+ order = 2,
+ type = "execute",
+ name = L["Remove SpellID"],
+ desc = L["Remove a spell from the filter."],
+ func = function()
+ if G.unitframe.buffwatch.PET[selectedSpell] then
+ E.global.unitframe.buffwatch.PET[selectedSpell].enabled = false
+ E:Print(L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."])
+ else
+ E.global.unitframe.buffwatch.PET[selectedSpell] = nil
+ end
+
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:CreateAndUpdateUF("pet")
+ end,
+ disabled = function() return not selectedSpell end
+ },
+ quickSearch = {
+ order = 3,
+ type = "input",
+ name = L["Filter Search"],
+ desc = L["Search for a spell name inside of a filter."],
+ get = function() return quickSearchText end,
+ set = function(info,value) quickSearchText = value end
+ },
+ selectSpell = {
+ order = 10,
+ type = "select",
+ name = L["Select Spell"],
+ width = "double",
+ values = function()
+ local values = {}
+ local list = E.global.unitframe.buffwatch.PET
+ if not list then return end
+ local searchText = quickSearchText:lower()
+ for _, spell in pairs(list) do
+ if spell.id then
+ local name = GetSpellInfo(spell.id)
+ if name and name:lower():find(searchText) then values[spell.id] = name end
+ end
+ end
+ return values
+ end,
+ get = function(info) return selectedSpell end,
+ set = function(info, value)
+ selectedSpell = value
+ UpdateFilterGroup()
+ end
+ }
+ }
+ }
+
+ E.Options.args.filters.args.resetGroup = {
+ order = 25,
+ type = "group",
+ name = L["Reset Filter"],
+ guiInline = true,
+ args = {
+ enableReset = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return FilterResetState[selectedFilter] end,
+ set = function(info, value)
+ FilterResetState[selectedFilter] = value
+ E.Options.args.filters.args.resetGroup.args.resetFilter.disabled = (not value)
+ end
+ },
+ resetFilter = {
+ order = 2,
+ type = "execute",
+ name = L["Reset Filter"],
+ desc = L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."],
+ disabled = function() return not FilterResetState[selectedFilter] end,
+ func = function(info)
+ E.global.unitframe.buffwatch.PET = E:CopyTable({}, G.unitframe.buffwatch.PET)
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:Update_AllFrames()
+ end
+ }
+ }
+ }
+
+ if selectedSpell then
+ local name = GetSpellInfo(selectedSpell)
+ if name then
+ E.Options.args.filters.args.filterGroup.args[name] = {
+ order = -10,
+ type = "group",
+ name = name.." ("..selectedSpell..")",
+ get = function(info) return E.global.unitframe.buffwatch.PET[selectedSpell][info[#info]] end,
+ set = function(info, value) E.global.unitframe.buffwatch.PET[selectedSpell][info[#info]] = value UF:CreateAndUpdateUF("pet") end,
+ args = {
+ enabled = {
+ order = 0,
+ type = "toggle",
+ name = L["Enable"],
+ },
+ point = {
+ order = 1,
+ type = "select",
+ name = L["Anchor Point"],
+ values = {
+ ["TOPLEFT"] = "TOPLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT",
+ ["LEFT"] = "LEFT",
+ ["RIGHT"] = "RIGHT",
+ ["TOP"] = "TOP",
+ ["BOTTOM"] = "BOTTOM"
+ }
+ },
+ sizeOverride = {
+ order = 2,
+ type = "range",
+ name = L["Size Override"],
+ min = 0, max = 50, step = 1
+ },
+ xOffset = {
+ order = 3,
+ type = "range",
+ name = L["xOffset"],
+ min = -75, max = 75, step = 1
+ },
+ yOffset = {
+ order = 4,
+ type = "range",
+ name = L["yOffset"],
+ min = -75, max = 75, step = 1
+ },
+ style = {
+ order = 5,
+ type = "select",
+ name = L["Style"],
+ values = {
+ ["coloredIcon"] = L["Colored Icon"],
+ ["texturedIcon"] = L["Textured Icon"],
+ ["NONE"] = L["NONE"]
+ }
+ },
+ color = {
+ order = 6,
+ type = "color",
+ name = L["COLOR"],
+ get = function(info)
+ local t = E.global.unitframe.buffwatch.PET[selectedSpell][info[#info]]
+ return t.r, t.g, t.b, t.a
+ end,
+ set = function(info, r, g, b)
+ local t = E.global.unitframe.buffwatch.PET[selectedSpell][info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:CreateAndUpdateUF("pet")
+ end
+ },
+ displayText = {
+ order = 7,
+ type = "toggle",
+ name = L["Display Text"]
+ },
+ textColor = {
+ order = 8,
+ type = "color",
+ name = L["Text Color"],
+ get = function(info)
+ local t = E.global.unitframe.buffwatch.PET[selectedSpell][info[#info]]
+ if t then
+ return t.r, t.g, t.b, t.a
+ else
+ return 1, 1, 1, 1
+ end
+ end,
+ set = function(info, r, g, b)
+ local t = E.global.unitframe.buffwatch.PET[selectedSpell][info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:CreateAndUpdateUF("pet")
+ end
+ },
+ decimalThreshold = {
+ order = 9,
+ type = "range",
+ name = L["Decimal Threshold"],
+ desc = L["Threshold before text goes into decimal form. Set to -1 to disable decimals."],
+ min = -1, max = 10, step = 1
+ },
+ textThreshold = {
+ order = 10,
+ type = "range",
+ name = L["Text Threshold"],
+ desc = L["At what point should the text be displayed. Set to -1 to disable."],
+ min = -1, max = 60, step = 1
+ },
+ anyUnit = {
+ order = 11,
+ type = "toggle",
+ name = L["Show Aura From Other Players"]
+ },
+ onlyShowMissing = {
+ order = 12,
+ type = "toggle",
+ name = L["Show When Not Active"]
+ }
+ }
+ }
+ else
+ E:Print(L["Not valid spell id"])
+ end
+ end
+ elseif selectedFilter == "Buff Indicator" then
+ if not E.global.unitframe.buffwatch[E.myclass] then
+ E.global.unitframe.buffwatch[E.myclass] = {}
+ end
+
+ E.Options.args.filters.args.filterGroup = {
+ order = 15,
+ type = "group",
+ name = selectedFilter,
+ guiInline = true,
+ childGroups = "select",
+ args = {
+ addSpellID = {
+ order = 1,
+ type = "input",
+ name = L["Add SpellID"],
+ desc = L["Add a spell to the filter."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if not tonumber(value) then
+ E:Print(L["Value must be a number"])
+ elseif not GetSpellInfo(value) then
+ E:Print(L["Not valid spell id"])
+ else
+ E.global.unitframe.buffwatch[E.myclass][tonumber(value)] = {["enabled"] = true, ["id"] = tonumber(value), ["point"] = "TOPRIGHT", ["color"] = {["r"] = 1, ["g"] = 0, ["b"] = 0}, ["anyUnit"] = false, ["style"] = "coloredIcon", ["xOffset"] = 0, ["yOffset"] = 0}
+ selectedSpell = nil
+ UpdateFilterGroup()
+
+ UF:UpdateAuraWatchFromHeader("raid")
+ UF:UpdateAuraWatchFromHeader("raid40")
+ UF:UpdateAuraWatchFromHeader("party")
+ UF:UpdateAuraWatchFromHeader("raidpet", true)
+ end
+ end
+ },
+ removeSpellID = {
+ order = 2,
+ type = "execute",
+ name = L["Remove SpellID"],
+ desc = L["Remove a spell from the filter."],
+ func = function()
+ if G.unitframe.buffwatch[E.myclass][selectedSpell] then
+ E.global.unitframe.buffwatch[E.myclass][selectedSpell].enabled = false
+ E:Print(L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."])
+ else
+ E.global.unitframe.buffwatch[E.myclass][selectedSpell] = nil
+ end
+
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:UpdateAuraWatchFromHeader("raid")
+ UF:UpdateAuraWatchFromHeader("raid40")
+ UF:UpdateAuraWatchFromHeader("party")
+ UF:UpdateAuraWatchFromHeader("raidpet", true)
+ end,
+ disabled = function() return not selectedSpell end
+ },
+ quickSearch = {
+ order = 3,
+ type = "input",
+ name = L["Filter Search"],
+ desc = L["Search for a spell name inside of a filter."],
+ get = function() return quickSearchText end,
+ set = function(info,value) quickSearchText = value end
+ },
+ selectSpell = {
+ order = 10,
+ type = "select",
+ name = L["Select Spell"],
+ width = "double",
+ values = function()
+ local values = {}
+ local list = E.global.unitframe.buffwatch[E.myclass]
+ if not list then return end
+ local searchText = quickSearchText:lower()
+ for _, spell in pairs(list) do
+ if spell.id then
+ local name = GetSpellInfo(spell.id)
+ if name and name:lower():find(searchText) then values[spell.id] = name end
+ end
+ end
+ return values
+ end,
+ get = function(info) return selectedSpell end,
+ set = function(info, value)
+ selectedSpell = value
+ UpdateFilterGroup()
+ end
+ }
+ }
+ }
+
+ E.Options.args.filters.args.resetGroup = {
+ order = 25,
+ type = "group",
+ name = L["Reset Filter"],
+ guiInline = true,
+ args = {
+ enableReset = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return FilterResetState[selectedFilter] end,
+ set = function(info, value)
+ FilterResetState[selectedFilter] = value
+ E.Options.args.filters.args.resetGroup.args.resetFilter.disabled = (not value)
+ end
+ },
+ resetFilter = {
+ order = 2,
+ type = "execute",
+ name = L["Reset Filter"],
+ desc = L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."],
+ disabled = function() return not FilterResetState[selectedFilter] end,
+ func = function(info)
+ E.global.unitframe.buffwatch[E.myclass] = E:CopyTable({}, G.unitframe.buffwatch[E.myclass])
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:Update_AllFrames()
+ end
+ }
+ }
+ }
+
+ if selectedSpell then
+ local name = GetSpellInfo(selectedSpell)
+ E.Options.args.filters.args.filterGroup.args[name] = {
+ order = -10,
+ type = "group",
+ name = name.." ("..selectedSpell..")",
+ get = function(info) return E.global.unitframe.buffwatch[E.myclass][selectedSpell][info[#info]] end,
+ set = function(info, value)
+ E.global.unitframe.buffwatch[E.myclass][selectedSpell][info[#info]] = value
+
+ UF:UpdateAuraWatchFromHeader("raid")
+ UF:UpdateAuraWatchFromHeader("raid40")
+ UF:UpdateAuraWatchFromHeader("party")
+ UF:UpdateAuraWatchFromHeader("raidpet", true)
+ end,
+ args = {
+ enabled = {
+ order = 0,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ point = {
+ order = 1,
+ type = "select",
+ name = L["Anchor Point"],
+ values = {
+ ["TOPLEFT"] = "TOPLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT",
+ ["LEFT"] = "LEFT",
+ ["RIGHT"] = "RIGHT",
+ ["TOP"] = "TOP",
+ ["BOTTOM"] = "BOTTOM"
+ }
+ },
+ sizeOverride = {
+ order = 2,
+ type = "range",
+ name = L["Size Override"],
+ min = 0, max = 50, step = 1
+ },
+ xOffset = {
+ order = 3,
+ type = "range",
+ name = L["xOffset"],
+ min = -75, max = 75, step = 1
+ },
+ yOffset = {
+ order = 4,
+ type = "range",
+ name = L["yOffset"],
+ min = -75, max = 75, step = 1
+ },
+ style = {
+ order = 5,
+ type = "select",
+ name = L["Style"],
+ values = {
+ ["coloredIcon"] = L["Colored Icon"],
+ ["texturedIcon"] = L["Textured Icon"],
+ ["NONE"] = L["NONE"]
+ }
+ },
+ color = {
+ order = 6,
+ type = "color",
+ name = L["COLOR"],
+ get = function(info)
+ local t = E.global.unitframe.buffwatch[E.myclass][selectedSpell][info[#info]]
+ return t.r, t.g, t.b, t.a
+ end,
+ set = function(info, r, g, b)
+ local t = E.global.unitframe.buffwatch[E.myclass][selectedSpell][info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:UpdateAuraWatchFromHeader("raid")
+ UF:UpdateAuraWatchFromHeader("raid40")
+ UF:UpdateAuraWatchFromHeader("party")
+ UF:UpdateAuraWatchFromHeader("raidpet", true)
+ end
+ },
+ displayText = {
+ order = 7,
+ type = "toggle",
+ name = L["Display Text"]
+ },
+ textColor = {
+ order = 8,
+ type = "color",
+ name = L["Text Color"],
+ get = function(info)
+ local t = E.global.unitframe.buffwatch[E.myclass][selectedSpell][info[#info]]
+ if t then
+ return t.r, t.g, t.b, t.a
+ else
+ return 1, 1, 1, 1
+ end
+ end,
+ set = function(info, r, g, b)
+ E.global.unitframe.buffwatch[E.myclass][selectedSpell].textColor = E.global.unitframe.buffwatch[E.myclass][selectedSpell].textColor or {}
+ local t = E.global.unitframe.buffwatch[E.myclass][selectedSpell].textColor
+ t.r, t.g, t.b = r, g, b
+ UF:UpdateAuraWatchFromHeader("raid")
+ UF:UpdateAuraWatchFromHeader("raid40")
+ UF:UpdateAuraWatchFromHeader("party")
+ UF:UpdateAuraWatchFromHeader("raidpet", true)
+ end
+ },
+ decimalThreshold = {
+ order = 9,
+ type = "range",
+ name = L["Decimal Threshold"],
+ desc = L["Threshold before text goes into decimal form. Set to -1 to disable decimals."],
+ min = -1, max = 10, step = 1
+ },
+ textThreshold = {
+ order = 10,
+ type = "range",
+ name = L["Text Threshold"],
+ desc = L["At what point should the text be displayed. Set to -1 to disable."],
+ min = -1, max = 60, step = 1
+ },
+ anyUnit = {
+ order = 11,
+ type = "toggle",
+ name = L["Show Aura From Other Players"]
+ },
+ onlyShowMissing = {
+ order = 12,
+ type = "toggle",
+ name = L["Show When Not Active"]
+ }
+ }
+ }
+ end
+ elseif selectedFilter == "Buff Indicator (Profile)" then
+ E.Options.args.filters.args.filterGroup = {
+ order = 15,
+ type = "group",
+ name = selectedFilter,
+ guiInline = true,
+ childGroups = "select",
+ args = {
+ addSpellID = {
+ order = 1,
+ type = "input",
+ name = L["Add SpellID"],
+ desc = L["Add a spell to the filter."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if not tonumber(value) then
+ E:Print(L["Value must be a number"])
+ elseif not GetSpellInfo(value) then
+ E:Print(L["Not valid spell id"])
+ else
+ E.db.unitframe.filters.buffwatch[tonumber(value)] = {["enabled"] = true, ["id"] = tonumber(value), ["point"] = "TOPRIGHT", ["color"] = {["r"] = 1, ["g"] = 0, ["b"] = 0}, ["anyUnit"] = false, ["style"] = "coloredIcon", ["xOffset"] = 0, ["yOffset"] = 0}
+ selectedSpell = nil
+ UpdateFilterGroup()
+
+ UF:UpdateAuraWatchFromHeader("raid")
+ UF:UpdateAuraWatchFromHeader("raid40")
+ UF:UpdateAuraWatchFromHeader("party")
+ end
+ end
+ },
+ removeSpellID = {
+ order = 2,
+ type = "execute",
+ name = L["Remove SpellID"],
+ desc = L["Remove a spell from the filter."],
+ func = function()
+ if P.unitframe.filters.buffwatch[selectedSpell] then
+ E.db.unitframe.filters.buffwatch[selectedSpell].enabled = false
+ E:Print(L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."])
+ else
+ E.db.unitframe.filters.buffwatch[selectedSpell] = nil
+ end
+
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:UpdateAuraWatchFromHeader("raid")
+ UF:UpdateAuraWatchFromHeader("raid40")
+ UF:UpdateAuraWatchFromHeader("party")
+ end,
+ disabled = function() return not selectedSpell end
+ },
+ quickSearch = {
+ order = 3,
+ type = "input",
+ name = L["Filter Search"],
+ desc = L["Search for a spell name inside of a filter."],
+ get = function() return quickSearchText end,
+ set = function(info,value) quickSearchText = value end
+ },
+ selectSpell = {
+ order = 10,
+ type = "select",
+ name = L["Select Spell"],
+ width = "double",
+ values = function()
+ local values = {}
+ local list = E.db.unitframe.filters.buffwatch
+ if not list then return end
+ local searchText = quickSearchText:lower()
+ for _, spell in pairs(list) do
+ if spell.id then
+ local name = GetSpellInfo(spell.id)
+ if name:lower():find(searchText) then values[spell.id] = name end
+ end
+ end
+ return values
+ end,
+ get = function(info) return selectedSpell end,
+ set = function(info, value)
+ selectedSpell = value
+ UpdateFilterGroup()
+ end
+ }
+ }
+ }
+
+ E.Options.args.filters.args.resetGroup = {
+ order = 25,
+ type = "group",
+ name = L["Reset Filter"],
+ guiInline = true,
+ args = {
+ enableReset = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return FilterResetState[selectedFilter] end,
+ set = function(info, value)
+ FilterResetState[selectedFilter] = value
+ E.Options.args.filters.args.resetGroup.args.resetFilter.disabled = (not value)
+ end
+ },
+ resetFilter = {
+ order = 2,
+ type = "execute",
+ name = L["Reset Filter"],
+ desc = L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."],
+ disabled = function() return not FilterResetState[selectedFilter] end,
+ func = function(info)
+ E.db.unitframe.filters.buffwatch = {}
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:Update_AllFrames()
+ end
+ }
+ }
+ }
+
+ if selectedSpell then
+ local name = GetSpellInfo(selectedSpell)
+ E.Options.args.filters.args.filterGroup.args[name] = {
+ order = -10,
+ type = "group",
+ name = name.." ("..selectedSpell..")",
+ hidden = function() return not E.db.unitframe.filters.buffwatch[selectedSpell] end,
+ get = function(info)
+ if E.db.unitframe.filters.buffwatch[selectedSpell] then
+ return E.db.unitframe.filters.buffwatch[selectedSpell][info[#info]]
+ end
+ end,
+ set = function(info, value)
+ E.db.unitframe.filters.buffwatch[selectedSpell][info[#info]] = value
+
+ UF:UpdateAuraWatchFromHeader("raid")
+ UF:UpdateAuraWatchFromHeader("raid40")
+ UF:UpdateAuraWatchFromHeader("party")
+ end,
+ args = {
+ enabled = {
+ order = 0,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ point = {
+ order = 1,
+ type = "select",
+ name = L["Anchor Point"],
+ values = {
+ ["TOPLEFT"] = "TOPLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT",
+ ["LEFT"] = "LEFT",
+ ["RIGHT"] = "RIGHT",
+ ["TOP"] = "TOP",
+ ["BOTTOM"] = "BOTTOM"
+ }
+ },
+ sizeOverride = {
+ order = 2,
+ type = "range",
+ name = L["Size Override"],
+ min = 0, max = 50, step = 1
+ },
+ xOffset = {
+ order = 3,
+ type = "range",
+ name = L["xOffset"],
+ min = -75, max = 75, step = 1
+ },
+ yOffset = {
+ order = 4,
+ type = "range",
+ name = L["yOffset"],
+ min = -75, max = 75, step = 1
+ },
+ style = {
+ order = 5,
+ type = "select",
+ name = L["Style"],
+ values = {
+ ["coloredIcon"] = L["Colored Icon"],
+ ["texturedIcon"] = L["Textured Icon"],
+ ["NONE"] = L["NONE"]
+ }
+ },
+ color = {
+ order = 6,
+ type = "color",
+ name = L["COLOR"],
+ get = function(info)
+ if E.db.unitframe.filters.buffwatch[selectedSpell] then
+ local t = E.db.unitframe.filters.buffwatch[selectedSpell][info[#info]]
+ return t.r, t.g, t.b, t.a
+ end
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.filters.buffwatch[selectedSpell][info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:UpdateAuraWatchFromHeader("raid")
+ UF:UpdateAuraWatchFromHeader("raid40")
+ UF:UpdateAuraWatchFromHeader("party")
+ end
+ },
+ displayText = {
+ order = 7,
+ type = "toggle",
+ name = L["Display Text"]
+ },
+ textColor = {
+ order = 8,
+ type = "color",
+ name = L["Text Color"],
+ get = function(info)
+ if E.db.unitframe.filters.buffwatch[selectedSpell] then
+ local t = E.db.unitframe.filters.buffwatch[selectedSpell][info[#info]]
+ if t then
+ return t.r, t.g, t.b, t.a
+ else
+ return 1, 1, 1, 1
+ end
+ end
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.filters.buffwatch[selectedSpell][info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:UpdateAuraWatchFromHeader("raid")
+ UF:UpdateAuraWatchFromHeader("raid40")
+ UF:UpdateAuraWatchFromHeader("party")
+ end
+ },
+ decimalThreshold = {
+ order = 9,
+ type = "range",
+ name = L["Decimal Threshold"],
+ desc = L["Threshold before text goes into decimal form. Set to -1 to disable decimals."],
+ min = -1, max = 10, step = 1
+ },
+ textThreshold = {
+ order = 10,
+ type = "range",
+ name = L["Text Threshold"],
+ desc = L["At what point should the text be displayed. Set to -1 to disable."],
+ min = -1, max = 60, step = 1
+ },
+ anyUnit = {
+ order = 11,
+ type = "toggle",
+ name = L["Show Aura From Other Players"]
+ },
+ onlyShowMissing = {
+ order = 12,
+ type = "toggle",
+ name = L["Show When Not Active"]
+ }
+ }
+ }
+ end
+ else
+ if not selectedFilter or not E.global.unitframe.aurafilters[selectedFilter] then
+ E.Options.args.filters.args.filterGroup = nil
+ E.Options.args.filters.args.spellGroup = nil
+ E.Options.args.filters.args.resetGroup = nil
+ return
+ end
+
+ E.Options.args.filters.args.filterGroup = {
+ order = 10,
+ type = "group",
+ name = selectedFilter,
+ guiInline = true,
+ args = {
+ addSpell = {
+ order = 1,
+ type = "input",
+ name = L["Add Spell ID or Name"],
+ desc = L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if tonumber(value) then value = tonumber(value) end
+ if not E.global.unitframe.aurafilters[selectedFilter].spells[value] then
+ E.global.unitframe.aurafilters[selectedFilter].spells[value] = {
+ ["enable"] = true,
+ ["priority"] = 0,
+ ["stackThreshold"] = 0
+ }
+ end
+ UpdateFilterGroup()
+ UF:Update_AllFrames()
+ end
+ },
+ removeSpell = {
+ order = 2,
+ type = "execute",
+ name = L["Remove Spell"],
+ desc = L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."],
+ func = function()
+ local value = selectedSpell:match(" %((%d+)%)$") or selectedSpell
+ if tonumber(value) then value = tonumber(value) end
+ if G.unitframe.aurafilters[selectedFilter] then
+ if G.unitframe.aurafilters[selectedFilter].spells[value] then
+ E.global.unitframe.aurafilters[selectedFilter].spells[value].enable = false
+ E:Print(L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."])
+ else
+ E.global.unitframe.aurafilters[selectedFilter].spells[value] = nil
+ end
+ else
+ E.global.unitframe.aurafilters[selectedFilter].spells[value] = nil
+ end
+
+ UpdateFilterGroup()
+ UF:Update_AllFrames()
+ end,
+ disabled = function() return not (selectedSpell and selectedSpell ~= "") end
+ },
+ filterType = {
+ order = 3,
+ type = "select",
+ name = L["Filter Type"],
+ desc = L["Set the filter type. Blacklist will hide any auras in the list and show all others. Whitelist will show any auras in the filter and hide all others."],
+ values = {
+ ["Whitelist"] = L["Whitelist"],
+ ["Blacklist"] = L["Blacklist"]
+ },
+ get = function() return E.global.unitframe.aurafilters[selectedFilter].type end,
+ set = function(info, value) E.global.unitframe.aurafilters[selectedFilter].type = value UF:Update_AllFrames() end
+ },
+ quickSearch = {
+ order = 4,
+ type = "input",
+ name = L["Filter Search"],
+ desc = L["Search for a spell name inside of a filter."],
+ get = function() return quickSearchText end,
+ set = function(info,value) quickSearchText = value end
+ },
+ selectSpell = {
+ order = 10,
+ type = "select",
+ name = L["Select Spell"],
+ width = "double",
+ guiInline = true,
+ get = function(info) return selectedSpell end,
+ set = function(info, value)
+ selectedSpell = value
+ UpdateFilterGroup()
+ end,
+ values = function()
+ local filters = {}
+ local list = E.global.unitframe.aurafilters[selectedFilter].spells
+ if not list then return end
+ local searchText = quickSearchText:lower()
+ for filter in pairs(list) do
+ if tonumber(filter) then
+ local spellName = GetSpellInfo(filter)
+ if spellName then
+ filter = format("%s (%s)", spellName, filter)
+ else
+ filter = tostring(filter)
+ end
+ end
+ if filter:lower():find(searchText) then filters[filter] = filter end
+ end
+ if not next(filters) then filters[""] = L["NONE"] end
+ return filters
+ end
+ }
+ }
+ }
+
+ if E.DEFAULT_FILTER[selectedFilter] then
+ --Disable and hide filter type option for default filters
+ E.Options.args.filters.args.filterGroup.args.filterType.disabled = true
+ E.Options.args.filters.args.filterGroup.args.filterType.hidden = true
+
+ --Add button to reset content of the filter back to default
+ E.Options.args.filters.args.resetGroup = {
+ order = 25,
+ type = "group",
+ name = L["Reset Filter"],
+ guiInline = true,
+ args = {
+ enableReset = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return FilterResetState[selectedFilter] end,
+ set = function(info, value)
+ FilterResetState[selectedFilter] = value
+ E.Options.args.filters.args.resetGroup.args.resetFilter.disabled = (not value)
+ end
+ },
+ resetFilter = {
+ order = 2,
+ type = "execute",
+ name = L["Reset Filter"],
+ desc = L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."],
+ disabled = function() return not FilterResetState[selectedFilter] end,
+ func = function()
+ E.global.unitframe.aurafilters[selectedFilter].spells = E:CopyTable({}, G.unitframe.aurafilters[selectedFilter].spells)
+ selectedSpell = nil
+ UpdateFilterGroup()
+ UF:Update_AllFrames()
+ end
+ }
+ }
+ }
+ end
+
+ local spellID = selectedSpell and match(selectedSpell, "(%d+)")
+ if spellID then spellID = tonumber(spellID) end
+
+ if not selectedSpell or not E.global.unitframe.aurafilters[selectedFilter].spells[(spellID or selectedSpell)] then
+ E.Options.args.filters.args.spellGroup = nil
+ return
+ end
+
+ E.Options.args.filters.args.spellGroup = {
+ order = 15,
+ type = "group",
+ name = selectedSpell,
+ guiInline = true,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function()
+ if not (spellID or selectedSpell) then
+ return false
+ else
+ return E.global.unitframe.aurafilters[selectedFilter].spells[(spellID or selectedSpell)].enable
+ end
+ end,
+ set = function(info, value) E.global.unitframe.aurafilters[selectedFilter].spells[(spellID or selectedSpell)].enable = value UpdateFilterGroup() UF:Update_AllFrames() end
+ },
+ forDebuffIndicator = {
+ order = 2,
+ type = "group",
+ name = L["Used as RaidDebuff Indicator"],
+ guiInline = true,
+ args = {
+ priority = {
+ order = 1,
+ type = "range",
+ name = L["Priority"],
+ desc = L["Set the priority order of the spell, please note that prioritys are only used for the raid debuff module, not the standard buff/debuff module. If you want to disable set to zero."],
+ min = 0, max = 99, step = 1,
+ get = function()
+ if not selectedSpell then
+ return 0
+ else
+ return E.global.unitframe.aurafilters[selectedFilter].spells[(spellID or selectedSpell)].priority
+ end
+ end,
+ set = function(info, value) E.global.unitframe.aurafilters[selectedFilter].spells[(spellID or selectedSpell)].priority = value UpdateFilterGroup() UF:Update_AllFrames() end
+ },
+ stackThreshold = {
+ order = 2,
+ type = "range",
+ name = L["Stack Threshold"],
+ desc = L["The debuff needs to reach this amount of stacks before it is shown. Set to 0 to always show the debuff."],
+ min = 0, max = 99, step = 1,
+ get = function()
+ if not selectedSpell then
+ return 0
+ else
+ return E.global.unitframe.aurafilters[selectedFilter].spells[(spellID or selectedSpell)].stackThreshold
+ end
+ end,
+ set = function(info, value) E.global.unitframe.aurafilters[selectedFilter].spells[(spellID or selectedSpell)].stackThreshold = value UpdateFilterGroup() UF:Update_AllFrames() end
+ }
+ }
+ }
+ }
+ }
+ end
+
+ UF:Update_AllFrames()
+end
+
+E.Options.args.filters = {
+ order = -10, --Always Last Hehehe
+ type = "group",
+ name = L["FILTERS"],
+ args = {
+ createFilter = {
+ order = 1,
+ type = "input",
+ name = L["Create Filter"],
+ desc = L["Create a filter, once created a filter can be set inside the buffs/debuffs section of each unit."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then
+ return
+ end
+ if match(value, ",") then
+ E:Print(L["Filters are not allowed to have commas in their name. Stripping commas from filter name."])
+ value = gsub(value, ",", "")
+ end
+ if match(value, "^Friendly:") or match(value, "^Enemy:") then
+ return --dont allow people to create Friendly: or Enemy: filters
+ end
+ if G.unitframe.specialFilters[value] or E.global.unitframe.aurafilters[value] then
+ E:Print(L["Filter already exists!"])
+ return
+ end
+ E.global.unitframe.aurafilters[value] = {}
+ E.global.unitframe.aurafilters[value].spells = {}
+ end
+ },
+ selectFilter = {
+ order = 2,
+ type = "select",
+ name = L["Select Filter"],
+ get = function(info) return selectedFilter end,
+ set = function(info, value)
+ if value == "" then
+ selectedFilter = nil
+ selectedSpell = nil
+ else
+ selectedSpell = nil
+ if FilterResetState[selectedFilter] then
+ FilterResetState[selectedFilter] = nil
+ end
+ selectedFilter = value
+ end
+ quickSearchText = ""
+ UpdateFilterGroup()
+ end,
+ values = function()
+ local filters = {}
+ filters[""] = L["NONE"]
+ local list = E.global.unitframe.aurafilters
+ if not list then return end
+ for filter in pairs(list) do
+ filters[filter] = filter
+ end
+
+ filters["Buff Indicator"] = "Buff Indicator"
+ filters["Buff Indicator (Pet)"] = "Buff Indicator (Pet)"
+ filters["Buff Indicator (Profile)"] = "Buff Indicator (Profile)"
+ filters["AuraBar Colors"] = "AuraBar Colors"
+ filters["Debuff Highlight"] = "Debuff Highlight"
+ return filters
+ end
+ },
+ deleteFilter = {
+ order = 3,
+ type = "execute",
+ name = L["Delete Filter"],
+ desc = L["Delete a created filter, you cannot delete pre-existing filters, only custom ones."],
+ func = function()
+ E.global.unitframe.aurafilters[selectedFilter] = nil
+ removePriority(selectedFilter) --This will wipe a filter from the new aura system profile settings.
+ selectedFilter = nil
+ selectedSpell = nil
+ quickSearchText = ""
+ E.Options.args.filters.args.filterGroup = nil
+ end,
+ disabled = function() return G.unitframe.aurafilters[selectedFilter] end,
+ hidden = function() return selectedFilter == nil end
+ }
+ }
+}
+
+function E:SetToFilterConfig(filter)
+ selectedFilter = filter or "Buff Indicator"
+ UpdateFilterGroup()
+ E.Libs.AceConfigDialog:SelectGroup("ElvUI", "filters")
+end
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/General.lua b/ElvUI_OptionsUI/General.lua
new file mode 100644
index 0000000..9e3bb4b
--- /dev/null
+++ b/ElvUI_OptionsUI/General.lua
@@ -0,0 +1,718 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+local Misc = E:GetModule("Misc")
+local Layout = E:GetModule("Layout")
+local Totems = E:GetModule("Totems")
+local Blizzard = E:GetModule("Blizzard")
+local Threat = E:GetModule("Threat")
+local AFK = E:GetModule("AFK")
+
+local _G = _G
+
+local FCF_GetNumActiveChatFrames = FCF_GetNumActiveChatFrames
+
+local function GetChatWindowInfo()
+ local ChatTabInfo = {}
+ for i = 1, FCF_GetNumActiveChatFrames() do
+ if i ~= 2 then
+ ChatTabInfo["ChatFrame"..i] = _G["ChatFrame"..i.."Tab"]:GetText()
+ end
+ end
+
+ return ChatTabInfo
+end
+
+E.Options.args.general = {
+ order = 1,
+ type = "group",
+ name = L["General"],
+ childGroups = "tab",
+ get = function(info) return E.db.general[info[#info]] end,
+ set = function(info, value) E.db.general[info[#info]] = value end,
+ args = {
+ intro = {
+ order = 1,
+ type = "description",
+ name = L["ELVUI_DESC"]
+ },
+ general = {
+ order = 2,
+ type = "group",
+ name = L["General"],
+ args = {
+ generalHeader = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ messageRedirect = {
+ order = 2,
+ type = "select",
+ name = L["Chat Output"],
+ desc = L["This selects the Chat Frame to use as the output of ElvUI messages."],
+ values = GetChatWindowInfo()
+ },
+ AutoScale = {
+ order = 3,
+ type = "execute",
+ name = L["Auto Scale"],
+ func = function()
+ E.global.general.UIScale = E:PixelBestSize()
+ E:StaticPopup_Show("UISCALE_CHANGE")
+ end
+ },
+ UIScale = {
+ order = 4,
+ type = "range",
+ name = L["UI_SCALE"],
+ min = 0.1, max = 1.25, step = 0.0000000000000001,
+ softMin = 0.40, softMax = 1.15, bigStep = 0.01,
+ get = function(info) return E.global.general.UIScale end,
+ set = function(info, value)
+ E.global.general.UIScale = value
+ E:StaticPopup_Show("UISCALE_CHANGE")
+ end
+ },
+ ignoreScalePopup = {
+ order = 5,
+ type = "toggle",
+ name = L["Ignore UI Scale Popup"],
+ desc = L["This will prevent the UI Scale Popup from being shown when changing the game window size."],
+ get = function(info) return E.global.general.ignoreScalePopup end,
+ set = function(info, value) E.global.general.ignoreScalePopup = value end
+ },
+ pixelPerfect = {
+ order = 6,
+ type = "toggle",
+ name = L["Thin Border Theme"],
+ desc = L["The Thin Border Theme option will change the overall apperance of your UI. Using Thin Border Theme is a slight performance increase over the traditional layout."],
+ get = function(info) return E.private.general.pixelPerfect end,
+ set = function(info, value) E.private.general.pixelPerfect = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ eyefinity = {
+ order = 7,
+ type = "toggle",
+ name = L["Multi-Monitor Support"],
+ desc = L["Attempt to support eyefinity/nvidia surround."],
+ get = function(info) return E.global.general.eyefinity end,
+ set = function(info, value) E.global.general.eyefinity = value E:StaticPopup_Show("GLOBAL_RL") end
+ },
+ taintLog = {
+ order = 8,
+ type = "toggle",
+ name = L["Log Taints"],
+ desc = L["Send ADDON_ACTION_BLOCKED errors to the Lua Error frame. These errors are less important in most cases and will not effect your game performance. Also a lot of these errors cannot be fixed. Please only report these errors if you notice a Defect in gameplay."]
+ },
+ bottomPanel = {
+ order = 9,
+ type = "toggle",
+ name = L["Bottom Panel"],
+ desc = L["Display a panel across the bottom of the screen. This is for cosmetic only."],
+ set = function(info, value) E.db.general.bottomPanel = value Layout:BottomPanelVisibility() end
+ },
+ topPanel = {
+ order = 10,
+ type = "toggle",
+ name = L["Top Panel"],
+ desc = L["Display a panel across the top of the screen. This is for cosmetic only."],
+ set = function(info, value) E.db.general.topPanel = value Layout:TopPanelVisibility() end
+ },
+ afk = {
+ order = 11,
+ type = "toggle",
+ name = L["AFK Mode"],
+ desc = L["When you go AFK display the AFK screen."],
+ set = function(info, value) E.db.general.afk = value AFK:Toggle() end
+ },
+ decimalLength = {
+ order = 12,
+ type = "range",
+ name = L["Decimal Length"],
+ desc = L["Controls the amount of decimals used in values displayed on elements like NamePlates and UnitFrames."],
+ min = 0, max = 4, step = 1,
+ set = function(info, value)
+ E.db.general.decimalLength = value
+ E:BuildPrefixValues()
+ E:StaticPopup_Show("CONFIG_RL")
+ end
+ },
+ numberPrefixStyle = {
+ order = 13,
+ type = "select",
+ name = L["Unit Prefix Style"],
+ desc = L["The unit prefixes you want to use when values are shortened in ElvUI. This is mostly used on UnitFrames."],
+ set = function(info, value)
+ E.db.general.numberPrefixStyle = value
+ E:BuildPrefixValues()
+ E:StaticPopup_Show("CONFIG_RL")
+ end,
+ values = {
+ ["CHINESE"] = "Chinese (W, Y)",
+ ["ENGLISH"] = "English (K, M, B)",
+ ["GERMAN"] = "German (Tsd, Mio, Mrd)",
+ ["KOREAN"] = "Korean (천, 만, 억)",
+ ["METRIC"] = "Metric (k, M, G)"
+ }
+ },
+ smoothingAmount = {
+ order = 14,
+ type = "range",
+ isPercent = true,
+ name = L["Smoothing Amount"],
+ desc = L["Controls the speed at which smoothed bars will be updated."],
+ min = 0.1, max = 0.8, softMax = 0.75, softMin = 0.25, step = 0.01,
+ set = function(info, value)
+ E.db.general.smoothingAmount = value
+ E:SetSmoothingAmount(value)
+ end
+ },
+ locale = {
+ order = 15,
+ type = "select",
+ name = L["LANGUAGE"],
+ get = function(info) return E.global.general.locale end,
+ set = function(info, value)
+ E.global.general.locale = value
+ E:StaticPopup_Show("CONFIG_RL")
+ end,
+ values = {
+ ["deDE"] = "Deutsch",
+ ["enUS"] = "English",
+ ["esMX"] = "Español",
+ ["frFR"] = "Français",
+ ["ptBR"] = "Português",
+ ["ruRU"] = "Русский",
+ ["zhCN"] = "简体中文",
+ ["zhTW"] = "正體中文",
+ ["koKR"] = "한국어"
+ }
+ }
+ }
+ },
+ media = {
+ order = 3,
+ type = "group",
+ name = L["Media"],
+ get = function(info) return E.db.general[info[#info]] end,
+ set = function(info, value) E.db.general[info[#info]] = value end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Media"]
+ },
+ fontGroup = {
+ order = 2,
+ type = "group",
+ name = L["Font"],
+ guiInline = true,
+ args = {
+ font = {
+ order = 1,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Default Font"],
+ desc = L["The font that the core of the UI will use."],
+ values = AceGUIWidgetLSMlists.font,
+ set = function(info, value) E.db.general[info[#info]] = value E:UpdateMedia() E:UpdateFontTemplates() end
+ },
+ fontSize = {
+ order = 2,
+ type = "range",
+ name = L["FONT_SIZE"],
+ desc = L["Set the font size for everything in UI. Note: This doesn't effect somethings that have their own seperate options (UnitFrame Font, Datatext Font, ect..)"],
+ min = 4, max = 32, step = 1,
+ set = function(info, value) E.db.general[info[#info]] = value E:UpdateMedia() E:UpdateFontTemplates() end
+ },
+ fontStyle = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ values = C.Values.FontFlags,
+ set = function(info, value) E.db.general[info[#info]] = value E:UpdateMedia() E:UpdateFontTemplates() end
+ },
+ applyFontToAll = {
+ order = 4,
+ type = "execute",
+ name = L["Apply Font To All"],
+ desc = L["Applies the font and font size settings throughout the entire user interface. Note: Some font size settings will be skipped due to them having a smaller font size by default."],
+ func = function() E:StaticPopup_Show("APPLY_FONT_WARNING") end
+ },
+ dmgfont = {
+ order = 5,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["CombatText Font"],
+ desc = L["The font that combat text will use. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"],
+ values = AceGUIWidgetLSMlists.font,
+ get = function(info) return E.private.general[info[#info]] end,
+ set = function(info, value) E.private.general[info[#info]] = value E:UpdateMedia() E:UpdateFontTemplates() E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ namefont = {
+ order = 6,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Name Font"],
+ desc = L["The font that appears on the text above players heads. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"],
+ values = AceGUIWidgetLSMlists.font,
+ get = function(info) return E.private.general[info[#info]] end,
+ set = function(info, value) E.private.general[info[#info]] = value E:UpdateMedia() E:UpdateFontTemplates() E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ replaceBlizzFonts = {
+ order = 7,
+ type = "toggle",
+ name = L["Replace Blizzard Fonts"],
+ desc = L["Replaces the default Blizzard fonts on various panels and frames with the fonts chosen in the Media section of the ElvUI Options. NOTE: Any font that inherits from the fonts ElvUI usually replaces will be affected as well if you disable this. Enabled by default."],
+ get = function(info) return E.private.general[info[#info]] end,
+ set = function(info, value) E.private.general[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end
+ }
+ }
+ },
+ textureGroup = {
+ order = 3,
+ type = "group",
+ name = L["Textures"],
+ guiInline = true,
+ get = function(info) return E.private.general[info[#info]] end,
+ args = {
+ normTex = {
+ order = 1,
+ type = "select", dialogControl = "LSM30_Statusbar",
+ name = L["Primary Texture"],
+ desc = L["The texture that will be used mainly for statusbars."],
+ values = AceGUIWidgetLSMlists.statusbar,
+ set = function(info, value)
+ local previousValue = E.private.general[info[#info]]
+ E.private.general[info[#info]] = value
+
+ if E.db.unitframe.statusbar == previousValue then
+ E.db.unitframe.statusbar = value
+ E:UpdateAll(true)
+ else
+ E:UpdateMedia()
+ E:UpdateStatusBars()
+ end
+ end
+ },
+ glossTex = {
+ order = 2,
+ type = "select", dialogControl = "LSM30_Statusbar",
+ name = L["Secondary Texture"],
+ desc = L["This texture will get used on objects like chat windows and dropdown menus."],
+ values = AceGUIWidgetLSMlists.statusbar,
+ set = function(info, value)
+ E.private.general[info[#info]] = value
+ E:UpdateMedia()
+ E:UpdateFrameTemplates()
+ end
+ },
+ applyTextureToAll = {
+ order = 3,
+ type = "execute",
+ name = L["Apply Texture To All"],
+ desc = L["Applies the primary texture to all statusbars."],
+ func = function()
+ local texture = E.private.general.normTex
+ E.db.unitframe.statusbar = texture
+ E.db.nameplates.statusbar = texture
+ E:UpdateAll(true)
+ end
+ }
+ }
+ },
+ colorsGroup = {
+ order = 4,
+ type = "group",
+ name = L["COLORS"],
+ guiInline = true,
+ get = function(info)
+ local t = E.db.general[info[#info]]
+ local d = P.general[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local setting = info[#info]
+ local t = E.db.general[setting]
+ t.r, t.g, t.b, t.a = r, g, b, a
+ E:UpdateMedia()
+ if setting == "bordercolor" then
+ E:UpdateBorderColors()
+ elseif setting == "backdropcolor" or setting == "backdropfadecolor" then
+ E:UpdateBackdropColors()
+ end
+ end,
+ args = {
+ bordercolor = {
+ order = 1,
+ type = "color",
+ name = L["Border Color"],
+ desc = L["Main border color of the UI."],
+ hasAlpha = false,
+ },
+ backdropcolor = {
+ order = 2,
+ type = "color",
+ name = L["Backdrop Color"],
+ desc = L["Main backdrop color of the UI."],
+ hasAlpha = false,
+ },
+ backdropfadecolor = {
+ order = 3,
+ type = "color",
+ name = L["Backdrop Faded Color"],
+ desc = L["Backdrop color of transparent frames"],
+ hasAlpha = true,
+ },
+ valuecolor = {
+ order = 4,
+ type = "color",
+ name = L["Value Color"],
+ desc = L["Color some texts use."],
+ hasAlpha = false,
+ },
+ herocolor = {
+ order = 5,
+ type = "color",
+ name = "Class Color",
+ desc = "Color of class colored elements.",
+ hasAlpha = false,
+ },
+ cropIcon = {
+ order = 6,
+ type = "toggle",
+ tristate = true,
+ name = L["Crop Icons"],
+ desc = L["This is for Customized Icons in your Interface/Icons folder."],
+ get = function(info)
+ local value = E.db.general[info[#info]]
+ if value == 2 then return true
+ elseif value == 1 then return nil
+ else return false end
+ end,
+ set = function(info, value)
+ E.db.general[info[#info]] = (value and 2) or (value == nil and 1) or 0
+ E:StaticPopup_Show("PRIVATE_RL")
+ end
+ }
+ }
+ }
+ }
+ },
+ totems = {
+ order = 4,
+ type = "group",
+ name = L["Class Totems"],
+ get = function(info) return E.db.general.totems[info[#info]] end,
+ set = function(info, value) E.db.general.totems[info[#info]] = value Totems:PositionAndSize() end,
+ hidden = function() return false end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = TUTORIAL_TITLE47
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value) E.db.general.totems[info[#info]] = value Totems:ToggleEnable() end
+ },
+ size = {
+ order = 3,
+ type = "range",
+ name = L["Button Size"],
+ min = 24, max = 60, step = 1,
+ disabled = function() return not E.db.general.totems.enable end
+ },
+ spacing = {
+ order = 4,
+ type = "range",
+ name = L["Button Spacing"],
+ min = 1, max = 10, step = 1,
+ disabled = function() return not E.db.general.totems.enable end
+ },
+ sortDirection = {
+ order = 5,
+ type = "select",
+ name = L["Sort Direction"],
+ values = {
+ ["ASCENDING"] = L["Ascending"],
+ ["DESCENDING"] = L["Descending"]
+ },
+ disabled = function() return not E.db.general.totems.enable end
+ },
+ growthDirection = {
+ order = 6,
+ type = "select",
+ name = L["Bar Direction"],
+ values = {
+ ["VERTICAL"] = L["Vertical"],
+ ["HORIZONTAL"] = L["Horizontal"]
+ },
+ disabled = function() return not E.db.general.totems.enable end
+ }
+ }
+ },
+ chatBubblesGroup = {
+ order = 5,
+ type = "group",
+ name = L["Chat Bubbles"],
+ get = function(info) return E.private.general[info[#info]] end,
+ set = function(info, value) E.private.general[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Chat Bubbles"]
+ },
+ chatBubbles = {
+ order = 2,
+ type = "select",
+ name = L["Chat Bubbles Style"],
+ desc = L["Skin the blizzard chat bubbles."],
+ values = {
+ ["backdrop"] = L["Skin Backdrop"],
+ ["nobackdrop"] = L["Remove Backdrop"],
+ ["backdrop_noborder"] = L["Skin Backdrop (No Borders)"],
+ ["disabled"] = L["DISABLE"]
+ }
+ },
+ chatBubbleFont = {
+ order = 3,
+ type = "select",
+ name = L["Font"],
+ dialogControl = "LSM30_Font",
+ values = AceGUIWidgetLSMlists.font,
+ disabled = function() return E.private.general.chatBubbles == "disabled" end
+ },
+ chatBubbleFontSize = {
+ order = 4,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 32, step = 1,
+ disabled = function() return E.private.general.chatBubbles == "disabled" end
+ },
+ chatBubbleFontOutline = {
+ order = 5,
+ type = "select",
+ name = L["Font Outline"],
+ disabled = function() return E.private.general.chatBubbles == "disabled" end,
+ values = C.Values.FontFlags
+ },
+ chatBubbleName = {
+ order = 6,
+ type = "toggle",
+ name = L["Chat Bubble Names"],
+ desc = L["Display the name of the unit on the chat bubble."],
+ disabled = function() return E.private.general.chatBubbles == "disabled" or E.private.general.chatBubbles == "nobackdrop" end
+ }
+ }
+ },
+ objectiveFrameGroup = {
+ order = 6,
+ type = "group",
+ name = L["Objective Frame"],
+ get = function(info) return E.db.general[info[#info]] end,
+ args = {
+ objectiveFrameHeader = {
+ order = 1,
+ type = "header",
+ name = L["Objective Frame"],
+ },
+ watchFrameAutoHide = {
+ order = 2,
+ type = "toggle",
+ name = L["Auto Hide"],
+ desc = L["Automatically hide the objetive frame during boss or arena fights."],
+ set = function(info, value) E.db.general.watchFrameAutoHide = value; Blizzard:SetObjectiveFrameAutoHide() end,
+ },
+ watchFrameHeight = {
+ order = 3,
+ type = "range",
+ name = L["Objective Frame Height"],
+ desc = L["Height of the objective tracker. Increase size to be able to see more objectives."],
+ min = 400, max = E.screenheight, step = 1,
+ set = function(info, value) E.db.general.watchFrameHeight = value; Blizzard:SetWatchFrameHeight() end,
+ },
+ },
+ },
+ threatGroup = {
+ order = 7,
+ type = "group",
+ name = L["Threat"],
+ get = function(info) return E.db.general.threat[info[#info]] end,
+ args = {
+ threatHeader = {
+ order = 1,
+ type = "header",
+ name = L["Threat"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value) E.db.general.threat.enable = value Threat:ToggleEnable()end
+ },
+ position = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ desc = L["Adjust the position of the threat bar to either the left or right datatext panels."],
+ values = {
+ ["LEFTCHAT"] = L["Left Chat"],
+ ["RIGHTCHAT"] = L["Right Chat"]
+ },
+ set = function(info, value) E.db.general.threat.position = value Threat:UpdatePosition() end,
+ disabled = function() return not E.db.general.threat.enable end
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = ""
+ },
+ textSize = {
+ order = 5,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 6, max = 22, step = 1,
+ set = function(info, value) E.db.general.threat.textSize = value Threat:UpdatePosition() end,
+ disabled = function() return not E.db.general.threat.enable end
+ },
+ textOutline = {
+ order = 6,
+ type = "select",
+ name = L["Font Outline"],
+ values = C.Values.FontFlags,
+ set = function(info, value) E.db.general.threat.textOutline = value Threat:UpdatePosition() end,
+ disabled = function() return not E.db.general.threat.enable end
+ }
+ }
+ },
+ blizzUIImprovements = {
+ order = 8,
+ type = "group",
+ name = L["BlizzUI Improvements"],
+ get = function(info) return E.db.general[info[#info]] end,
+ set = function(info, value) E.db.general[info[#info]] = value end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["BlizzUI Improvements"]
+ },
+ loot = {
+ order = 2,
+ type = "toggle",
+ name = L["LOOT"],
+ desc = L["Enable/Disable the loot frame."],
+ get = function(info) return E.private.general[info[#info]] end,
+ set = function(info, value)
+ E.private.general[info[#info]] = value
+ E:StaticPopup_Show("PRIVATE_RL")
+ end
+ },
+ lootRoll = {
+ order = 3,
+ type = "toggle",
+ name = L["Loot Roll"],
+ desc = L["Enable/Disable the loot roll frame."],
+ get = function(info) return E.private.general[info[#info]] end,
+ set = function(info, value)
+ E.private.general[info[#info]] = value
+ E:StaticPopup_Show("PRIVATE_RL")
+ end
+ },
+ hideErrorFrame = {
+ order = 4,
+ type = "toggle",
+ name = L["Hide Error Text"],
+ desc = L["Hides the red error text at the top of the screen while in combat."],
+ set = function(info, value)
+ E.db.general[info[#info]] = value
+ Misc:ToggleErrorHandling()
+ end
+ },
+ enhancedPvpMessages = {
+ order = 5,
+ type = "toggle",
+ name = L["Enhanced PVP Messages"],
+ desc = L["Display battleground messages in the middle of the screen."],
+ },
+ raidUtility = {
+ order = 7,
+ type = "toggle",
+ name = L["RAID_CONTROL"],
+ desc = L["Enables the ElvUI Raid Control panel."],
+ get = function(info) return E.private.general[info[#info]] end,
+ set = function(info, value)
+ E.private.general[info[#info]] = value
+ E:StaticPopup_Show("PRIVATE_RL")
+ end
+ },
+ vehicleSeatIndicatorSize = {
+ order = 8,
+ type = "range",
+ name = L["Vehicle Seat Indicator Size"],
+ min = 64, max = 128, step = 4,
+ set = function(info, value)
+ E.db.general[info[#info]] = value
+ Blizzard:UpdateVehicleFrame()
+ end
+ }
+ }
+ },
+ misc = {
+ order = 9,
+ type = "group",
+ name = L["MISCELLANEOUS"],
+ get = function(info) return E.db.general[info[#info]] end,
+ set = function(info, value) E.db.general[info[#info]] = value end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["MISCELLANEOUS"]
+ },
+ interruptAnnounce = {
+ order = 2,
+ type = "select",
+ name = L["Announce Interrupts"],
+ desc = L["Announce when you interrupt a spell to the specified chat channel."],
+ values = {
+ ["NONE"] = L["NONE"],
+ ["SAY"] = L["SAY"],
+ ["PARTY"] = L["Party Only"],
+ ["RAID"] = L["Party / Raid"],
+ ["RAID_ONLY"] = L["Raid Only"],
+ ["EMOTE"] = L["EMOTE"]
+ },
+ set = function(info, value)
+ E.db.general[info[#info]] = value
+ Misc:ToggleInterruptAnnounce()
+ end
+ },
+ autoRepair = {
+ order = 3,
+ type = "select",
+ name = L["Auto Repair"],
+ desc = L["Automatically repair using the following method when visiting a merchant."],
+ values = {
+ ["NONE"] = L["NONE"],
+ ["GUILD"] = L["GUILD"],
+ ["PLAYER"] = L["PLAYER"]
+ }
+ },
+ autoAcceptInvite = {
+ order = 4,
+ type = "toggle",
+ name = L["Accept Invites"],
+ desc = L["Automatically accept invites from guild/friends."]
+ },
+ autoRoll = {
+ order = 5,
+ type = "toggle",
+ name = L["Auto Greed/DE"],
+ desc = L["Automatically select greed or disenchant (when available) on green quality items. This will only work if you are the max level."],
+ disabled = function() return not E.private.general.lootRoll end
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfig-3.0.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfig-3.0.lua
new file mode 100644
index 0000000..c5fcfd2
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfig-3.0.lua
@@ -0,0 +1,58 @@
+--- AceConfig-3.0 wrapper library.
+-- Provides an API to register an options table with the config registry,
+-- as well as associate it with a slash command.
+-- @class file
+-- @name AceConfig-3.0
+-- @release $Id$
+
+--[[
+AceConfig-3.0
+
+Very light wrapper library that combines all the AceConfig subcomponents into one more easily used whole.
+
+]]
+
+local cfgreg = LibStub("AceConfigRegistry-3.0-ElvUI")
+local cfgcmd = LibStub("AceConfigCmd-3.0-ElvUI")
+
+local MAJOR, MINOR = "AceConfig-3.0-ElvUI", 3
+local AceConfig = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceConfig then return end
+
+--TODO: local cfgdlg = LibStub("AceConfigDialog-3.0", true)
+--TODO: local cfgdrp = LibStub("AceConfigDropdown-3.0", true)
+
+-- Lua APIs
+local pcall, error, type, pairs = pcall, error, type, pairs
+
+-- -------------------------------------------------------------------
+-- :RegisterOptionsTable(appName, options, slashcmd, persist)
+--
+-- - appName - (string) application name
+-- - options - table or function ref, see AceConfigRegistry
+-- - slashcmd - slash command (string) or table with commands, or nil to NOT create a slash command
+
+--- Register a option table with the AceConfig registry.
+-- You can supply a slash command (or a table of slash commands) to register with AceConfigCmd directly.
+-- @paramsig appName, options [, slashcmd]
+-- @param appName The application name for the config table.
+-- @param options The option table (or a function to generate one on demand). http://www.wowace.com/addons/ace3/pages/ace-config-3-0-options-tables/
+-- @param slashcmd A slash command to register for the option table, or a table of slash commands.
+-- @usage
+-- local AceConfig = LibStub("AceConfig-3.0")
+-- AceConfig:RegisterOptionsTable("MyAddon", myOptions, {"/myslash", "/my"})
+function AceConfig:RegisterOptionsTable(appName, options, slashcmd)
+ local ok,msg = pcall(cfgreg.RegisterOptionsTable, self, appName, options)
+ if not ok then error(msg, 2) end
+
+ if slashcmd then
+ if type(slashcmd) == "table" then
+ for _,cmd in pairs(slashcmd) do
+ cfgcmd:CreateChatCommand(cmd, appName)
+ end
+ else
+ cfgcmd:CreateChatCommand(slashcmd, appName)
+ end
+ end
+end
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfig-3.0.xml b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfig-3.0.xml
new file mode 100644
index 0000000..87972ad
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfig-3.0.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua
new file mode 100644
index 0000000..63cc489
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua
@@ -0,0 +1,794 @@
+--- AceConfigCmd-3.0 handles access to an options table through the "command line" interface via the ChatFrames.
+-- @class file
+-- @name AceConfigCmd-3.0
+-- @release $Id$
+
+--[[
+AceConfigCmd-3.0
+
+Handles commandline optionstable access
+
+REQUIRES: AceConsole-3.0 for command registration (loaded on demand)
+
+]]
+
+-- TODO: plugin args
+
+local cfgreg = LibStub("AceConfigRegistry-3.0-ElvUI")
+
+local MAJOR, MINOR = "AceConfigCmd-3.0-ElvUI", 14
+local AceConfigCmd = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceConfigCmd then return end
+
+AceConfigCmd.commands = AceConfigCmd.commands or {}
+local commands = AceConfigCmd.commands
+
+local AceConsole -- LoD
+local AceConsoleName = "AceConsole-3.0"
+
+-- Lua APIs
+local strsub, strsplit, strlower, strmatch, strtrim = string.sub, string.split, string.lower, string.match, string.trim
+local format, tonumber, tostring = string.format, tonumber, tostring
+local tsort, tinsert = table.sort, table.insert
+local select, pairs, next, type = select, pairs, next, type
+local error, assert = error, assert
+
+-- WoW APIs
+local _G = _G
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: LibStub, SELECTED_CHAT_FRAME, DEFAULT_CHAT_FRAME
+
+
+local L = setmetatable({}, { -- TODO: replace with proper locale
+ __index = function(self,k) return k end
+})
+
+
+
+local function print(msg)
+ (SELECTED_CHAT_FRAME or DEFAULT_CHAT_FRAME):AddMessage(msg)
+end
+
+-- constants used by getparam() calls below
+
+local handlertypes = {["table"]=true}
+local handlermsg = "expected a table"
+
+local functypes = {["function"]=true, ["string"]=true}
+local funcmsg = "expected function or member name"
+
+
+-- pickfirstset() - picks the first non-nil value and returns it
+
+local function pickfirstset(...)
+ for i=1,select("#",...) do
+ if select(i,...)~=nil then
+ return select(i,...)
+ end
+ end
+end
+
+
+-- err() - produce real error() regarding malformed options tables etc
+
+local function err(info,inputpos,msg )
+ local cmdstr=" "..strsub(info.input, 1, inputpos-1)
+ error(MAJOR..": /" ..info[0] ..cmdstr ..": "..(msg or "malformed options table"), 2)
+end
+
+
+-- usererr() - produce chatframe message regarding bad slash syntax etc
+
+local function usererr(info,inputpos,msg )
+ local cmdstr=strsub(info.input, 1, inputpos-1);
+ print("/" ..info[0] .. " "..cmdstr ..": "..(msg or "malformed options table"))
+end
+
+
+-- callmethod() - call a given named method (e.g. "get", "set") with given arguments
+
+local function callmethod(info, inputpos, tab, methodtype, ...)
+ local method = info[methodtype]
+ if not method then
+ err(info, inputpos, "'"..methodtype.."': not set")
+ end
+
+ info.arg = tab.arg
+ info.option = tab
+ info.type = tab.type
+
+ if type(method)=="function" then
+ return method(info, ...)
+ elseif type(method)=="string" then
+ if type(info.handler[method])~="function" then
+ err(info, inputpos, "'"..methodtype.."': '"..method.."' is not a member function of "..tostring(info.handler))
+ end
+ return info.handler[method](info.handler, info, ...)
+ else
+ assert(false) -- type should have already been checked on read
+ end
+end
+
+-- callfunction() - call a given named function (e.g. "name", "desc") with given arguments
+
+local function callfunction(info, tab, methodtype, ...)
+ local method = tab[methodtype]
+
+ info.arg = tab.arg
+ info.option = tab
+ info.type = tab.type
+
+ if type(method)=="function" then
+ return method(info, ...)
+ else
+ assert(false) -- type should have already been checked on read
+ end
+end
+
+-- do_final() - do the final step (set/execute) along with validation and confirmation
+
+local function do_final(info, inputpos, tab, methodtype, ...)
+ if info.validate then
+ local res = callmethod(info,inputpos,tab,"validate",...)
+ if type(res)=="string" then
+ usererr(info, inputpos, "'"..strsub(info.input, inputpos).."' - "..res)
+ return
+ end
+ end
+ -- console ignores .confirm
+
+ callmethod(info,inputpos,tab,methodtype, ...)
+end
+
+
+-- getparam() - used by handle() to retreive and store "handler", "get", "set", etc
+
+local function getparam(info, inputpos, tab, depth, paramname, types, errormsg)
+ local old,oldat = info[paramname], info[paramname.."_at"]
+ local val=tab[paramname]
+ if val~=nil then
+ if val==false then
+ val=nil
+ elseif not types[type(val)] then
+ err(info, inputpos, "'" .. paramname.. "' - "..errormsg)
+ end
+ info[paramname] = val
+ info[paramname.."_at"] = depth
+ end
+ return old,oldat
+end
+
+
+-- iterateargs(tab) - custom iterator that iterates both t.args and t.plugins.*
+local dummytable={}
+
+local function iterateargs(tab)
+ if not tab.plugins then
+ return pairs(tab.args)
+ end
+
+ local argtabkey,argtab=next(tab.plugins)
+ local v
+
+ return function(_, k)
+ while argtab do
+ k,v = next(argtab, k)
+ if k then return k,v end
+ if argtab==tab.args then
+ argtab=nil
+ else
+ argtabkey,argtab = next(tab.plugins, argtabkey)
+ if not argtabkey then
+ argtab=tab.args
+ end
+ end
+ end
+ end
+end
+
+local function checkhidden(info, inputpos, tab)
+ if tab.cmdHidden~=nil then
+ return tab.cmdHidden
+ end
+ local hidden = tab.hidden
+ if type(hidden) == "function" or type(hidden) == "string" then
+ info.hidden = hidden
+ hidden = callmethod(info, inputpos, tab, 'hidden')
+ info.hidden = nil
+ end
+ return hidden
+end
+
+local function showhelp(info, inputpos, tab, depth, noHead)
+ if not noHead then
+ print("|cff33ff99"..info.appName.."|r: Arguments to |cffffff78/"..info[0].."|r "..strsub(info.input,1,inputpos-1)..":")
+ end
+
+ local sortTbl = {} -- [1..n]=name
+ local refTbl = {} -- [name]=tableref
+
+ for k,v in iterateargs(tab) do
+ if not refTbl[k] then -- a plugin overriding something in .args
+ tinsert(sortTbl, k)
+ refTbl[k] = v
+ end
+ end
+
+ tsort(sortTbl, function(one, two)
+ local o1 = refTbl[one].order or 100
+ local o2 = refTbl[two].order or 100
+ if type(o1) == "function" or type(o1) == "string" then
+ info.order = o1
+ info[#info+1] = one
+ o1 = callmethod(info, inputpos, refTbl[one], "order")
+ info[#info] = nil
+ info.order = nil
+ end
+ if type(o2) == "function" or type(o1) == "string" then
+ info.order = o2
+ info[#info+1] = two
+ o2 = callmethod(info, inputpos, refTbl[two], "order")
+ info[#info] = nil
+ info.order = nil
+ end
+ if o1<0 and o2<0 then return o1 4) and not _G["KEY_" .. text] then
+ return false
+ end
+ local s = text
+ if shift then
+ s = "SHIFT-" .. s
+ end
+ if ctrl then
+ s = "CTRL-" .. s
+ end
+ if alt then
+ s = "ALT-" .. s
+ end
+ return s
+end
+
+-- handle() - selfrecursing function that processes input->optiontable
+-- - depth - starts at 0
+-- - retfalse - return false rather than produce error if a match is not found (used by inlined groups)
+
+local function handle(info, inputpos, tab, depth, retfalse)
+
+ if not(type(tab)=="table" and type(tab.type)=="string") then err(info,inputpos) end
+
+ -------------------------------------------------------------------
+ -- Grab hold of handler,set,get,func,etc if set (and remember old ones)
+ -- Note that we do NOT validate if method names are correct at this stage,
+ -- the handler may change before they're actually used!
+
+ local oldhandler,oldhandler_at = getparam(info,inputpos,tab,depth,"handler",handlertypes,handlermsg)
+ local oldset,oldset_at = getparam(info,inputpos,tab,depth,"set",functypes,funcmsg)
+ local oldget,oldget_at = getparam(info,inputpos,tab,depth,"get",functypes,funcmsg)
+ local oldfunc,oldfunc_at = getparam(info,inputpos,tab,depth,"func",functypes,funcmsg)
+ local oldvalidate,oldvalidate_at = getparam(info,inputpos,tab,depth,"validate",functypes,funcmsg)
+ --local oldconfirm,oldconfirm_at = getparam(info,inputpos,tab,depth,"confirm",functypes,funcmsg)
+
+ -------------------------------------------------------------------
+ -- Act according to .type of this table
+
+ if tab.type=="group" then
+ ------------ group --------------------------------------------
+
+ if type(tab.args)~="table" then err(info, inputpos) end
+ if tab.plugins and type(tab.plugins)~="table" then err(info,inputpos) end
+
+ -- grab next arg from input
+ local _,nextpos,arg = (info.input):find(" *([^ ]+) *", inputpos)
+ if not arg then
+ showhelp(info, inputpos, tab, depth)
+ return
+ end
+ nextpos=nextpos+1
+
+ -- loop .args and try to find a key with a matching name
+ for k,v in iterateargs(tab) do
+ if not(type(k)=="string" and type(v)=="table" and type(v.type)=="string") then err(info,inputpos, "options table child '"..tostring(k).."' is malformed") end
+
+ -- is this child an inline group? if so, traverse into it
+ if v.type=="group" and pickfirstset(v.cmdInline, v.inline, false) then
+ info[depth+1] = k
+ if handle(info, inputpos, v, depth+1, true)==false then
+ info[depth+1] = nil
+ -- wasn't found in there, but that's ok, we just keep looking down here
+ else
+ return -- done, name was found in inline group
+ end
+ -- matching name and not a inline group
+ elseif strlower(arg)==strlower(k:gsub(" ", "_")) then
+ info[depth+1] = k
+ return handle(info,nextpos,v,depth+1)
+ end
+ end
+
+ -- no match
+ if retfalse then
+ -- restore old infotable members and return false to indicate failure
+ info.handler,info.handler_at = oldhandler,oldhandler_at
+ info.set,info.set_at = oldset,oldset_at
+ info.get,info.get_at = oldget,oldget_at
+ info.func,info.func_at = oldfunc,oldfunc_at
+ info.validate,info.validate_at = oldvalidate,oldvalidate_at
+ --info.confirm,info.confirm_at = oldconfirm,oldconfirm_at
+ return false
+ end
+
+ -- couldn't find the command, display error
+ usererr(info, inputpos, "'"..arg.."' - " .. L["unknown argument"])
+ return
+ end
+
+ local str = strsub(info.input,inputpos);
+
+ if tab.type=="execute" then
+ ------------ execute --------------------------------------------
+ do_final(info, inputpos, tab, "func")
+
+
+
+ elseif tab.type=="input" then
+ ------------ input --------------------------------------------
+
+ local res = true
+ if tab.pattern then
+ if not(type(tab.pattern)=="string") then err(info, inputpos, "'pattern' - expected a string") end
+ if not strmatch(str, tab.pattern) then
+ usererr(info, inputpos, "'"..str.."' - " .. L["invalid input"])
+ return
+ end
+ end
+
+ do_final(info, inputpos, tab, "set", str)
+
+
+
+ elseif tab.type=="toggle" then
+ ------------ toggle --------------------------------------------
+ local b
+ local str = strtrim(strlower(str))
+ if str=="" then
+ b = callmethod(info, inputpos, tab, "get")
+
+ if tab.tristate then
+ --cycle in true, nil, false order
+ if b then
+ b = nil
+ elseif b == nil then
+ b = false
+ else
+ b = true
+ end
+ else
+ b = not b
+ end
+
+ elseif str==L["on"] then
+ b = true
+ elseif str==L["off"] then
+ b = false
+ elseif tab.tristate and str==L["default"] then
+ b = nil
+ else
+ if tab.tristate then
+ usererr(info, inputpos, format(L["'%s' - expected 'on', 'off' or 'default', or no argument to toggle."], str))
+ else
+ usererr(info, inputpos, format(L["'%s' - expected 'on' or 'off', or no argument to toggle."], str))
+ end
+ return
+ end
+
+ do_final(info, inputpos, tab, "set", b)
+
+
+ elseif tab.type=="range" then
+ ------------ range --------------------------------------------
+ local val = tonumber(str)
+ if not val then
+ usererr(info, inputpos, "'"..str.."' - "..L["expected number"])
+ return
+ end
+ if type(info.step)=="number" then
+ val = val- (val % info.step)
+ end
+ if type(info.min)=="number" and valinfo.max then
+ usererr(info, inputpos, val.." - "..format(L["must be equal to or lower than %s"], tostring(info.max)) )
+ return
+ end
+
+ do_final(info, inputpos, tab, "set", val)
+
+
+ elseif tab.type=="select" then
+ ------------ select ------------------------------------
+ local str = strtrim(strlower(str))
+
+ local values = tab.values
+ if type(values) == "function" or type(values) == "string" then
+ info.values = values
+ values = callmethod(info, inputpos, tab, "values")
+ info.values = nil
+ end
+
+ if str == "" then
+ local b = callmethod(info, inputpos, tab, "get")
+ local fmt = "|cffffff78- [%s]|r %s"
+ local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
+ print(L["Options for |cffffff78"..info[#info].."|r:"])
+ for k, v in pairs(values) do
+ if b == k then
+ print(fmt_sel:format(k, v))
+ else
+ print(fmt:format(k, v))
+ end
+ end
+ return
+ end
+
+ local ok
+ for k,v in pairs(values) do
+ if strlower(k)==str then
+ str = k -- overwrite with key (in case of case mismatches)
+ ok = true
+ break
+ end
+ end
+ if not ok then
+ usererr(info, inputpos, "'"..str.."' - "..L["unknown selection"])
+ return
+ end
+
+ do_final(info, inputpos, tab, "set", str)
+
+ elseif tab.type=="multiselect" then
+ ------------ multiselect -------------------------------------------
+ local str = strtrim(strlower(str))
+
+ local values = tab.values
+ if type(values) == "function" or type(values) == "string" then
+ info.values = values
+ values = callmethod(info, inputpos, tab, "values")
+ info.values = nil
+ end
+
+ if str == "" then
+ local fmt = "|cffffff78- [%s]|r %s"
+ local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
+ print(L["Options for |cffffff78"..info[#info].."|r (multiple possible):"])
+ for k, v in pairs(values) do
+ if callmethod(info, inputpos, tab, "get", k) then
+ print(fmt_sel:format(k, v))
+ else
+ print(fmt:format(k, v))
+ end
+ end
+ return
+ end
+
+ --build a table of the selections, checking that they exist
+ --parse for =on =off =default in the process
+ --table will be key = true for options that should toggle, key = [on|off|default] for options to be set
+ local sels = {}
+ for v in str:gmatch("[^ ]+") do
+ --parse option=on etc
+ local opt, val = v:match('(.+)=(.+)')
+ --get option if toggling
+ if not opt then
+ opt = v
+ end
+
+ --check that the opt is valid
+ local ok
+ for k,v in pairs(values) do
+ if strlower(k)==opt then
+ opt = k -- overwrite with key (in case of case mismatches)
+ ok = true
+ break
+ end
+ end
+
+ if not ok then
+ usererr(info, inputpos, "'"..opt.."' - "..L["unknown selection"])
+ return
+ end
+
+ --check that if val was supplied it is valid
+ if val then
+ if val == L["on"] or val == L["off"] or (tab.tristate and val == L["default"]) then
+ --val is valid insert it
+ sels[opt] = val
+ else
+ if tab.tristate then
+ usererr(info, inputpos, format(L["'%s' '%s' - expected 'on', 'off' or 'default', or no argument to toggle."], v, val))
+ else
+ usererr(info, inputpos, format(L["'%s' '%s' - expected 'on' or 'off', or no argument to toggle."], v, val))
+ end
+ return
+ end
+ else
+ -- no val supplied, toggle
+ sels[opt] = true
+ end
+ end
+
+ for opt, val in pairs(sels) do
+ local newval
+
+ if (val == true) then
+ --toggle the option
+ local b = callmethod(info, inputpos, tab, "get", opt)
+
+ if tab.tristate then
+ --cycle in true, nil, false order
+ if b then
+ b = nil
+ elseif b == nil then
+ b = false
+ else
+ b = true
+ end
+ else
+ b = not b
+ end
+ newval = b
+ else
+ --set the option as specified
+ if val==L["on"] then
+ newval = true
+ elseif val==L["off"] then
+ newval = false
+ elseif val==L["default"] then
+ newval = nil
+ end
+ end
+
+ do_final(info, inputpos, tab, "set", opt, newval)
+ end
+
+
+ elseif tab.type=="color" then
+ ------------ color --------------------------------------------
+ local str = strtrim(strlower(str))
+ if str == "" then
+ --TODO: Show current value
+ return
+ end
+
+ local r, g, b, a
+
+ local hasAlpha = tab.hasAlpha
+ if type(hasAlpha) == "function" or type(hasAlpha) == "string" then
+ info.hasAlpha = hasAlpha
+ hasAlpha = callmethod(info, inputpos, tab, 'hasAlpha')
+ info.hasAlpha = nil
+ end
+
+ if hasAlpha then
+ if str:len() == 8 and str:find("^%x*$") then
+ --parse a hex string
+ r,g,b,a = tonumber(str:sub(1, 2), 16) / 255, tonumber(str:sub(3, 4), 16) / 255, tonumber(str:sub(5, 6), 16) / 255, tonumber(str:sub(7, 8), 16) / 255
+ else
+ --parse seperate values
+ r,g,b,a = str:match("^([%d%.]+) ([%d%.]+) ([%d%.]+) ([%d%.]+)$")
+ r,g,b,a = tonumber(r), tonumber(g), tonumber(b), tonumber(a)
+ end
+ if not (r and g and b and a) then
+ usererr(info, inputpos, format(L["'%s' - expected 'RRGGBBAA' or 'r g b a'."], str))
+ return
+ end
+
+ if r >= 0.0 and r <= 1.0 and g >= 0.0 and g <= 1.0 and b >= 0.0 and b <= 1.0 and a >= 0.0 and a <= 1.0 then
+ --values are valid
+ elseif r >= 0 and r <= 255 and g >= 0 and g <= 255 and b >= 0 and b <= 255 and a >= 0 and a <= 255 then
+ --values are valid 0..255, convert to 0..1
+ r = r / 255
+ g = g / 255
+ b = b / 255
+ a = a / 255
+ else
+ --values are invalid
+ usererr(info, inputpos, format(L["'%s' - values must all be either in the range 0..1 or 0..255."], str))
+ end
+ else
+ a = 1.0
+ if str:len() == 6 and str:find("^%x*$") then
+ --parse a hex string
+ r,g,b = tonumber(str:sub(1, 2), 16) / 255, tonumber(str:sub(3, 4), 16) / 255, tonumber(str:sub(5, 6), 16) / 255
+ else
+ --parse seperate values
+ r,g,b = str:match("^([%d%.]+) ([%d%.]+) ([%d%.]+)$")
+ r,g,b = tonumber(r), tonumber(g), tonumber(b)
+ end
+ if not (r and g and b) then
+ usererr(info, inputpos, format(L["'%s' - expected 'RRGGBB' or 'r g b'."], str))
+ return
+ end
+ if r >= 0.0 and r <= 1.0 and g >= 0.0 and g <= 1.0 and b >= 0.0 and b <= 1.0 then
+ --values are valid
+ elseif r >= 0 and r <= 255 and g >= 0 and g <= 255 and b >= 0 and b <= 255 then
+ --values are valid 0..255, convert to 0..1
+ r = r / 255
+ g = g / 255
+ b = b / 255
+ else
+ --values are invalid
+ usererr(info, inputpos, format(L["'%s' - values must all be either in the range 0-1 or 0-255."], str))
+ end
+ end
+
+ do_final(info, inputpos, tab, "set", r,g,b,a)
+
+ elseif tab.type=="keybinding" then
+ ------------ keybinding --------------------------------------------
+ local str = strtrim(strlower(str))
+ if str == "" then
+ --TODO: Show current value
+ return
+ end
+ local value = keybindingValidateFunc(str:upper())
+ if value == false then
+ usererr(info, inputpos, format(L["'%s' - Invalid Keybinding."], str))
+ return
+ end
+
+ do_final(info, inputpos, tab, "set", value)
+
+ elseif tab.type=="description" then
+ ------------ description --------------------
+ -- ignore description, GUI config only
+ else
+ err(info, inputpos, "unknown options table item type '"..tostring(tab.type).."'")
+ end
+end
+
+--- Handle the chat command.
+-- This is usually called from a chat command handler to parse the command input as operations on an aceoptions table.\\
+-- AceConfigCmd uses this function internally when a slash command is registered with `:CreateChatCommand`
+-- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
+-- @param appName The application name as given to `:RegisterOptionsTable()`
+-- @param input The commandline input (as given by the WoW handler, i.e. without the command itself)
+-- @usage
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceConsole-3.0")
+-- -- Use AceConsole-3.0 to register a Chat Command
+-- MyAddon:RegisterChatCommand("mychat", "ChatCommand")
+--
+-- -- Show the GUI if no input is supplied, otherwise handle the chat input.
+-- function MyAddon:ChatCommand(input)
+-- -- Assuming "MyOptions" is the appName of a valid options table
+-- if not input or input:trim() == "" then
+-- LibStub("AceConfigDialog-3.0"):Open("MyOptions")
+-- else
+-- LibStub("AceConfigCmd-3.0").HandleCommand(MyAddon, "mychat", "MyOptions", input)
+-- end
+-- end
+function AceConfigCmd:HandleCommand(slashcmd, appName, input)
+
+ local optgetter = cfgreg:GetOptionsTable(appName)
+ if not optgetter then
+ error([[Usage: HandleCommand("slashcmd", "appName", "input"): 'appName' - no options table "]]..tostring(appName)..[[" has been registered]], 2)
+ end
+ local options = assert( optgetter("cmd", MAJOR) )
+
+ local info = { -- Don't try to recycle this, it gets handed off to callbacks and whatnot
+ [0] = slashcmd,
+ appName = appName,
+ options = options,
+ input = input,
+ self = self,
+ handler = self,
+ uiType = "cmd",
+ uiName = MAJOR,
+ }
+
+ handle(info, 1, options, 0) -- (info, inputpos, table, depth)
+end
+
+--- Utility function to create a slash command handler.
+-- Also registers tab completion with AceTab
+-- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
+-- @param appName The application name as given to `:RegisterOptionsTable()`
+function AceConfigCmd:CreateChatCommand(slashcmd, appName)
+ if not AceConsole then
+ AceConsole = LibStub(AceConsoleName)
+ end
+ if AceConsole.RegisterChatCommand(self, slashcmd, function(input)
+ AceConfigCmd.HandleCommand(self, slashcmd, appName, input) -- upgradable
+ end,
+ true) then -- succesfully registered so lets get the command -> app table in
+ commands[slashcmd] = appName
+ end
+end
+
+--- Utility function that returns the options table that belongs to a slashcommand.
+-- Designed to be used for the AceTab interface.
+-- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
+-- @return The options table associated with the slash command (or nil if the slash command was not registered)
+function AceConfigCmd:GetChatCommandOptions(slashcmd)
+ return commands[slashcmd]
+end
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml
new file mode 100644
index 0000000..188d354
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
new file mode 100644
index 0000000..1de0275
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
@@ -0,0 +1,2080 @@
+--- AceConfigDialog-3.0 generates AceGUI-3.0 based windows based on option tables.
+-- @class file
+-- @name AceConfigDialog-3.0
+-- @release $Id$
+
+local LibStub = LibStub
+local gui = LibStub("AceGUI-3.0")
+local reg = LibStub("AceConfigRegistry-3.0-ElvUI")
+
+local MAJOR, MINOR = "AceConfigDialog-3.0-ElvUI", 79
+local AceConfigDialog, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceConfigDialog then return end
+
+AceConfigDialog.OpenFrames = AceConfigDialog.OpenFrames or {}
+AceConfigDialog.Status = AceConfigDialog.Status or {}
+AceConfigDialog.frame = AceConfigDialog.frame or CreateFrame("Frame")
+
+AceConfigDialog.frame.apps = AceConfigDialog.frame.apps or {}
+AceConfigDialog.frame.closing = AceConfigDialog.frame.closing or {}
+AceConfigDialog.frame.closeAllOverride = AceConfigDialog.frame.closeAllOverride or {}
+
+-- Lua APIs
+local tconcat, tinsert, tsort, tremove = table.concat, table.insert, table.sort, table.remove
+local strmatch, format = string.match, string.format
+local assert, loadstring, error = assert, loadstring, error
+local pairs, next, select, type, unpack, wipe, ipairs = pairs, next, select, type, unpack, wipe, ipairs
+local rawset, tostring, tonumber = rawset, tostring, tonumber
+local math_min, math_max, math_floor = math.min, math.max, math.floor
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: NORMAL_FONT_COLOR, GameTooltip, StaticPopupDialogs, ACCEPT, CANCEL, StaticPopup_Show
+-- GLOBALS: PlaySound, GameFontHighlight, GameFontHighlightSmall, GameFontHighlightLarge
+-- GLOBALS: CloseSpecialWindows, InterfaceOptions_AddCategory, geterrorhandler
+
+local emptyTbl = {}
+
+--[[
+ xpcall safecall implementation
+]]
+local xpcall = xpcall
+
+local function errorhandler(err)
+ return geterrorhandler()(err)
+end
+
+local function CreateDispatcher(argCount)
+ local code = [[
+ local xpcall, eh = ...
+ local method, ARGS
+ local function call() return method(ARGS) end
+
+ local function dispatch(func, ...)
+ method = func
+ if not method then return end
+ ARGS = ...
+ return xpcall(call, eh)
+ end
+
+ return dispatch
+ ]]
+
+ local ARGS = {}
+ for i = 1, argCount do ARGS[i] = "arg"..i end
+ code = code:gsub("ARGS", tconcat(ARGS, ", "))
+ return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
+end
+
+local Dispatchers = setmetatable({}, {__index=function(self, argCount)
+ local dispatcher = CreateDispatcher(argCount)
+ rawset(self, argCount, dispatcher)
+ return dispatcher
+end})
+Dispatchers[0] = function(func)
+ return xpcall(func, errorhandler)
+end
+
+local function safecall(func, ...)
+ return Dispatchers[select("#", ...)](func, ...)
+end
+
+local width_multiplier = 170
+
+--[[
+Group Types
+ Tree - All Descendant Groups will all become nodes on the tree, direct child options will appear above the tree
+ - Descendant Groups with inline=true and thier children will not become nodes
+
+ Tab - Direct Child Groups will become tabs, direct child options will appear above the tab control
+ - Grandchild groups will default to inline unless specified otherwise
+
+ Select- Same as Tab but with entries in a dropdown rather than tabs
+
+
+ Inline Groups
+ - Will not become nodes of a select group, they will be effectivly part of thier parent group seperated by a border
+ - If declared on a direct child of a root node of a select group, they will appear above the group container control
+ - When a group is displayed inline, all descendants will also be inline members of the group
+
+]]
+
+-- Recycling functions
+local new, del, copy
+--newcount, delcount,createdcount,cached = 0,0,0
+do
+ local pool = setmetatable({},{__mode="k"})
+ function new()
+ --newcount = newcount + 1
+ local t = next(pool)
+ if t then
+ pool[t] = nil
+ return t
+ else
+ --createdcount = createdcount + 1
+ return {}
+ end
+ end
+ function copy(t)
+ local c = new()
+ for k, v in pairs(t) do
+ c[k] = v
+ end
+ return c
+ end
+ function del(t)
+ --delcount = delcount + 1
+ wipe(t)
+ pool[t] = true
+ end
+-- function cached()
+-- local n = 0
+-- for k in pairs(pool) do
+-- n = n + 1
+-- end
+-- return n
+-- end
+end
+
+-- picks the first non-nil value and returns it
+local function pickfirstset(...)
+ for i=1,select("#",...) do
+ if select(i,...)~=nil then
+ return select(i,...)
+ end
+ end
+end
+
+--gets an option from a given group, checking plugins
+local function GetSubOption(group, key)
+ if group.plugins then
+ for plugin, t in pairs(group.plugins) do
+ if t[key] then
+ return t[key]
+ end
+ end
+ end
+
+ return group.args[key]
+end
+
+--Option member type definitions, used to decide how to access it
+
+--Is the member Inherited from parent options
+local isInherited = {
+ set = true,
+ get = true,
+ func = true,
+ confirm = true,
+ validate = true,
+ disabled = true,
+ hidden = true
+}
+
+--Does a string type mean a literal value, instead of the default of a method of the handler
+local stringIsLiteral = {
+ name = true,
+ desc = true,
+ icon = true,
+ usage = true,
+ width = true,
+ image = true,
+ fontSize = true,
+}
+
+--Is Never a function or method
+local allIsLiteral = {
+ type = true,
+ descStyle = true,
+ imageWidth = true,
+ imageHeight = true,
+}
+
+--gets the value for a member that could be a function
+--function refs are called with an info arg
+--every other type is returned
+local function GetOptionsMemberValue(membername, option, options, path, appName, ...)
+ --get definition for the member
+ local inherits = isInherited[membername]
+
+
+ --get the member of the option, traversing the tree if it can be inherited
+ local member
+
+ if inherits then
+ local group = options
+ if group[membername] ~= nil then
+ member = group[membername]
+ end
+ for i = 1, #path do
+ group = GetSubOption(group, path[i])
+ if group[membername] ~= nil then
+ member = group[membername]
+ end
+ end
+ else
+ member = option[membername]
+ end
+
+ --check if we need to call a functon, or if we have a literal value
+ if ( not allIsLiteral[membername] ) and ( type(member) == "function" or ((not stringIsLiteral[membername]) and type(member) == "string") ) then
+ --We have a function to call
+ local info = new()
+ --traverse the options table, picking up the handler and filling the info with the path
+ local handler
+ local group = options
+ handler = group.handler or handler
+
+ for i = 1, #path do
+ group = GetSubOption(group, path[i])
+ info[i] = path[i]
+ handler = group.handler or handler
+ end
+
+ info.options = options
+ info.appName = appName
+ info[0] = appName
+ info.arg = option.arg
+ info.handler = handler
+ info.option = option
+ info.type = option.type
+ info.uiType = "dialog"
+ info.uiName = MAJOR
+
+ local a, b, c, d, e, f, g, h -- ElvUI adds e,f,g,h for default color
+ --using 4 returns for the get of a color type, increase if a type needs more
+ if type(member) == "function" then
+ --Call the function
+ a,b,c,d,e,f,g,h = member(info, ...)
+ else
+ --Call the method
+ if handler and handler[member] then
+ a,b,c,d,e,f,g,h = handler[member](handler, info, ...)
+ else
+ error(format("Method %s doesn't exist in handler for type %s", member, membername))
+ end
+ end
+ del(info)
+ return a,b,c,d,e,f,g,h
+ else
+ --The value isnt a function to call, return it
+ return member
+ end
+end
+
+--[[calls an options function that could be inherited, method name or function ref
+local function CallOptionsFunction(funcname ,option, options, path, appName, ...)
+ local info = new()
+
+ local func
+ local group = options
+ local handler
+
+ --build the info table containing the path
+ -- pick up functions while traversing the tree
+ if group[funcname] ~= nil then
+ func = group[funcname]
+ end
+ handler = group.handler or handler
+
+ for i, v in ipairs(path) do
+ group = GetSubOption(group, v)
+ info[i] = v
+ if group[funcname] ~= nil then
+ func = group[funcname]
+ end
+ handler = group.handler or handler
+ end
+
+ info.options = options
+ info[0] = appName
+ info.arg = option.arg
+
+ local a, b, c ,d
+ if type(func) == "string" then
+ if handler and handler[func] then
+ a,b,c,d = handler[func](handler, info, ...)
+ else
+ error(string.format("Method %s doesn't exist in handler for type func", func))
+ end
+ elseif type(func) == "function" then
+ a,b,c,d = func(info, ...)
+ end
+ del(info)
+ return a,b,c,d
+end
+--]]
+
+--tables to hold orders and names for options being sorted, will be created with new()
+--prevents needing to call functions repeatedly while sorting
+local tempOrders
+local tempNames
+
+local function compareOptions(a,b)
+ if not a then
+ return true
+ end
+ if not b then
+ return false
+ end
+ local OrderA, OrderB = tempOrders[a] or 100, tempOrders[b] or 100
+ if OrderA == OrderB then
+ local NameA = (type(tempNames[a]) == "string") and tempNames[a] or ""
+ local NameB = (type(tempNames[b]) == "string") and tempNames[b] or ""
+ return NameA:upper() < NameB:upper()
+ end
+ if OrderA < 0 then
+ if OrderB >= 0 then
+ return false
+ end
+ else
+ if OrderB < 0 then
+ return true
+ end
+ end
+ return OrderA < OrderB
+end
+
+
+
+--builds 2 tables out of an options group
+-- keySort, sorted keys
+-- opts, combined options from .plugins and args
+local function BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
+ tempOrders = new()
+ tempNames = new()
+
+ if group.plugins then
+ for plugin, t in pairs(group.plugins) do
+ for k, v in pairs(t) do
+ if not opts[k] then
+ tinsert(keySort, k)
+ opts[k] = v
+
+ path[#path+1] = k
+ tempOrders[k] = GetOptionsMemberValue("order", v, options, path, appName)
+ tempNames[k] = GetOptionsMemberValue("name", v, options, path, appName)
+ path[#path] = nil
+ end
+ end
+ end
+ end
+
+ for k, v in pairs(group.args) do
+ if not opts[k] then
+ tinsert(keySort, k)
+ opts[k] = v
+
+ path[#path+1] = k
+ tempOrders[k] = GetOptionsMemberValue("order", v, options, path, appName)
+ tempNames[k] = GetOptionsMemberValue("name", v, options, path, appName)
+ path[#path] = nil
+ end
+ end
+
+ tsort(keySort, compareOptions)
+
+ del(tempOrders)
+ del(tempNames)
+end
+
+local function DelTree(tree)
+ if tree.children then
+ local childs = tree.children
+ for i = 1, #childs do
+ DelTree(childs[i])
+ del(childs[i])
+ end
+ del(childs)
+ end
+end
+
+local function CleanUserData(widget, event)
+
+ local user = widget:GetUserDataTable()
+
+ if user.path then
+ del(user.path)
+ end
+
+ if widget.type == "TreeGroup" then
+ local tree = user.tree
+ widget:SetTree(nil)
+ if tree then
+ for i = 1, #tree do
+ DelTree(tree[i])
+ del(tree[i])
+ end
+ del(tree)
+ end
+ end
+
+ if widget.type == "TabGroup" then
+ widget:SetTabs(nil)
+ if user.tablist then
+ del(user.tablist)
+ end
+ end
+
+ if widget.type == "DropdownGroup" then
+ widget:SetGroupList(nil)
+ if user.grouplist then
+ del(user.grouplist)
+ end
+ if user.orderlist then
+ del(user.orderlist)
+ end
+ end
+end
+
+-- - Gets a status table for the given appname and options path.
+-- @param appName The application name as given to `:RegisterOptionsTable()`
+-- @param path The path to the options (a table with all group keys)
+-- @return
+function AceConfigDialog:GetStatusTable(appName, path)
+ local status = self.Status
+
+ if not status[appName] then
+ status[appName] = {}
+ status[appName].status = {}
+ status[appName].children = {}
+ end
+
+ status = status[appName]
+
+ if path then
+ for i = 1, #path do
+ local v = path[i]
+ if not status.children[v] then
+ status.children[v] = {}
+ status.children[v].status = {}
+ status.children[v].children = {}
+ end
+ status = status.children[v]
+ end
+ end
+
+ return status.status
+end
+
+--- Selects the specified path in the options window.
+-- The path specified has to match the keys of the groups in the table.
+-- @param appName The application name as given to `:RegisterOptionsTable()`
+-- @param ... The path to the key that should be selected
+function AceConfigDialog:SelectGroup(appName, ...)
+ local path = new()
+
+
+ local app = reg:GetOptionsTable(appName)
+ if not app then
+ error(("%s isn't registed with AceConfigRegistry, unable to open config"):format(appName), 2)
+ end
+ local options = app("dialog", MAJOR)
+ local group = options
+ local status = self:GetStatusTable(appName, path)
+ if not status.groups then
+ status.groups = {}
+ end
+ status = status.groups
+ local treevalue
+ local treestatus
+
+ for n = 1, select("#",...) do
+ local key = select(n, ...)
+
+ if group.childGroups == "tab" or group.childGroups == "select" then
+ --if this is a tab or select group, select the group
+ status.selected = key
+ --children of this group are no longer extra levels of a tree
+ treevalue = nil
+ else
+ --tree group by default
+ if treevalue then
+ --this is an extra level of a tree group, build a uniquevalue for it
+ treevalue = treevalue.."\001"..key
+ else
+ --this is the top level of a tree group, the uniquevalue is the same as the key
+ treevalue = key
+ if not status.groups then
+ status.groups = {}
+ end
+ --save this trees status table for any extra levels or groups
+ treestatus = status
+ end
+ --make sure that the tree entry is open, and select it.
+ --the selected group will be overwritten if a child is the final target but still needs to be open
+ treestatus.selected = treevalue
+ treestatus.groups[treevalue] = true
+
+ end
+
+ --move to the next group in the path
+ group = GetSubOption(group, key)
+ if not group then
+ break
+ end
+ tinsert(path, key)
+ status = self:GetStatusTable(appName, path)
+ if not status.groups then
+ status.groups = {}
+ end
+ status = status.groups
+ end
+
+ del(path)
+ reg:NotifyChange(appName)
+end
+
+local function OptionOnMouseOver(widget, event)
+ --show a tooltip/set the status bar to the desc text
+ local user = widget:GetUserDataTable()
+ local opt = user.option
+ local options = user.options
+ local path = user.path
+ local appName = user.appName
+
+ -- modified by ElvUI
+ if opt.descStyle and opt.descStyle ~= "tooltip" then return end
+
+ local name = GetOptionsMemberValue("name", opt, options, path, appName)
+ local desc = GetOptionsMemberValue("desc", opt, options, path, appName)
+ local usage = GetOptionsMemberValue("usage", opt, options, path, appName)
+
+ local descText = type(desc) == "string"
+ local usageText = type(usage) == "string"
+ local userText = opt.type == "multiselect"
+ local softText = opt.softMin or opt.softMax
+ local bigText = opt.bigStep
+ local Min, Max, Step
+
+ if softText then
+ Min = (opt.min and "|cFFCCCCCCMin:|r "..(opt.isPercent and (opt.min*100).."%" or opt.min)) or ""
+ Max = (opt.max and "|cFFCCCCCCMax:|r "..(opt.isPercent and (opt.max*100).."%" or opt.max)) or ""
+ softText = Min ~= "" or Max ~= ""
+ end
+ if bigText then
+ local dec = opt.step and format("%f", opt.step):gsub('%.?0-$','')
+ local num = dec and tonumber(dec)
+ Step = (num and num > 0 and "|cFFCCCCCCStep:|r "..dec) or ""
+ bigText = Step ~= ""
+ end
+
+ if descText or usageText or userText or softText or bigText then
+ GameTooltip:SetOwner(widget.frame, "ANCHOR_TOPRIGHT")
+ GameTooltip:SetText(name, 1, .82, 0, true)
+
+ if userText then
+ GameTooltip:AddLine(user.text, 0.5, 0.5, 0.8, true)
+ end
+ if descText then
+ GameTooltip:AddLine(desc, 1, 1, 1, true)
+ end
+ if usageText then
+ GameTooltip:AddLine("Usage: "..usage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true)
+ end
+ if bigText or softText then
+ GameTooltip:AddLine(" ")
+ end
+ if bigText then
+ GameTooltip:AddLine(Step, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true)
+ end
+ if softText then
+ GameTooltip:AddDoubleLine(Min, Max)
+ end
+
+ GameTooltip:Show()
+ end
+end
+
+local function OptionOnMouseLeave(widget, event)
+ GameTooltip:Hide()
+end
+
+local function GetFuncName(option)
+ local type = option.type
+ if type == "execute" then
+ return "func"
+ else
+ return "set"
+ end
+end
+local function confirmPopup(appName, rootframe, basepath, info, message, func, ...)
+ if not StaticPopupDialogs["ACECONFIGDIALOG30_CONFIRM_DIALOG"] then
+ StaticPopupDialogs["ACECONFIGDIALOG30_CONFIRM_DIALOG"] = {}
+ end
+ local t = StaticPopupDialogs["ACECONFIGDIALOG30_CONFIRM_DIALOG"]
+ for k in pairs(t) do
+ t[k] = nil
+ end
+ t.text = message
+ t.button1 = ACCEPT
+ t.button2 = CANCEL
+ t.preferredIndex = STATICPOPUP_NUMDIALOGS
+ local dialog, oldstrata
+ t.OnAccept = function()
+ safecall(func, unpack(t))
+ if dialog and oldstrata then
+ dialog:SetFrameStrata(oldstrata)
+ end
+ AceConfigDialog:Open(appName, rootframe, unpack(basepath or emptyTbl))
+ del(info)
+ end
+ t.OnCancel = function()
+ if dialog and oldstrata then
+ dialog:SetFrameStrata(oldstrata)
+ end
+ AceConfigDialog:Open(appName, rootframe, unpack(basepath or emptyTbl))
+ del(info)
+ end
+ for i = 1, select("#", ...) do
+ t[i] = select(i, ...) or false
+ end
+ t.timeout = 0
+ t.whileDead = 1
+ t.hideOnEscape = 1
+
+ dialog = StaticPopup_Show("ACECONFIGDIALOG30_CONFIRM_DIALOG")
+ if dialog then
+ oldstrata = dialog:GetFrameStrata()
+ dialog:SetFrameStrata("TOOLTIP")
+ end
+end
+
+local function validationErrorPopup(message)
+ if not StaticPopupDialogs["ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG"] then
+ StaticPopupDialogs["ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG"] = {}
+ end
+ local t = StaticPopupDialogs["ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG"]
+ t.text = message
+ t.button1 = OKAY
+ t.preferredIndex = STATICPOPUP_NUMDIALOGS
+ local dialog, oldstrata
+ t.OnAccept = function()
+ if dialog and oldstrata then
+ dialog:SetFrameStrata(oldstrata)
+ end
+ end
+ t.timeout = 0
+ t.whileDead = 1
+ t.hideOnEscape = 1
+
+ dialog = StaticPopup_Show("ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG")
+ if dialog then
+ oldstrata = dialog:GetFrameStrata()
+ dialog:SetFrameStrata("TOOLTIP")
+ end
+end
+
+local function ActivateControl(widget, event, ...)
+ --This function will call the set / execute handler for the widget
+ --widget:GetUserDataTable() contains the needed info
+ local user = widget:GetUserDataTable()
+ local option = user.option
+ local options = user.options
+ local path = user.path
+ local info = new()
+
+ local func
+ local group = options
+ local funcname = GetFuncName(option)
+ local handler
+ local confirm
+ local validate
+ --build the info table containing the path
+ -- pick up functions while traversing the tree
+ if group[funcname] ~= nil then
+ func = group[funcname]
+ end
+ handler = group.handler or handler
+ confirm = group.confirm
+ validate = group.validate
+ for i = 1, #path do
+ local v = path[i]
+ group = GetSubOption(group, v)
+ info[i] = v
+ if group[funcname] ~= nil then
+ func = group[funcname]
+ end
+ handler = group.handler or handler
+ if group.confirm ~= nil then
+ confirm = group.confirm
+ end
+ if group.validate ~= nil then
+ validate = group.validate
+ end
+ end
+
+ info.options = options
+ info.appName = user.appName
+ info.arg = option.arg
+ info.handler = handler
+ info.option = option
+ info.type = option.type
+ info.uiType = "dialog"
+ info.uiName = MAJOR
+
+ local name
+ if type(option.name) == "function" then
+ name = option.name(info)
+ elseif type(option.name) == "string" then
+ name = option.name
+ else
+ name = ""
+ end
+ local usage = option.usage
+ local pattern = option.pattern
+
+ local validated = true
+
+ if option.type == "input" then
+ if type(pattern)=="string" then
+ if not strmatch(..., pattern) then
+ validated = false
+ end
+ end
+ end
+
+ local success
+ if validated and option.type ~= "execute" then
+ if type(validate) == "string" then
+ if handler and handler[validate] then
+ success, validated = safecall(handler[validate], handler, info, ...)
+ if not success then validated = false end
+ else
+ error(format("Method %s doesn't exist in handler for type execute", validate))
+ end
+ elseif type(validate) == "function" then
+ success, validated = safecall(validate, info, ...)
+ if not success then validated = false end
+ end
+ end
+
+ local rootframe = user.rootframe
+ if not validated or type(validated) == "string" then
+ if not validated then
+ if usage then
+ validated = name..": "..usage
+ else
+ if pattern then
+ validated = name..": Expected "..pattern
+ else
+ validated = name..": Invalid Value"
+ end
+ end
+ end
+
+ -- show validate message
+ if not group.validatePopup and rootframe.SetStatusText then
+ rootframe:SetStatusText(validated)
+ else
+ validationErrorPopup(validated)
+ end
+ PlaySound("igPlayerInviteDecline")
+ del(info)
+ return true
+ else
+
+ local confirmText = option.confirmText
+ --call confirm func/method
+ if type(confirm) == "string" then
+ if handler and handler[confirm] then
+ success, confirm = safecall(handler[confirm], handler, info, ...)
+ if success and type(confirm) == "string" then
+ confirmText = confirm
+ confirm = true
+ elseif not success then
+ confirm = false
+ end
+ else
+ error(format("Method %s doesn't exist in handler for type confirm", confirm))
+ end
+ elseif type(confirm) == "function" then
+ success, confirm = safecall(confirm, info, ...)
+ if success and type(confirm) == "string" then
+ confirmText = confirm
+ confirm = true
+ elseif not success then
+ confirm = false
+ end
+ end
+
+ --confirm if needed
+ if type(confirm) == "boolean" then
+ if confirm then
+ if not confirmText then
+ local name, desc = option.name, option.desc
+ if type(name) == "function" then
+ name = name(info)
+ end
+ if type(desc) == "function" then
+ desc = desc(info)
+ end
+ confirmText = name
+ if desc then
+ confirmText = confirmText.." - "..desc
+ end
+ end
+
+ local iscustom = user.rootframe:GetUserData("iscustom")
+ local rootframe
+
+ if iscustom then
+ rootframe = user.rootframe
+ end
+ local basepath = user.rootframe:GetUserData("basepath")
+ if type(func) == "string" then
+ if handler and handler[func] then
+ confirmPopup(user.appName, rootframe, basepath, info, confirmText, handler[func], handler, info, ...)
+ else
+ error(format("Method %s doesn't exist in handler for type func", func))
+ end
+ elseif type(func) == "function" then
+ confirmPopup(user.appName, rootframe, basepath, info, confirmText, func, info, ...)
+ end
+ --func will be called and info deleted when the confirm dialog is responded to
+ return
+ end
+ end
+
+ --call the function
+ if type(func) == "string" then
+ if handler and handler[func] then
+ safecall(handler[func],handler, info, ...)
+ else
+ error(format("Method %s doesn't exist in handler for type func", func))
+ end
+ elseif type(func) == "function" then
+ safecall(func,info, ...)
+ end
+
+
+
+ local iscustom = user.rootframe:GetUserData("iscustom")
+ local basepath = user.rootframe:GetUserData("basepath") or emptyTbl
+ --full refresh of the frame, some controls dont cause this on all events
+ if option.type == "color" then
+ if event == "OnValueConfirmed" then
+
+ if iscustom then
+ AceConfigDialog:Open(user.appName, user.rootframe, unpack(basepath))
+ else
+ AceConfigDialog:Open(user.appName, unpack(basepath))
+ end
+ end
+ elseif option.type == "range" then
+ if event == "OnMouseUp" then
+ if iscustom then
+ AceConfigDialog:Open(user.appName, user.rootframe, unpack(basepath))
+ else
+ AceConfigDialog:Open(user.appName, unpack(basepath))
+ end
+ end
+ --multiselects don't cause a refresh on 'OnValueChanged' only 'OnClosed'
+ elseif option.type == "multiselect" then
+ user.valuechanged = true
+ else
+ if iscustom then
+ AceConfigDialog:Open(user.appName, user.rootframe, unpack(basepath))
+ else
+ AceConfigDialog:Open(user.appName, unpack(basepath))
+ end
+ end
+
+ end
+ del(info)
+end
+
+local function ActivateSlider(widget, event, value)
+ local option = widget:GetUserData("option")
+ local min, max, step = option.min or (not option.softMin and 0 or nil), option.max or (not option.softMax and 100 or nil), option.step
+
+ -- checks added by elvui
+ if type(min) == 'function' then min = min() end
+ if type(max) == 'function' then max = max() end
+
+ if min then
+ if step then
+ value = math_floor((value - min) / step + 0.5) * step + min
+ end
+ value = math_max(value, min)
+ end
+ if max then
+ value = math_min(value, max)
+ end
+ ActivateControl(widget,event,value)
+end
+
+--called from a checkbox that is part of an internally created multiselect group
+--this type is safe to refresh on activation of one control
+local function ActivateMultiControl(widget, event, ...)
+ ActivateControl(widget, event, widget:GetUserData("value"), ...)
+ local user = widget:GetUserDataTable()
+ local iscustom = user.rootframe:GetUserData("iscustom")
+ local basepath = user.rootframe:GetUserData("basepath") or emptyTbl
+ if iscustom then
+ AceConfigDialog:Open(user.appName, user.rootframe, unpack(basepath))
+ else
+ AceConfigDialog:Open(user.appName, unpack(basepath))
+ end
+end
+
+local function MultiControlOnClosed(widget, event, ...)
+ local user = widget:GetUserDataTable()
+ if user.valuechanged and not widget:IsReleasing() then
+ local iscustom = user.rootframe:GetUserData("iscustom")
+ local basepath = user.rootframe:GetUserData("basepath") or emptyTbl
+ if iscustom then
+ AceConfigDialog:Open(user.appName, user.rootframe, unpack(basepath))
+ else
+ AceConfigDialog:Open(user.appName, unpack(basepath))
+ end
+ end
+end
+
+local function FrameOnClose(widget, event)
+ local appName = widget:GetUserData("appName")
+ AceConfigDialog.OpenFrames[appName] = nil
+ gui:Release(widget)
+end
+
+local function CheckOptionHidden(option, options, path, appName)
+ --check for a specific boolean option
+ local hidden = pickfirstset(option.dialogHidden,option.guiHidden)
+ if hidden ~= nil then
+ return hidden
+ end
+
+ return GetOptionsMemberValue("hidden", option, options, path, appName)
+end
+
+local function CheckOptionDisabled(option, options, path, appName)
+ --check for a specific boolean option
+ local disabled = pickfirstset(option.dialogDisabled,option.guiDisabled)
+ if disabled ~= nil then
+ return disabled
+ end
+
+ return GetOptionsMemberValue("disabled", option, options, path, appName)
+end
+--[[
+local function BuildTabs(group, options, path, appName)
+ local tabs = new()
+ local text = new()
+ local keySort = new()
+ local opts = new()
+
+ BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
+
+ for i = 1, #keySort do
+ local k = keySort[i]
+ local v = opts[k]
+ if v.type == "group" then
+ path[#path+1] = k
+ local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
+ local hidden = CheckOptionHidden(v, options, path, appName)
+ if not inline and not hidden then
+ tinsert(tabs, k)
+ text[k] = GetOptionsMemberValue("name", v, options, path, appName)
+ end
+ path[#path] = nil
+ end
+ end
+
+ del(keySort)
+ del(opts)
+
+ return tabs, text
+end
+]]
+local function BuildSelect(group, options, path, appName)
+ local groups = new()
+ local order = new()
+ local keySort = new()
+ local opts = new()
+
+ BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
+
+ for i = 1, #keySort do
+ local k = keySort[i]
+ local v = opts[k]
+ if v.type == "group" then
+ path[#path+1] = k
+ local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
+ local hidden = CheckOptionHidden(v, options, path, appName)
+ if not inline and not hidden then
+ groups[k] = GetOptionsMemberValue("name", v, options, path, appName)
+ tinsert(order, k)
+ end
+ path[#path] = nil
+ end
+ end
+
+ del(opts)
+ del(keySort)
+
+ return groups, order
+end
+
+local function BuildSubGroups(group, tree, options, path, appName)
+ local keySort = new()
+ local opts = new()
+
+ BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
+
+ for i = 1, #keySort do
+ local k = keySort[i]
+ local v = opts[k]
+ if v.type == "group" then
+ path[#path+1] = k
+ local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
+ local hidden = CheckOptionHidden(v, options, path, appName)
+ if not inline and not hidden then
+ local entry = new()
+ entry.value = k
+ entry.text = GetOptionsMemberValue("name", v, options, path, appName)
+ entry.icon = GetOptionsMemberValue("icon", v, options, path, appName)
+ entry.iconCoords = GetOptionsMemberValue("iconCoords", v, options, path, appName)
+ entry.disabled = CheckOptionDisabled(v, options, path, appName)
+ if not tree.children then tree.children = new() end
+ tinsert(tree.children,entry)
+ if (v.childGroups or "tree") == "tree" then
+ BuildSubGroups(v,entry, options, path, appName)
+ end
+ end
+ path[#path] = nil
+ end
+ end
+
+ del(keySort)
+ del(opts)
+end
+
+local function BuildGroups(group, options, path, appName, recurse)
+ local tree = new()
+ local keySort = new()
+ local opts = new()
+
+ BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
+
+ for i = 1, #keySort do
+ local k = keySort[i]
+ local v = opts[k]
+ if v.type == "group" then
+ path[#path+1] = k
+ local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
+ local hidden = CheckOptionHidden(v, options, path, appName)
+ if not inline and not hidden then
+ local entry = new()
+ entry.value = k
+ entry.text = GetOptionsMemberValue("name", v, options, path, appName)
+ entry.icon = GetOptionsMemberValue("icon", v, options, path, appName)
+ entry.iconCoords = GetOptionsMemberValue("iconCoords", v, options, path, appName)
+ entry.disabled = CheckOptionDisabled(v, options, path, appName)
+ tinsert(tree,entry)
+ if recurse and (v.childGroups or "tree") == "tree" then
+ BuildSubGroups(v,entry, options, path, appName)
+ end
+ end
+ path[#path] = nil
+ end
+ end
+ del(keySort)
+ del(opts)
+ return tree
+end
+
+local function InjectInfo(control, options, option, path, rootframe, appName)
+ local user = control:GetUserDataTable()
+ for i = 1, #path do
+ user[i] = path[i]
+ end
+ user.rootframe = rootframe
+ user.option = option
+ user.options = options
+ user.path = copy(path)
+ user.appName = appName
+ control:SetCallback("OnRelease", CleanUserData)
+ control:SetCallback("OnLeave", OptionOnMouseLeave)
+ control:SetCallback("OnEnter", OptionOnMouseOver)
+end
+
+local function CreateControl(userControlType, fallbackControlType)
+ local control
+ if userControlType then
+ control = gui:Create(userControlType)
+ if not control then
+ geterrorhandler()(("Invalid Custom Control Type - %s"):format(tostring(userControlType)))
+ end
+ end
+ if not control then
+ control = gui:Create(fallbackControlType)
+ end
+ return control
+end
+
+local function sortTblAsStrings(x,y)
+ return tostring(x) < tostring(y) -- Support numbers as keys
+end
+
+-- added by ElvUI
+local function sortTblByValue(x,y)
+ return x[2] < y[2]
+end
+
+--[[
+ options - root of the options table being fed
+ container - widget that controls will be placed in
+ rootframe - Frame object the options are in
+ path - table with the keys to get to the group being fed
+--]]
+
+local function FeedOptions(appName, options,container,rootframe,path,group,inline)
+ local keySort = new()
+ local opts = new()
+
+ BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
+
+ for i = 1, #keySort do
+ local k = keySort[i]
+ local v = opts[k]
+ tinsert(path, k)
+ local hidden = CheckOptionHidden(v, options, path, appName)
+ local name = GetOptionsMemberValue("name", v, options, path, appName)
+ if not hidden then
+ if v.type == "group" then
+ if inline or pickfirstset(v.dialogInline,v.guiInline,v.inline, false) then
+ --Inline group
+ local GroupContainer
+ if name and name ~= "" then
+ GroupContainer = gui:Create("InlineGroup")
+ GroupContainer:SetTitle(name or "")
+ else
+ GroupContainer = gui:Create("SimpleGroup")
+ end
+
+ GroupContainer.width = "fill"
+ GroupContainer:SetLayout("flow")
+ container:AddChild(GroupContainer)
+ FeedOptions(appName,options,GroupContainer,rootframe,path,v,true)
+ end
+ else
+ --Control to feed
+ local control
+
+ local name = GetOptionsMemberValue("name", v, options, path, appName)
+
+ if v.type == "execute" then
+
+ local imageCoords = GetOptionsMemberValue("imageCoords",v, options, path, appName)
+ local image, width, height = GetOptionsMemberValue("image",v, options, path, appName)
+
+ local iconControl = type(image) == "string" or type(image) == "number"
+ control = CreateControl(v.dialogControl or v.control, iconControl and "Icon" or "Button-ElvUI")
+ if iconControl then
+ if not width then
+ width = GetOptionsMemberValue("imageWidth",v, options, path, appName)
+ end
+ if not height then
+ height = GetOptionsMemberValue("imageHeight",v, options, path, appName)
+ end
+ if type(imageCoords) == "table" then
+ control:SetImage(image, unpack(imageCoords))
+ else
+ control:SetImage(image)
+ end
+ if type(width) ~= "number" then
+ width = 32
+ end
+ if type(height) ~= "number" then
+ height = 32
+ end
+ control:SetImageSize(width, height)
+ control:SetLabel(name)
+ else
+ control:SetText(name)
+ end
+ control:SetCallback("OnClick",ActivateControl)
+
+ elseif v.type == "input" then
+ control = CreateControl(v.dialogControl or v.control, v.multiline and "MultiLineEditBox" or "EditBox")
+
+ if v.multiline and control.SetNumLines then
+ control:SetNumLines(tonumber(v.multiline) or 4)
+ end
+ control:SetLabel(name)
+ control:SetCallback("OnEnterPressed",ActivateControl)
+ local text = GetOptionsMemberValue("get",v, options, path, appName)
+ if type(text) ~= "string" then
+ text = ""
+ end
+ control:SetText(text)
+
+ elseif v.type == "toggle" then
+ control = CreateControl(v.dialogControl or v.control, "CheckBox")
+ control:SetLabel(name)
+ control.textWidth = GetOptionsMemberValue("textWidth",v,options,path,appName)
+ if control.textWidth and control.frame and control.text then
+ local textWidth = control.text:GetWidth()+30
+ control.customWidth = (textWidth>=width_multiplier and textWidth<=width_multiplier*1.5) and textWidth
+ end
+ control:SetTriState(v.tristate)
+ local value = GetOptionsMemberValue("get",v, options, path, appName)
+ control:SetValue(value)
+ control:SetCallback("OnValueChanged",ActivateControl)
+
+ if v.descStyle == "inline" then
+ local desc = GetOptionsMemberValue("desc", v, options, path, appName)
+ control:SetDescription(desc)
+ end
+
+ local image = GetOptionsMemberValue("image", v, options, path, appName)
+ local imageCoords = GetOptionsMemberValue("imageCoords", v, options, path, appName)
+
+ if type(image) == "string" then
+ if type(imageCoords) == "table" then
+ control:SetImage(image, unpack(imageCoords))
+ else
+ control:SetImage(image)
+ end
+ end
+ elseif v.type == "range" then
+ control = CreateControl(v.dialogControl or v.control, "Slider")
+ control:SetLabel(name)
+ control:SetSliderValues(v.softMin or v.min or 0, v.softMax or v.max or 100, v.bigStep or v.step or 0)
+ control:SetIsPercent(v.isPercent)
+ local value = GetOptionsMemberValue("get",v, options, path, appName)
+ if type(value) ~= "number" then
+ value = 0
+ end
+ control:SetValue(value)
+ control:SetCallback("OnValueChanged",ActivateSlider)
+ control:SetCallback("OnMouseUp",ActivateSlider)
+
+ elseif v.type == "select" then
+ local values = GetOptionsMemberValue("values", v, options, path, appName)
+ local sorting = GetOptionsMemberValue("sorting", v, options, path, appName)
+ if v.style == "radio" then
+ local disabled = CheckOptionDisabled(v, options, path, appName)
+ local width = GetOptionsMemberValue("width",v,options,path,appName)
+ control = gui:Create("InlineGroup")
+ control:SetLayout("Flow")
+ control:SetTitle(name)
+ control.width = "fill"
+
+ control:PauseLayout()
+ local optionValue = GetOptionsMemberValue("get",v, options, path, appName)
+ if not sorting then
+ sorting = {}
+ for value, text in pairs(values) do
+ sorting[#sorting+1]=value
+ end
+ tsort(sorting, sortTblAsStrings)
+ end
+ for k, value in ipairs(sorting) do
+ local text = values[value]
+ local radio = gui:Create("CheckBox")
+ radio:SetLabel(text)
+ radio:SetUserData("value", value)
+ radio:SetUserData("text", text)
+ radio:SetDisabled(disabled)
+ radio:SetType("radio")
+ radio:SetValue(optionValue == value)
+ radio:SetCallback("OnValueChanged", ActivateMultiControl)
+ InjectInfo(radio, options, v, path, rootframe, appName)
+ control:AddChild(radio)
+ if width == "double" then
+ radio:SetWidth(width_multiplier * 2)
+ elseif width == "half" then
+ radio:SetWidth(width_multiplier / 2)
+ elseif (type(width) == "number") then
+ radio:SetWidth(width_multiplier * width)
+ elseif width == "full" then
+ radio.width = "fill"
+ else
+ radio:SetWidth(width_multiplier)
+ end
+ end
+ control:ResumeLayout()
+ control:DoLayout()
+ else
+ control = CreateControl(v.dialogControl or v.control, "Dropdown")
+ local sortByValue = GetOptionsMemberValue("sortByValue",v,options,path,appName)
+
+ local itemType = v.itemControl
+ if itemType and not gui:GetWidgetVersion(itemType) then
+ geterrorhandler()(("Invalid Custom Item Type - %s"):format(tostring(itemType)))
+ itemType = nil
+ end
+ control:SetLabel(name)
+ control:SetList(values, sorting, itemType, sortByValue)
+ local value = GetOptionsMemberValue("get",v, options, path, appName)
+ if not values[value] then
+ value = nil
+ end
+ control:SetValue(value)
+ control:SetCallback("OnValueChanged", ActivateControl)
+ end
+
+ elseif v.type == "multiselect" then
+ local values = GetOptionsMemberValue("values", v, options, path, appName)
+ local disabled = CheckOptionDisabled(v, options, path, appName)
+ local sortByValue = GetOptionsMemberValue("sortByValue", v, options, path, appName)
+
+ local valuesort = new()
+ if values then
+ for value, text in pairs(values) do
+ tinsert(valuesort, (sortByValue and {value, text}) or value)
+ end
+ end
+
+ if sortByValue then
+ tsort(valuesort, sortTblByValue)
+ else
+ tsort(valuesort)
+ end
+
+ local controlType = v.dialogControl or v.control
+ if controlType then
+ control = gui:Create(controlType)
+ if not control then
+ geterrorhandler()(("Invalid Custom Control Type - %s"):format(tostring(controlType)))
+ end
+ end
+ if control then
+ control:SetMultiselect(true)
+ control:SetLabel(name)
+ control:SetList(values)
+ control:SetDisabled(disabled)
+ control:SetCallback("OnValueChanged",ActivateControl)
+ control:SetCallback("OnClosed", MultiControlOnClosed)
+ local width = GetOptionsMemberValue("width",v,options,path,appName)
+ if width == "double" then
+ control:SetWidth(width_multiplier * 2)
+ elseif width == "half" then
+ control:SetWidth(width_multiplier / 2)
+ elseif (type(width) == "number") then
+ control:SetWidth(width_multiplier * width)
+ elseif width == "full" then
+ control.width = "fill"
+ else
+ control:SetWidth(width_multiplier)
+ end
+ --check:SetTriState(v.tristate)
+ for i = 1, #valuesort do
+ local key = (sortByValue and valuesort[i][1]) or valuesort[i]
+ local value = GetOptionsMemberValue("get",v, options, path, appName, key)
+ control:SetItemValue(key,value)
+ end
+ else
+ local width = GetOptionsMemberValue("width",v,options,path,appName)
+ local dragdrop = GetOptionsMemberValue("dragdrop",v,options,path,appName)
+
+ control = gui:Create("InlineGroup")
+ control:SetLayout("Flow")
+ control:SetTitle(name)
+ control.width = "fill"
+
+ control:PauseLayout()
+
+ for i = 1, #valuesort do
+ local value = (sortByValue and valuesort[i][1]) or valuesort[i]
+ local text = values[value]
+ if dragdrop then
+ local button = gui:Create("Button-ElvUI")
+ button:SetDisabled(disabled)
+ button:SetUserData("value", value)
+ button:SetUserData("text", text)
+ local state = v.stateSwitchGetText and v.stateSwitchGetText(button, text, value)
+ button:SetText(format("|cFF888888%d|r %s", i, state or text))
+ button.stateSwitchOnClick = v.stateSwitchOnClick
+ button.dragOnMouseDown = v.dragOnMouseDown
+ button.dragOnMouseUp = v.dragOnMouseUp
+ button.dragOnEnter = v.dragOnEnter
+ button.dragOnLeave = v.dragOnLeave
+ button.dragOnClick = v.dragOnClick
+ button.dragdrop = true
+ button.ActivateMultiControl = ActivateMultiControl
+ button.value = GetOptionsMemberValue("get",v, options, path, appName, value)
+ InjectInfo(button, options, v, path, rootframe, appName)
+ control:AddChild(button)
+ if width == "double" then
+ button:SetWidth(width_multiplier * 2)
+ elseif width == "half" then
+ button:SetWidth(width_multiplier / 2)
+ elseif (type(width) == "number") then
+ control:SetWidth(width_multiplier * width)
+ elseif width == "full" then
+ button.width = "fill"
+ else
+ button:SetWidth(width_multiplier)
+ end
+ else
+ local check = gui:Create("CheckBox")
+ check:SetLabel(text)
+ check:SetUserData("value", value)
+ check:SetUserData("text", text)
+ check:SetDisabled(disabled)
+ check:SetTriState(v.tristate)
+ check:SetValue(GetOptionsMemberValue("get",v, options, path, appName, value))
+ check:SetCallback("OnValueChanged",ActivateMultiControl)
+ InjectInfo(check, options, v, path, rootframe, appName)
+ control:AddChild(check)
+ if width == "double" then
+ check:SetWidth(width_multiplier * 2)
+ elseif width == "half" then
+ check:SetWidth(width_multiplier / 2)
+ elseif (type(width) == "number") then
+ control:SetWidth(width_multiplier * width)
+ elseif width == "full" then
+ check.width = "fill"
+ else
+ check:SetWidth(width_multiplier)
+ end
+ end
+ end
+ control:ResumeLayout()
+ control:DoLayout()
+
+
+ end
+
+ del(valuesort)
+
+ elseif v.type == "color" then
+ control = CreateControl(v.dialogControl or v.control, "ColorPicker-ElvUI")
+ control:SetLabel(name)
+ control:SetHasAlpha(GetOptionsMemberValue("hasAlpha",v, options, path, appName))
+ control:SetColor(GetOptionsMemberValue("get",v, options, path, appName))
+ control:SetCallback("OnValueChanged",ActivateControl)
+ control:SetCallback("OnValueConfirmed",ActivateControl)
+
+ elseif v.type == "keybinding" then
+ control = CreateControl(v.dialogControl or v.control, "Keybinding")
+ control:SetLabel(name)
+ control:SetKey(GetOptionsMemberValue("get",v, options, path, appName))
+ control:SetCallback("OnKeyChanged",ActivateControl)
+
+ elseif v.type == "header" then
+ control = CreateControl(v.dialogControl or v.control, "Heading")
+ control:SetText(name)
+ control.width = "fill"
+
+ elseif v.type == "description" then
+ control = CreateControl(v.dialogControl or v.control, "Label")
+ control:SetText(name)
+
+ local fontSize = GetOptionsMemberValue("fontSize",v, options, path, appName)
+ if fontSize == "medium" then
+ control:SetFontObject(GameFontHighlight)
+ elseif fontSize == "large" then
+ control:SetFontObject(GameFontHighlightLarge)
+ else -- small or invalid
+ control:SetFontObject(GameFontHighlightSmall)
+ end
+
+ local imageCoords = GetOptionsMemberValue("imageCoords",v, options, path, appName)
+ local image, width, height = GetOptionsMemberValue("image",v, options, path, appName)
+
+ if type(image) == "string" then
+ if not width then
+ width = GetOptionsMemberValue("imageWidth",v, options, path, appName)
+ end
+ if not height then
+ height = GetOptionsMemberValue("imageHeight",v, options, path, appName)
+ end
+ if type(imageCoords) == "table" then
+ control:SetImage(image, unpack(imageCoords))
+ else
+ control:SetImage(image)
+ end
+ if type(width) ~= "number" then
+ width = 32
+ end
+ if type(height) ~= "number" then
+ height = 32
+ end
+ control:SetImageSize(width, height)
+ end
+ local width = GetOptionsMemberValue("width",v,options,path,appName)
+ control.width = not width and "fill"
+ end
+
+ --Common Init
+ if control then
+ local customWidth = control.customWidth or GetOptionsMemberValue("customWidth",v,options,path,appName)
+ if control.width ~= "fill" or customWidth then
+ if customWidth then
+ control:SetWidth(customWidth)
+ else
+ local width = GetOptionsMemberValue("width",v,options,path,appName)
+ if width == "double" then
+ control:SetWidth(width_multiplier * 2)
+ elseif width == "half" then
+ control:SetWidth(width_multiplier / 2)
+ elseif (type(width) == "number") then
+ control:SetWidth(width_multiplier * width)
+ elseif width == "full" then
+ control.width = "fill"
+ else
+ control:SetWidth(width_multiplier)
+ end
+ end
+ end
+ if control.SetDisabled then
+ local disabled = CheckOptionDisabled(v, options, path, appName)
+ control:SetDisabled(disabled)
+ end
+
+ InjectInfo(control, options, v, path, rootframe, appName)
+ container:AddChild(control)
+ end
+
+ end
+ end
+ tremove(path)
+ end
+ container:ResumeLayout()
+ container:DoLayout()
+ del(keySort)
+ del(opts)
+end
+
+local function BuildPath(path, ...)
+ for i = 1, select("#",...) do
+ tinsert(path, (select(i,...)))
+ end
+end
+
+
+local function TreeOnButtonEnter(widget, event, uniquevalue, button)
+ local user = widget:GetUserDataTable()
+ if not user then return end
+ local options = user.options
+ local option = user.option
+ local path = user.path
+ local appName = user.appName
+
+ local feedpath = new()
+ for i = 1, #path do
+ feedpath[i] = path[i]
+ end
+
+ BuildPath(feedpath, ("\001"):split(uniquevalue))
+ local group = options
+ for i = 1, #feedpath do
+ if not group then return end
+ group = GetSubOption(group, feedpath[i])
+ end
+
+ local name = GetOptionsMemberValue("name", group, options, feedpath, appName)
+ local desc = GetOptionsMemberValue("desc", group, options, feedpath, appName)
+
+ if type(desc) == "string" then
+ GameTooltip:SetOwner(button, "ANCHOR_CURSOR")
+ if widget.type == "TabGroup" then
+ GameTooltip:SetPoint("BOTTOM",button,"TOP")
+ else
+ GameTooltip:SetPoint("LEFT",button,"RIGHT")
+ end
+
+ GameTooltip:SetText(name, 1, .82, 0, 1)
+
+ GameTooltip:AddLine(desc, 1, 1, 1, 1)
+
+ GameTooltip:Show()
+ end
+end
+
+local function TreeOnButtonLeave(widget, event, value, button)
+ GameTooltip:Hide()
+end
+
+
+local function GroupExists(appName, options, path, uniquevalue)
+ if not uniquevalue then return false end
+
+ local feedpath = new()
+ local temppath = new()
+ for i = 1, #path do
+ feedpath[i] = path[i]
+ end
+
+ BuildPath(feedpath, ("\001"):split(uniquevalue))
+
+ local group = options
+ for i = 1, #feedpath do
+ local v = feedpath[i]
+ temppath[i] = v
+ group = GetSubOption(group, v)
+
+ if not group or group.type ~= "group" or CheckOptionHidden(group, options, temppath, appName) then
+ del(feedpath)
+ del(temppath)
+ return false
+ end
+ end
+ del(feedpath)
+ del(temppath)
+ return true
+end
+
+local function GroupSelected(widget, event, uniquevalue)
+
+ local user = widget:GetUserDataTable()
+
+ local options = user.options
+ local option = user.option
+ local path = user.path
+ local rootframe = user.rootframe
+
+ local feedpath = new()
+ for i = 1, #path do
+ feedpath[i] = path[i]
+ end
+
+ BuildPath(feedpath, ("\001"):split(uniquevalue))
+ widget:ReleaseChildren()
+ AceConfigDialog:FeedGroup(user.appName,options,widget,rootframe,feedpath)
+
+ del(feedpath)
+end
+
+
+
+--[[
+-- INTERNAL --
+This function will feed one group, and any inline child groups into the given container
+Select Groups will only have the selection control (tree, tabs, dropdown) fed in
+and have a group selected, this event will trigger the feeding of child groups
+
+Rules:
+ If the group is Inline, FeedOptions
+ If the group has no child groups, FeedOptions
+
+ If the group is a tab or select group, FeedOptions then add the Group Control
+ If the group is a tree group FeedOptions then
+ its parent isnt a tree group: then add the tree control containing this and all child tree groups
+ if its parent is a tree group, its already a node on a tree
+--]]
+
+function AceConfigDialog:FeedGroup(appName,options,container,rootframe,path, isRoot)
+ local group = options
+ --follow the path to get to the curent group
+ local inline
+ local grouptype, parenttype = options.childGroups, "none"
+
+
+ for i = 1, #path do
+ local v = path[i]
+ group = GetSubOption(group, v)
+ inline = inline or pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
+ parenttype = grouptype
+ grouptype = group.childGroups
+ end
+
+ if not parenttype then
+ parenttype = "tree"
+ end
+
+ --check if the group has child groups
+ local hasChildGroups
+ for k, v in pairs(group.args) do
+ if v.type == "group" and not pickfirstset(v.dialogInline,v.guiInline,v.inline, false) and not CheckOptionHidden(v, options, path, appName) then
+ hasChildGroups = true
+ end
+ end
+ if group.plugins then
+ for plugin, t in pairs(group.plugins) do
+ for k, v in pairs(t) do
+ if v.type == "group" and not pickfirstset(v.dialogInline,v.guiInline,v.inline, false) and not CheckOptionHidden(v, options, path, appName) then
+ hasChildGroups = true
+ end
+ end
+ end
+ end
+
+ container:SetLayout("flow")
+ local scroll
+
+ --Add a scrollframe if we are not going to add a group control, this is the inverse of the conditions for that later on
+ if (not (hasChildGroups and not inline)) or (grouptype ~= "tab" and grouptype ~= "select" and (parenttype == "tree" and not isRoot)) then
+ if container.type ~= "InlineGroup" and container.type ~= "SimpleGroup" then
+ scroll = gui:Create("ScrollFrame")
+ scroll:SetLayout("flow")
+ scroll.width = "fill"
+ scroll.height = "fill"
+ container:SetLayout("fill")
+ container:AddChild(scroll)
+ container = scroll
+ end
+ end
+
+ FeedOptions(appName,options,container,rootframe,path,group,nil)
+
+ if scroll then
+ container:PerformLayout()
+ local status = self:GetStatusTable(appName, path)
+ if not status.scroll then
+ status.scroll = {}
+ end
+ scroll:SetStatusTable(status.scroll)
+ end
+
+ if hasChildGroups and not inline then
+ local name = GetOptionsMemberValue("name", group, options, path, appName)
+ if grouptype == "tab" then
+
+ local tab = gui:Create("TabGroup")
+ InjectInfo(tab, options, group, path, rootframe, appName)
+ tab:SetCallback("OnGroupSelected", GroupSelected)
+ tab:SetCallback("OnTabEnter", TreeOnButtonEnter)
+ tab:SetCallback("OnTabLeave", TreeOnButtonLeave)
+
+ local status = AceConfigDialog:GetStatusTable(appName, path)
+ if not status.groups then
+ status.groups = {}
+ end
+ tab:SetStatusTable(status.groups)
+ tab.width = "fill"
+ tab.height = "fill"
+
+ local tabs = BuildGroups(group, options, path, appName)
+ tab:SetTabs(tabs)
+ tab:SetUserData("tablist", tabs)
+
+ for i = 1, #tabs do
+ local entry = tabs[i]
+ if not entry.disabled then
+ tab:SelectTab((GroupExists(appName, options, path,status.groups.selected) and status.groups.selected) or entry.value)
+ break
+ end
+ end
+
+ container:AddChild(tab)
+
+ elseif grouptype == "select" then
+
+ local select = gui:Create("DropdownGroup")
+ select:SetTitle(name)
+ InjectInfo(select, options, group, path, rootframe, appName)
+ select:SetCallback("OnGroupSelected", GroupSelected)
+ local status = AceConfigDialog:GetStatusTable(appName, path)
+ if not status.groups then
+ status.groups = {}
+ end
+ select:SetStatusTable(status.groups)
+ local grouplist, orderlist = BuildSelect(group, options, path, appName)
+ select:SetGroupList(grouplist, orderlist)
+ select:SetUserData("grouplist", grouplist)
+ select:SetUserData("orderlist", orderlist)
+
+ local firstgroup = orderlist[1]
+ if firstgroup then
+ select:SetGroup((GroupExists(appName, options, path,status.groups.selected) and status.groups.selected) or firstgroup)
+ end
+
+ select.width = "fill"
+ select.height = "fill"
+
+ container:AddChild(select)
+
+ --assume tree group by default
+ --if parenttype is tree then this group is already a node on that tree
+ elseif (parenttype ~= "tree") or isRoot then
+ local tree = gui:Create("TreeGroup")
+ InjectInfo(tree, options, group, path, rootframe, appName)
+ tree:EnableButtonTooltips(false)
+
+ tree.width = "fill"
+ tree.height = "fill"
+
+ tree:SetCallback("OnGroupSelected", GroupSelected)
+ tree:SetCallback("OnButtonEnter", TreeOnButtonEnter)
+ tree:SetCallback("OnButtonLeave", TreeOnButtonLeave)
+
+ local status = AceConfigDialog:GetStatusTable(appName, path)
+ if not status.groups then
+ status.groups = {}
+ end
+ local treedefinition = BuildGroups(group, options, path, appName, true)
+ tree:SetStatusTable(status.groups)
+
+ tree:SetTree(treedefinition)
+ tree:SetUserData("tree",treedefinition)
+
+ for i = 1, #treedefinition do
+ local entry = treedefinition[i]
+ if not entry.disabled then
+ tree:SelectByValue((GroupExists(appName, options, path,status.groups.selected) and status.groups.selected) or entry.value)
+ break
+ end
+ end
+
+ container:AddChild(tree)
+ end
+ end
+end
+
+local old_CloseSpecialWindows
+
+
+local function RefreshOnUpdate(this)
+ for appName in pairs(this.closing) do
+ if AceConfigDialog.OpenFrames[appName] then
+ AceConfigDialog.OpenFrames[appName]:Hide()
+ end
+ if AceConfigDialog.BlizOptions and AceConfigDialog.BlizOptions[appName] then
+ for key, widget in pairs(AceConfigDialog.BlizOptions[appName]) do
+ if not widget:IsVisible() then
+ widget:ReleaseChildren()
+ end
+ end
+ end
+ this.closing[appName] = nil
+ end
+
+ if this.closeAll then
+ for k, v in pairs(AceConfigDialog.OpenFrames) do
+ if not this.closeAllOverride[k] then
+ v:Hide()
+ end
+ end
+ this.closeAll = nil
+ wipe(this.closeAllOverride)
+ end
+
+ for appName in pairs(this.apps) do
+ if AceConfigDialog.OpenFrames[appName] then
+ local user = AceConfigDialog.OpenFrames[appName]:GetUserDataTable()
+ AceConfigDialog:Open(appName, unpack(user.basepath or emptyTbl))
+ end
+ if AceConfigDialog.BlizOptions and AceConfigDialog.BlizOptions[appName] then
+ for key, widget in pairs(AceConfigDialog.BlizOptions[appName]) do
+ local user = widget:GetUserDataTable()
+ if widget:IsVisible() then
+ AceConfigDialog:Open(widget:GetUserData("appName"), widget, unpack(user.basepath or emptyTbl))
+ end
+ end
+ end
+ this.apps[appName] = nil
+ end
+ this:SetScript("OnUpdate", nil)
+end
+
+-- Upgrade the OnUpdate script as well, if needed.
+if AceConfigDialog.frame:GetScript("OnUpdate") then
+ AceConfigDialog.frame:SetScript("OnUpdate", RefreshOnUpdate)
+end
+
+--- Close all open options windows
+function AceConfigDialog:CloseAll()
+ AceConfigDialog.frame.closeAll = true
+ AceConfigDialog.frame:SetScript("OnUpdate", RefreshOnUpdate)
+ if next(self.OpenFrames) then
+ return true
+ end
+end
+
+--- Close a specific options window.
+-- @param appName The application name as given to `:RegisterOptionsTable()`
+function AceConfigDialog:Close(appName)
+ if self.OpenFrames[appName] then
+ AceConfigDialog.frame.closing[appName] = true
+ AceConfigDialog.frame:SetScript("OnUpdate", RefreshOnUpdate)
+ return true
+ end
+end
+
+-- Internal -- Called by AceConfigRegistry
+function AceConfigDialog:ConfigTableChanged(event, appName)
+ AceConfigDialog.frame.apps[appName] = true
+ AceConfigDialog.frame:SetScript("OnUpdate", RefreshOnUpdate)
+end
+
+reg.RegisterCallback(AceConfigDialog, "ConfigTableChange", "ConfigTableChanged")
+
+--- Sets the default size of the options window for a specific application.
+-- @param appName The application name as given to `:RegisterOptionsTable()`
+-- @param width The default width
+-- @param height The default height
+function AceConfigDialog:SetDefaultSize(appName, width, height)
+ local status = AceConfigDialog:GetStatusTable(appName)
+ if type(width) == "number" and type(height) == "number" then
+ status.width = width
+ status.height = height
+ end
+end
+
+--- Open an option window at the specified path (if any).
+-- This function can optionally feed the group into a pre-created container
+-- instead of creating a new container frame.
+-- @paramsig appName [, container][, ...]
+-- @param appName The application name as given to `:RegisterOptionsTable()`
+-- @param container An optional container frame to feed the options into
+-- @param ... The path to open after creating the options window (see `:SelectGroup` for details)
+function AceConfigDialog:Open(appName, container, ...)
+ if not old_CloseSpecialWindows then
+ old_CloseSpecialWindows = CloseSpecialWindows
+ CloseSpecialWindows = function()
+ local found = old_CloseSpecialWindows()
+ return self:CloseAll() or found
+ end
+ end
+ local app = reg:GetOptionsTable(appName)
+ if not app then
+ error(("%s isn't registed with AceConfigRegistry, unable to open config"):format(appName), 2)
+ end
+ local options = app("dialog", MAJOR)
+
+ local f
+
+ local path = new()
+ local name = GetOptionsMemberValue("name", options, options, path, appName)
+
+ --If an optional path is specified add it to the path table before feeding the options
+ --as container is optional as well it may contain the first element of the path
+ if type(container) == "string" then
+ tinsert(path, container)
+ container = nil
+ end
+ for n = 1, select("#",...) do
+ tinsert(path, (select(n, ...)))
+ end
+
+ local option = options
+ if type(container) == "table" and container.type == "BlizOptionsGroup" and #path > 0 then
+ for i = 1, #path do
+ option = options.args[path[i]]
+ end
+ name = format("%s - %s", name, GetOptionsMemberValue("name", option, options, path, appName))
+ end
+
+ --if a container is given feed into that
+ if container then
+ f = container
+ f:ReleaseChildren()
+ f:SetUserData("appName", appName)
+ f:SetUserData("iscustom", true)
+ if #path > 0 then
+ f:SetUserData("basepath", copy(path))
+ end
+ local status = AceConfigDialog:GetStatusTable(appName)
+ if not status.width then
+ status.width = 700
+ end
+ if not status.height then
+ status.height = 500
+ end
+ if f.SetStatusTable then
+ f:SetStatusTable(status)
+ end
+ if f.SetTitle then
+ f:SetTitle(name or "")
+ end
+ else
+ if not self.OpenFrames[appName] then
+ f = gui:Create("Frame")
+ self.OpenFrames[appName] = f
+ else
+ f = self.OpenFrames[appName]
+ end
+ f:ReleaseChildren()
+ f:SetCallback("OnClose", FrameOnClose)
+ f:SetUserData("appName", appName)
+ if #path > 0 then
+ f:SetUserData("basepath", copy(path))
+ end
+ f:SetTitle(name or "")
+ local status = AceConfigDialog:GetStatusTable(appName)
+ f:SetStatusTable(status)
+ end
+
+ self:FeedGroup(appName,options,f,f,path,true)
+ if f.Show then
+ f:Show()
+ end
+ del(path)
+
+ if AceConfigDialog.frame.closeAll then
+ -- close all is set, but thats not good, since we're just opening here, so force it
+ AceConfigDialog.frame.closeAllOverride[appName] = true
+ end
+end
+
+-- convert pre-39 BlizOptions structure to the new format
+if oldminor and oldminor < 39 and AceConfigDialog.BlizOptions then
+ local old = AceConfigDialog.BlizOptions
+ local new = {}
+ for key, widget in pairs(old) do
+ local appName = widget:GetUserData("appName")
+ if not new[appName] then new[appName] = {} end
+ new[appName][key] = widget
+ end
+ AceConfigDialog.BlizOptions = new
+else
+ AceConfigDialog.BlizOptions = AceConfigDialog.BlizOptions or {}
+end
+
+local function FeedToBlizPanel(widget, event)
+ local path = widget:GetUserData("path")
+ AceConfigDialog:Open(widget:GetUserData("appName"), widget, unpack(path or emptyTbl))
+end
+
+local function ClearBlizPanel(widget, event)
+ local appName = widget:GetUserData("appName")
+ AceConfigDialog.frame.closing[appName] = true
+ AceConfigDialog.frame:SetScript("OnUpdate", RefreshOnUpdate)
+end
+
+--- Add an option table into the Blizzard Interface Options panel.
+-- You can optionally supply a descriptive name to use and a parent frame to use,
+-- as well as a path in the options table.\\
+-- If no name is specified, the appName will be used instead.
+--
+-- If you specify a proper `parent` (by name), the interface options will generate a
+-- tree layout. Note that only one level of children is supported, so the parent always
+-- has to be a head-level note.
+--
+-- This function returns a reference to the container frame registered with the Interface
+-- Options. You can use this reference to open the options with the API function
+-- `InterfaceOptionsFrame_OpenToCategory`.
+-- @param appName The application name as given to `:RegisterOptionsTable()`
+-- @param name A descriptive name to display in the options tree (defaults to appName)
+-- @param parent The parent to use in the interface options tree.
+-- @param ... The path in the options table to feed into the interface options panel.
+-- @return The reference to the frame registered into the Interface Options.
+function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
+ local BlizOptions = AceConfigDialog.BlizOptions
+
+ local key = appName
+ for n = 1, select("#", ...) do
+ key = key.."\001"..select(n, ...)
+ end
+
+ if not BlizOptions[appName] then
+ BlizOptions[appName] = {}
+ end
+
+ if not BlizOptions[appName][key] then
+ local group = gui:Create("BlizOptionsGroup")
+ BlizOptions[appName][key] = group
+ group:SetName(name or appName, parent)
+
+ group:SetTitle(name or appName)
+ group:SetUserData("appName", appName)
+ if select("#", ...) > 0 then
+ local path = {}
+ for n = 1, select("#",...) do
+ tinsert(path, (select(n, ...)))
+ end
+ group:SetUserData("path", path)
+ end
+ group:SetCallback("OnShow", FeedToBlizPanel)
+ group:SetCallback("OnHide", ClearBlizPanel)
+ InterfaceOptions_AddCategory(group.frame)
+ return group.frame
+ else
+ error(("%s has already been added to the Blizzard Options Window with the given path"):format(appName), 2)
+ end
+end
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml
new file mode 100644
index 0000000..86ce057
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua
new file mode 100644
index 0000000..2ea2220
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua
@@ -0,0 +1,384 @@
+--- AceConfigRegistry-3.0 handles central registration of options tables in use by addons and modules.\\
+-- Options tables can be registered as raw tables, OR as function refs that return a table.\\
+-- Such functions receive three arguments: "uiType", "uiName", "appName". \\
+-- * Valid **uiTypes**: "cmd", "dropdown", "dialog". This is verified by the library at call time. \\
+-- * The **uiName** field is expected to contain the full name of the calling addon, including version, e.g. "FooBar-1.0". This is verified by the library at call time.\\
+-- * The **appName** field is the options table name as given at registration time \\
+--
+-- :IterateOptionsTables() (and :GetOptionsTable() if only given one argument) return a function reference that the requesting config handling addon must call with valid "uiType", "uiName".
+-- @class file
+-- @name AceConfigRegistry-3.0
+-- @release $Id$
+local CallbackHandler = LibStub("CallbackHandler-1.0")
+
+local MAJOR, MINOR = "AceConfigRegistry-3.0-ElvUI", 20
+local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceConfigRegistry then return end
+
+AceConfigRegistry.tables = AceConfigRegistry.tables or {}
+
+if not AceConfigRegistry.callbacks then
+ AceConfigRegistry.callbacks = CallbackHandler:New(AceConfigRegistry)
+end
+
+-- Lua APIs
+local tinsert, tconcat = table.insert, table.concat
+local strfind, strmatch = string.find, string.match
+local type, tostring, select, pairs = type, tostring, select, pairs
+local error, assert = error, assert
+
+-----------------------------------------------------------------------
+-- Validating options table consistency:
+
+
+AceConfigRegistry.validated = {
+ -- list of options table names ran through :ValidateOptionsTable automatically.
+ -- CLEARED ON PURPOSE, since newer versions may have newer validators
+ cmd = {},
+ dropdown = {},
+ dialog = {},
+}
+
+
+
+local function err(msg, errlvl, ...)
+ local t = {}
+ for i=select("#",...),1,-1 do
+ tinsert(t, (select(i, ...)))
+ end
+ error(MAJOR..":ValidateOptionsTable(): "..tconcat(t,".")..msg, errlvl+2)
+end
+
+
+local isstring={["string"]=true, _="string"}
+local isstringfunc={["string"]=true,["function"]=true, _="string or funcref"}
+local istable={["table"]=true, _="table"}
+local ismethodtable={["table"]=true,["string"]=true,["function"]=true, _="methodname, funcref or table"}
+local optstring={["nil"]=true,["string"]=true, _="string"}
+local optstringfunc={["nil"]=true,["string"]=true,["function"]=true, _="string or funcref"}
+local optnumber={["nil"]=true,["number"]=true, _="number"}
+local optnumberfunc={["nil"]=true,["number"]=true,["function"]=true,_="number"} -- added by ElvUI for range
+local optmethodfalse={["nil"]=true,["string"]=true,["function"]=true,["boolean"]={[false]=true}, _="methodname, funcref or false"}
+local optmethodnumber={["nil"]=true,["string"]=true,["function"]=true,["number"]=true, _="methodname, funcref or number"}
+local optmethodtable={["nil"]=true,["string"]=true,["function"]=true,["table"]=true, _="methodname, funcref or table"}
+local optmethodbool={["nil"]=true,["string"]=true,["function"]=true,["boolean"]=true, _="methodname, funcref or boolean"}
+local opttable={["nil"]=true,["table"]=true, _="table"}
+local optbool={["nil"]=true,["boolean"]=true, _="boolean"}
+local optboolnumber={["nil"]=true,["boolean"]=true,["number"]=true, _="boolean or number"}
+local optstringnumber={["nil"]=true,["string"]=true,["number"]=true, _="string or number"}
+
+local basekeys={
+ type=isstring,
+ name=isstringfunc,
+ desc=optstringfunc,
+ descStyle=optstring,
+ order=optmethodnumber,
+ validate=optmethodfalse,
+ validatePopup=optbool, --ElvUI
+ confirm=optmethodbool,
+ confirmText=optstring,
+ disabled=optmethodbool,
+ hidden=optmethodbool,
+ guiHidden=optmethodbool,
+ dialogHidden=optmethodbool,
+ dropdownHidden=optmethodbool,
+ cmdHidden=optmethodbool,
+ icon=optstringfunc,
+ iconCoords=optmethodtable,
+ handler=opttable,
+ get=optmethodfalse,
+ set=optmethodfalse,
+ func=optmethodfalse,
+ arg={["*"]=true},
+ width=optstringnumber,
+ -- below here were created by ElvUI --
+ customWidth=optnumber,
+ textWidth=optmethodbool,
+ sortByValue=optmethodbool,
+ dragdrop=optmethodbool,
+ dragOnEnter=optmethodfalse,
+ dragOnLeave=optmethodfalse,
+ dragOnClick=optmethodfalse,
+ dragOnMouseUp=optmethodfalse,
+ dragOnMouseDown=optmethodfalse,
+ stateSwitchOnClick=optmethodfalse,
+ stateSwitchGetText=optmethodfalse,
+}
+
+local typedkeys={
+ header={
+ control=optstring,
+ dialogControl=optstring,
+ dropdownControl=optstring,
+ },
+ description={
+ image=optstringfunc,
+ imageCoords=optmethodtable,
+ imageHeight=optnumber,
+ imageWidth=optnumber,
+ fontSize=optstringfunc,
+ control=optstring,
+ dialogControl=optstring,
+ dropdownControl=optstring,
+ },
+ group={
+ args=istable,
+ plugins=opttable,
+ inline=optbool,
+ cmdInline=optbool,
+ guiInline=optbool,
+ dropdownInline=optbool,
+ dialogInline=optbool,
+ childGroups=optstring,
+ },
+ execute={
+ image=optstringfunc,
+ imageCoords=optmethodtable,
+ imageHeight=optnumber,
+ imageWidth=optnumber,
+ control=optstring,
+ dialogControl=optstring,
+ dropdownControl=optstring,
+ },
+ input={
+ pattern=optstring,
+ usage=optstring,
+ control=optstring,
+ dialogControl=optstring,
+ dropdownControl=optstring,
+ multiline=optboolnumber,
+ },
+ toggle={
+ tristate=optbool,
+ image=optstringfunc,
+ imageCoords=optmethodtable,
+ control=optstring,
+ dialogControl=optstring,
+ dropdownControl=optstring,
+ },
+ tristate={
+ },
+ range={
+ min=optnumberfunc, --ElvUI
+ softMin=optnumberfunc, --ElvUI
+ max=optnumberfunc, --ElvUI
+ softMax=optnumberfunc, --ElvUI
+ step=optnumber,
+ bigStep=optnumberfunc, --ElvUI
+ isPercent=optbool,
+ control=optstring,
+ dialogControl=optstring,
+ dropdownControl=optstring,
+ },
+ select={
+ values=ismethodtable,
+ sorting=optmethodtable,
+ style={
+ ["nil"]=true,
+ ["string"]={dropdown=true,radio=true},
+ _="string: 'dropdown' or 'radio'"
+ },
+ control=optstring,
+ dialogControl=optstring,
+ dropdownControl=optstring,
+ itemControl=optstring,
+ },
+ multiselect={
+ values=ismethodtable,
+ style=optstring,
+ tristate=optbool,
+ control=optstring,
+ dialogControl=optstring,
+ dropdownControl=optstring,
+ },
+ color={
+ hasAlpha=optmethodbool,
+ control=optstring,
+ dialogControl=optstring,
+ dropdownControl=optstring,
+ },
+ keybinding={
+ control=optstring,
+ dialogControl=optstring,
+ dropdownControl=optstring,
+ },
+}
+
+local function validateKey(k,errlvl,...)
+ errlvl=(errlvl or 0)+1
+ if type(k)~="string" then
+ err("["..tostring(k).."] - key is not a string", errlvl,...)
+ end
+ if strfind(k, "[%c\127]") then
+ err("["..tostring(k).."] - key name contained control characters", errlvl,...)
+ end
+end
+
+local function validateVal(v, oktypes, errlvl,...)
+ errlvl=(errlvl or 0)+1
+ local isok=oktypes[type(v)] or oktypes["*"]
+
+ if not isok then
+ err(": expected a "..oktypes._..", got '"..tostring(v).."'", errlvl,...)
+ end
+ if type(isok)=="table" then -- isok was a table containing specific values to be tested for!
+ if not isok[v] then
+ err(": did not expect "..type(v).." value '"..tostring(v).."'", errlvl,...)
+ end
+ end
+end
+
+local function validate(options,errlvl,...)
+ errlvl=(errlvl or 0)+1
+ -- basic consistency
+ if type(options)~="table" then
+ err(": expected a table, got a "..type(options), errlvl,...)
+ end
+ if type(options.type)~="string" then
+ err(".type: expected a string, got a "..type(options.type), errlvl,...)
+ end
+
+ -- get type and 'typedkeys' member
+ local tk = typedkeys[options.type]
+ if not tk then
+ err(".type: unknown type '"..options.type.."'", errlvl,...)
+ end
+
+ -- make sure that all options[] are known parameters
+ for k,v in pairs(options) do
+ if not (tk[k] or basekeys[k]) then
+ err(": unknown parameter", errlvl,tostring(k),...)
+ end
+ end
+
+ -- verify that required params are there, and that everything is the right type
+ for k,oktypes in pairs(basekeys) do
+ validateVal(options[k], oktypes, errlvl,k,...)
+ end
+ for k,oktypes in pairs(tk) do
+ validateVal(options[k], oktypes, errlvl,k,...)
+ end
+
+ -- extra logic for groups
+ if options.type=="group" then
+ for k,v in pairs(options.args) do
+ validateKey(k,errlvl,"args",...)
+ validate(v, errlvl,k,"args",...)
+ end
+ if options.plugins then
+ for plugname,plugin in pairs(options.plugins) do
+ if type(plugin)~="table" then
+ err(": expected a table, got '"..tostring(plugin).."'", errlvl,tostring(plugname),"plugins",...)
+ end
+ for k,v in pairs(plugin) do
+ validateKey(k,errlvl,tostring(plugname),"plugins",...)
+ validate(v, errlvl,k,tostring(plugname),"plugins",...)
+ end
+ end
+ end
+ end
+end
+
+
+--- Validates basic structure and integrity of an options table \\
+-- Does NOT verify that get/set etc actually exist, since they can be defined at any depth
+-- @param options The table to be validated
+-- @param name The name of the table to be validated (shown in any error message)
+-- @param errlvl (optional number) error level offset, default 0 (=errors point to the function calling :ValidateOptionsTable)
+function AceConfigRegistry:ValidateOptionsTable(options,name,errlvl)
+ errlvl=(errlvl or 0)+1
+ name = name or "Optionstable"
+ if not options.name then
+ options.name=name -- bit of a hack, the root level doesn't really need a .name :-/
+ end
+ validate(options,errlvl,name)
+end
+
+--- Fires a "ConfigTableChange" callback for those listening in on it, allowing config GUIs to refresh.
+-- You should call this function if your options table changed from any outside event, like a game event
+-- or a timer.
+-- @param appName The application name as given to `:RegisterOptionsTable()`
+function AceConfigRegistry:NotifyChange(appName)
+ if not AceConfigRegistry.tables[appName] then return end
+ AceConfigRegistry.callbacks:Fire("ConfigTableChange", appName)
+end
+
+-- -------------------------------------------------------------------
+-- Registering and retreiving options tables:
+
+
+-- validateGetterArgs: helper function for :GetOptionsTable (or, rather, the getter functions returned by it)
+
+local function validateGetterArgs(uiType, uiName, errlvl)
+ errlvl=(errlvl or 0)+2
+ if uiType~="cmd" and uiType~="dropdown" and uiType~="dialog" then
+ error(MAJOR..": Requesting options table: 'uiType' - invalid configuration UI type, expected 'cmd', 'dropdown' or 'dialog'", errlvl)
+ end
+ if not strmatch(uiName, "[A-Za-z]%-[0-9]") then -- Expecting e.g. "MyLib-1.2"
+ error(MAJOR..": Requesting options table: 'uiName' - badly formatted or missing version number. Expected e.g. 'MyLib-1.2'", errlvl)
+ end
+end
+
+--- Register an options table with the config registry.
+-- @param appName The application name as given to `:RegisterOptionsTable()`
+-- @param options The options table, OR a function reference that generates it on demand. \\
+-- See the top of the page for info on arguments passed to such functions.
+-- @param skipValidation Skip options table validation (primarily useful for extremely huge options, with a noticeable slowdown)
+function AceConfigRegistry:RegisterOptionsTable(appName, options, skipValidation)
+ if type(options)=="table" then
+ if options.type~="group" then -- quick sanity checker
+ error(MAJOR..": RegisterOptionsTable(appName, options): 'options' - missing type='group' member in root group", 2)
+ end
+ AceConfigRegistry.tables[appName] = function(uiType, uiName, errlvl)
+ errlvl=(errlvl or 0)+1
+ validateGetterArgs(uiType, uiName, errlvl)
+ if not AceConfigRegistry.validated[uiType][appName] and not skipValidation then
+ AceConfigRegistry:ValidateOptionsTable(options, appName, errlvl) -- upgradable
+ AceConfigRegistry.validated[uiType][appName] = true
+ end
+ return options
+ end
+ elseif type(options)=="function" then
+ AceConfigRegistry.tables[appName] = function(uiType, uiName, errlvl)
+ errlvl=(errlvl or 0)+1
+ validateGetterArgs(uiType, uiName, errlvl)
+ local tab = assert(options(uiType, uiName, appName))
+ if not AceConfigRegistry.validated[uiType][appName] and not skipValidation then
+ AceConfigRegistry:ValidateOptionsTable(tab, appName, errlvl) -- upgradable
+ AceConfigRegistry.validated[uiType][appName] = true
+ end
+ return tab
+ end
+ else
+ error(MAJOR..": RegisterOptionsTable(appName, options): 'options' - expected table or function reference", 2)
+ end
+end
+
+--- Returns an iterator of ["appName"]=funcref pairs
+function AceConfigRegistry:IterateOptionsTables()
+ return pairs(AceConfigRegistry.tables)
+end
+
+
+
+
+--- Query the registry for a specific options table.
+-- If only appName is given, a function is returned which you
+-- can call with (uiType,uiName) to get the table.\\
+-- If uiType&uiName are given, the table is returned.
+-- @param appName The application name as given to `:RegisterOptionsTable()`
+-- @param uiType The type of UI to get the table for, one of "cmd", "dropdown", "dialog"
+-- @param uiName The name of the library/addon querying for the table, e.g. "MyLib-1.0"
+function AceConfigRegistry:GetOptionsTable(appName, uiType, uiName)
+ local f = AceConfigRegistry.tables[appName]
+ if not f then
+ return nil
+ end
+
+ if uiType then
+ return f(uiType,uiName,1) -- get the table for us
+ else
+ return f -- return the function
+ end
+end
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml
new file mode 100644
index 0000000..101bfda
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceDBOptions-3.0/AceDBOptions-3.0.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceDBOptions-3.0/AceDBOptions-3.0.lua
new file mode 100644
index 0000000..3c23951
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceDBOptions-3.0/AceDBOptions-3.0.lua
@@ -0,0 +1,460 @@
+--- AceDBOptions-3.0 provides a universal AceConfig options screen for managing AceDB-3.0 profiles.
+-- @class file
+-- @name AceDBOptions-3.0
+-- @release $Id$
+local ACEDBO_MAJOR, ACEDBO_MINOR = "AceDBOptions-3.0", 15
+local AceDBOptions = LibStub:NewLibrary(ACEDBO_MAJOR, ACEDBO_MINOR)
+
+if not AceDBOptions then return end -- No upgrade needed
+
+-- Lua APIs
+local pairs, next = pairs, next
+
+-- WoW APIs
+local UnitClass = UnitClass
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: NORMAL_FONT_COLOR_CODE, FONT_COLOR_CODE_CLOSE
+
+AceDBOptions.optionTables = AceDBOptions.optionTables or {}
+AceDBOptions.handlers = AceDBOptions.handlers or {}
+
+--[[
+ Localization of AceDBOptions-3.0
+]]
+
+local L = {
+ choose = "Existing Profiles",
+ choose_desc = "You can either create a new profile by entering a name in the editbox, or choose one of the already existing profiles.",
+ choose_sub = "Select one of your currently available profiles.",
+ copy = "Copy From",
+ copy_desc = "Copy the settings from one existing profile into the currently active profile.",
+ current = "Current Profile:",
+ default = "Default",
+ delete = "Delete a Profile",
+ delete_confirm = "Are you sure you want to delete the selected profile?",
+ delete_desc = "Delete existing and unused profiles from the database to save space, and cleanup the SavedVariables file.",
+ delete_sub = "Deletes a profile from the database.",
+ intro = "You can change the active database profile, so you can have different settings for every character.",
+ new = "New",
+ new_sub = "Create a new empty profile.",
+ profiles = "Profiles",
+ profiles_sub = "Manage Profiles",
+ reset = "Reset Profile",
+ reset_desc = "Reset the current profile back to its default values, in case your configuration is broken, or you simply want to start over.",
+ reset_sub = "Reset the current profile to the default",
+}
+
+local LOCALE = GetLocale()
+if LOCALE == "deDE" then
+ L["choose"] = "Vorhandene Profile"
+ L["choose_desc"] = "Du kannst ein neues Profil erstellen, indem du einen neuen Namen in der Eingabebox 'Neu' eingibst, oder wähle eines der vorhandenen Profile aus."
+ L["choose_sub"] = "Wählt ein bereits vorhandenes Profil aus."
+ L["copy"] = "Kopieren von..."
+ L["copy_desc"] = "Kopiere die Einstellungen von einem vorhandenen Profil in das aktive Profil."
+ L["current"] = "Aktuelles Profil:"
+ L["default"] = "Standard"
+ L["delete"] = "Profil löschen"
+ L["delete_confirm"] = "Willst du das ausgewählte Profil wirklich löschen?"
+ L["delete_desc"] = "Lösche vorhandene oder unbenutzte Profile aus der Datenbank, um Platz zu sparen und die SavedVariables-Datei 'sauber' zu halten."
+ L["delete_sub"] = "Löscht ein Profil aus der Datenbank."
+ L["intro"] = "Hier kannst du das aktive Datenbankprofil ändern, damit du verschiedene Einstellungen für jeden Charakter erstellen kannst, wodurch eine sehr flexible Konfiguration möglich wird."
+ L["new"] = "Neu"
+ L["new_sub"] = "Ein neues Profil erstellen."
+ L["profiles"] = "Profile"
+ L["profiles_sub"] = "Profile verwalten"
+ L["reset"] = "Profil zurücksetzen"
+ L["reset_desc"] = "Setzt das momentane Profil auf Standardwerte zurück, für den Fall, dass mit der Konfiguration etwas schief lief oder weil du einfach neu starten willst."
+ L["reset_sub"] = "Das aktuelle Profil auf Standard zurücksetzen."
+elseif LOCALE == "frFR" then
+ L["choose"] = "Profils existants"
+ L["choose_desc"] = "Vous pouvez créer un nouveau profil en entrant un nouveau nom dans la boîte de saisie, ou en choississant un des profils déjà existants."
+ L["choose_sub"] = "Permet de choisir un des profils déjà disponibles."
+ L["copy"] = "Copier à partir de"
+ L["copy_desc"] = "Copie les paramètres d'un profil déjà existant dans le profil actuellement actif."
+ L["current"] = "Profil actuel :"
+ L["default"] = "Défaut"
+ L["delete"] = "Supprimer un profil"
+ L["delete_confirm"] = "Etes-vous sûr de vouloir supprimer le profil sélectionné ?"
+ L["delete_desc"] = "Supprime les profils existants inutilisés de la base de données afin de gagner de la place et de nettoyer le fichier SavedVariables."
+ L["delete_sub"] = "Supprime un profil de la base de données."
+ L["intro"] = "Vous pouvez changer le profil actuel afin d'avoir des paramètres différents pour chaque personnage, permettant ainsi d'avoir une configuration très flexible."
+ L["new"] = "Nouveau"
+ L["new_sub"] = "Créée un nouveau profil vierge."
+ L["profiles"] = "Profils"
+ L["profiles_sub"] = "Gestion des profils"
+ L["reset"] = "Réinitialiser le profil"
+ L["reset_desc"] = "Réinitialise le profil actuel au cas où votre configuration est corrompue ou si vous voulez tout simplement faire table rase."
+ L["reset_sub"] = "Réinitialise le profil actuel avec les paramètres par défaut."
+elseif LOCALE == "koKR" then
+ L["choose"] = "저장 중인 프로필"
+ L["choose_desc"] = "입력창에 새로운 이름을 입력하거나 저장 중인 프로필 중 하나를 선택하여 새로운 프로필을 만들 수 있습니다."
+ L["choose_sub"] = "현재 이용할 수 있는 프로필 중 하나를 선택합니다."
+ L["copy"] = "복사해오기"
+ L["copy_desc"] = "현재 사용 중인 프로필에 선택한 프로필의 설정을 복사합니다."
+ L["current"] = "현재 프로필:"
+ L["default"] = "기본값"
+ L["delete"] = "프로필 삭제"
+ L["delete_confirm"] = "정말로 선택한 프로필을 삭제할까요?"
+ L["delete_desc"] = "저장 공간 절약과 SavedVariables 파일의 정리를 위해 데이터베이스에서 사용하지 않는 프로필을 삭제하세요."
+ L["delete_sub"] = "데이터베이스의 프로필을 삭제합니다."
+ L["intro"] = "활성 데이터베이스 프로필을 변경할 수 있고, 각 캐릭터 별로 다른 설정을 할 수 있습니다."
+ L["new"] = "새로운 프로필"
+ L["new_sub"] = "새로운 프로필을 만듭니다."
+ L["profiles"] = "프로필"
+ L["profiles_sub"] = "프로필 관리"
+ L["reset"] = "프로필 초기화"
+ L["reset_desc"] = "설정이 깨졌거나 처음부터 다시 설정을 원하는 경우, 현재 프로필을 기본값으로 초기화하세요."
+ L["reset_sub"] = "현재 프로필을 기본값으로 초기화합니다"
+elseif LOCALE == "esES" or LOCALE == "esMX" then
+ L["choose"] = "Perfiles existentes"
+ L["choose_desc"] = "Puedes crear un nuevo perfil introduciendo un nombre en el recuadro o puedes seleccionar un perfil de los ya existentes."
+ L["choose_sub"] = "Selecciona uno de los perfiles disponibles."
+ L["copy"] = "Copiar de"
+ L["copy_desc"] = "Copia los ajustes de un perfil existente al perfil actual."
+ L["current"] = "Perfil actual:"
+ L["default"] = "Por defecto"
+ L["delete"] = "Borrar un Perfil"
+ L["delete_confirm"] = "¿Estas seguro que quieres borrar el perfil seleccionado?"
+ L["delete_desc"] = "Borra los perfiles existentes y sin uso de la base de datos para ganar espacio y limpiar el archivo SavedVariables."
+ L["delete_sub"] = "Borra un perfil de la base de datos."
+ L["intro"] = "Puedes cambiar el perfil activo de tal manera que cada personaje tenga diferentes configuraciones."
+ L["new"] = "Nuevo"
+ L["new_sub"] = "Crear un nuevo perfil vacio."
+ L["profiles"] = "Perfiles"
+ L["profiles_sub"] = "Manejar Perfiles"
+ L["reset"] = "Reiniciar Perfil"
+ L["reset_desc"] = "Reinicia el perfil actual a los valores por defectos, en caso de que se haya estropeado la configuración o quieras volver a empezar de nuevo."
+ L["reset_sub"] = "Reinicar el perfil actual al de por defecto"
+elseif LOCALE == "zhTW" then
+ L["choose"] = "現有的設定檔"
+ L["choose_desc"] = "您可以在文字方塊內輸入名字以建立新的設定檔,或是選擇一個現有的設定檔使用。"
+ L["choose_sub"] = "從當前可用的設定檔裡面選擇一個。"
+ L["copy"] = "複製自"
+ L["copy_desc"] = "從一個現有的設定檔,將設定複製到現在使用中的設定檔。"
+ L["current"] = "目前設定檔:"
+ L["default"] = "預設"
+ L["delete"] = "刪除一個設定檔"
+ L["delete_confirm"] = "確定要刪除所選擇的設定檔嗎?"
+ L["delete_desc"] = "從資料庫裡刪除不再使用的設定檔,以節省空間,並且清理 SavedVariables 檔案。"
+ L["delete_sub"] = "從資料庫裡刪除一個設定檔。"
+ L["intro"] = "您可以從資料庫中選擇一個設定檔來使用,如此就可以讓每個角色使用不同的設定。"
+ L["new"] = "新建"
+ L["new_sub"] = "新建一個空的設定檔。"
+ L["profiles"] = "設定檔"
+ L["profiles_sub"] = "管理設定檔"
+ L["reset"] = "重置設定檔"
+ L["reset_desc"] = "將現用的設定檔重置為預設值;用於設定檔損壞,或者單純想要重來的情況。"
+ L["reset_sub"] = "將目前的設定檔重置為預設值"
+elseif LOCALE == "zhCN" then
+ L["choose"] = "现有的配置文件"
+ L["choose_desc"] = "你可以通过在文本框内输入一个名字创立一个新的配置文件,也可以选择一个已经存在的配置文件。"
+ L["choose_sub"] = "从当前可用的配置文件里面选择一个。"
+ L["copy"] = "复制自"
+ L["copy_desc"] = "从当前某个已保存的配置文件复制到当前正使用的配置文件。"
+ L["current"] = "当前配置文件:"
+ L["default"] = "默认"
+ L["delete"] = "删除一个配置文件"
+ L["delete_confirm"] = "你确定要删除所选择的配置文件么?"
+ L["delete_desc"] = "从数据库里删除不再使用的配置文件,以节省空间,并且清理SavedVariables文件。"
+ L["delete_sub"] = "从数据库里删除一个配置文件。"
+ L["intro"] = "你可以选择一个活动的数据配置文件,这样你的每个角色就可以拥有不同的设置值,可以给你的插件配置带来极大的灵活性。"
+ L["new"] = "新建"
+ L["new_sub"] = "新建一个空的配置文件。"
+ L["profiles"] = "配置文件"
+ L["profiles_sub"] = "管理配置文件"
+ L["reset"] = "重置配置文件"
+ L["reset_desc"] = "将当前的配置文件恢复到它的默认值,用于你的配置文件损坏,或者你只是想重来的情况。"
+ L["reset_sub"] = "将当前的配置文件恢复为默认值"
+elseif LOCALE == "ruRU" then
+ L["choose"] = "Существующие профили"
+ L["choose_desc"] = "Вы можете создать новый профиль, введя название в поле ввода, или выбрать один из уже существующих профилей."
+ L["choose_sub"] = "Выбор одиного из уже доступных профилей"
+ L["copy"] = "Скопировать из"
+ L["copy_desc"] = "Скопировать настройки из выбранного профиля в активный."
+ L["current"] = "Текущий профиль:"
+ L["default"] = "По умолчанию"
+ L["delete"] = "Удалить профиль"
+ L["delete_confirm"] = "Вы уверены, что вы хотите удалить выбранный профиль?"
+ L["delete_desc"] = "Удалить существующий и неиспользуемый профиль из БД для сохранения места, и очистить SavedVariables файл."
+ L["delete_sub"] = "Удаление профиля из БД"
+ L["intro"] = "Изменяя активный профиль, вы можете задать различные настройки модификаций для каждого персонажа."
+ L["new"] = "Новый"
+ L["new_sub"] = "Создать новый чистый профиль"
+ L["profiles"] = "Профили"
+ L["profiles_sub"] = "Управление профилями"
+ L["reset"] = "Сброс профиля"
+ L["reset_desc"] = "Сбросить текущий профиль к стандартным настройкам, если ваша конфигурация испорчена или вы хотите настроить всё заново."
+ L["reset_sub"] = "Сброс текущего профиля на стандартный"
+elseif LOCALE == "itIT" then
+ L["choose"] = "Profili Esistenti"
+ L["choose_desc"] = "Puoi creare un nuovo profilo digitando il nome della casella di testo, oppure scegliendone uno tra i profili già esistenti."
+ L["choose_sub"] = "Seleziona uno dei profili attualmente disponibili."
+ L["copy"] = "Copia Da"
+ L["copy_desc"] = "Copia le impostazioni da un profilo esistente, nel profilo attivo in questo momento."
+ L["current"] = "Profilo Attivo:"
+ L["default"] = "Standard"
+ L["delete"] = "Cancella un Profilo"
+ L["delete_confirm"] = "Sei sicuro di voler cancellare il profilo selezionato?"
+ L["delete_desc"] = "Cancella i profili non utilizzati dal database per risparmiare spazio e mantenere puliti i file di configurazione SavedVariables."
+ L["delete_sub"] = "Cancella un profilo dal Database."
+ L["intro"] = "Puoi cambiare il profilo attivo, in modo da usare impostazioni diverse per ogni personaggio."
+ L["new"] = "Nuovo"
+ L["new_sub"] = "Crea un nuovo profilo vuoto."
+ L["profiles"] = "Profili"
+ L["profiles_sub"] = "Gestisci Profili"
+ L["reset"] = "Reimposta Profilo"
+ L["reset_desc"] = "Riporta il tuo profilo attivo alle sue impostazioni predefinite, nel caso in cui la tua configurazione si sia corrotta, o semplicemente tu voglia re-inizializzarla."
+ L["reset_sub"] = "Reimposta il profilo ai suoi valori predefiniti."
+elseif LOCALE == "ptBR" then
+ L["choose"] = "Perfis Existentes"
+ L["choose_desc"] = "Você pode tanto criar um perfil novo tanto digitando um nome na caixa de texto, quanto escolher um dos perfis já existentes."
+ L["choose_sub"] = "Selecione um de seus perfis atualmente disponíveis."
+ L["copy"] = "Copiar De"
+ L["copy_desc"] = "Copia as definições de um perfil existente no perfil atualmente ativo."
+ L["current"] = "Perfil Autal:"
+ L["default"] = "Padrão"
+ L["delete"] = "Remover um Perfil"
+ L["delete_confirm"] = "Tem certeza que deseja remover o perfil selecionado?"
+ L["delete_desc"] = "Remove perfis existentes e inutilizados do banco de dados para economizar espaço, e limpar o arquivo SavedVariables."
+ L["delete_sub"] = "Remove um perfil do banco de dados."
+ L["intro"] = "Você pode alterar o perfil do banco de dados ativo, para que possa ter definições diferentes para cada personagem."
+ L["new"] = "Novo"
+ L["new_sub"] = "Cria um novo perfil vazio."
+ L["profiles"] = "Perfis"
+ L["profiles_sub"] = "Gerenciar Perfis"
+ L["reset"] = "Resetar Perfil"
+ L["reset_desc"] = "Reseta o perfil atual para os valores padrões, no caso de sua configuração estar quebrada, ou simplesmente se deseja começar novamente."
+ L["reset_sub"] = "Resetar o perfil atual ao padrão"
+end
+
+local defaultProfiles
+local tmpprofiles = {}
+
+-- Get a list of available profiles for the specified database.
+-- You can specify which profiles to include/exclude in the list using the two boolean parameters listed below.
+-- @param db The db object to retrieve the profiles from
+-- @param common If true, getProfileList will add the default profiles to the return list, even if they have not been created yet
+-- @param nocurrent If true, then getProfileList will not display the current profile in the list
+-- @return Hashtable of all profiles with the internal name as keys and the display name as value.
+local function getProfileList(db, common, nocurrent)
+ local profiles = {}
+
+ -- copy existing profiles into the table
+ local currentProfile = db:GetCurrentProfile()
+ for i,v in pairs(db:GetProfiles(tmpprofiles)) do
+ if not (nocurrent and v == currentProfile) then
+ profiles[v] = v
+ end
+ end
+
+ -- add our default profiles to choose from ( or rename existing profiles)
+ for k,v in pairs(defaultProfiles) do
+ if (common or profiles[k]) and not (nocurrent and k == currentProfile) then
+ profiles[k] = v
+ end
+ end
+
+ return profiles
+end
+
+--[[
+ OptionsHandlerPrototype
+ prototype class for handling the options in a sane way
+]]
+local OptionsHandlerPrototype = {}
+
+--[[ Reset the profile ]]
+function OptionsHandlerPrototype:Reset()
+ self.db:ResetProfile()
+end
+
+--[[ Set the profile to value ]]
+function OptionsHandlerPrototype:SetProfile(info, value)
+ self.db:SetProfile(value)
+end
+
+--[[ returns the currently active profile ]]
+function OptionsHandlerPrototype:GetCurrentProfile()
+ return self.db:GetCurrentProfile()
+end
+
+--[[
+ List all active profiles
+ you can control the output with the .arg variable
+ currently four modes are supported
+
+ (empty) - return all available profiles
+ "nocurrent" - returns all available profiles except the currently active profile
+ "common" - returns all avaialble profiles + some commonly used profiles ("char - realm", "realm", "class", "Default")
+ "both" - common except the active profile
+]]
+function OptionsHandlerPrototype:ListProfiles(info)
+ local arg = info.arg
+ local profiles
+ if arg == "common" and not self.noDefaultProfiles then
+ profiles = getProfileList(self.db, true, nil)
+ elseif arg == "nocurrent" then
+ profiles = getProfileList(self.db, nil, true)
+ elseif arg == "both" then -- currently not used
+ profiles = getProfileList(self.db, (not self.noDefaultProfiles) and true, true)
+ else
+ profiles = getProfileList(self.db)
+ end
+
+ return profiles
+end
+
+function OptionsHandlerPrototype:HasNoProfiles(info)
+ local profiles = self:ListProfiles(info)
+ return ((not next(profiles)) and true or false)
+end
+
+--[[ Copy a profile ]]
+function OptionsHandlerPrototype:CopyProfile(info, value)
+ self.db:CopyProfile(value)
+end
+
+--[[ Delete a profile from the db ]]
+function OptionsHandlerPrototype:DeleteProfile(info, value)
+ self.db:DeleteProfile(value)
+end
+
+--[[ fill defaultProfiles with some generic values ]]
+local function generateDefaultProfiles(db)
+ defaultProfiles = {
+ ["Default"] = L["default"],
+ [db.keys.char] = db.keys.char,
+ [db.keys.realm] = db.keys.realm,
+ [db.keys.class] = UnitClass("player")
+ }
+end
+
+--[[ create and return a handler object for the db, or upgrade it if it already existed ]]
+local function getOptionsHandler(db, noDefaultProfiles)
+ if not defaultProfiles then
+ generateDefaultProfiles(db)
+ end
+
+ local handler = AceDBOptions.handlers[db] or { db = db, noDefaultProfiles = noDefaultProfiles }
+
+ for k,v in pairs(OptionsHandlerPrototype) do
+ handler[k] = v
+ end
+
+ AceDBOptions.handlers[db] = handler
+ return handler
+end
+
+--[[
+ the real options table
+]]
+local optionsTable = {
+ desc = {
+ order = 1,
+ type = "description",
+ name = L["intro"] .. "\n",
+ },
+ descreset = {
+ order = 9,
+ type = "description",
+ name = L["reset_desc"],
+ },
+ reset = {
+ order = 10,
+ type = "execute",
+ name = L["reset"],
+ desc = L["reset_sub"],
+ func = "Reset",
+ },
+ current = {
+ order = 11,
+ type = "description",
+ name = function(info) return L["current"] .. " " .. NORMAL_FONT_COLOR_CODE .. info.handler:GetCurrentProfile() .. FONT_COLOR_CODE_CLOSE end,
+ width = "default",
+ },
+ choosedesc = {
+ order = 20,
+ type = "description",
+ name = "\n" .. L["choose_desc"],
+ },
+ new = {
+ name = L["new"],
+ desc = L["new_sub"],
+ type = "input",
+ order = 30,
+ get = false,
+ set = "SetProfile",
+ },
+ choose = {
+ name = L["choose"],
+ desc = L["choose_sub"],
+ type = "select",
+ order = 40,
+ get = "GetCurrentProfile",
+ set = "SetProfile",
+ values = "ListProfiles",
+ arg = "common",
+ },
+ copydesc = {
+ order = 50,
+ type = "description",
+ name = "\n" .. L["copy_desc"],
+ },
+ copyfrom = {
+ order = 60,
+ type = "select",
+ name = L["copy"],
+ desc = L["copy_desc"],
+ get = false,
+ set = "CopyProfile",
+ values = "ListProfiles",
+ disabled = "HasNoProfiles",
+ arg = "nocurrent",
+ },
+ deldesc = {
+ order = 70,
+ type = "description",
+ name = "\n" .. L["delete_desc"],
+ },
+ delete = {
+ order = 80,
+ type = "select",
+ name = L["delete"],
+ desc = L["delete_sub"],
+ get = false,
+ set = "DeleteProfile",
+ values = "ListProfiles",
+ disabled = "HasNoProfiles",
+ arg = "nocurrent",
+ confirm = true,
+ confirmText = L["delete_confirm"],
+ },
+}
+
+--- Get/Create a option table that you can use in your addon to control the profiles of AceDB-3.0.
+-- @param db The database object to create the options table for.
+-- @return The options table to be used in AceConfig-3.0
+-- @usage
+-- -- Assuming `options` is your top-level options table and `self.db` is your database:
+-- options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
+function AceDBOptions:GetOptionsTable(db, noDefaultProfiles)
+ local tbl = AceDBOptions.optionTables[db] or {
+ type = "group",
+ name = L["profiles"],
+ desc = L["profiles_sub"],
+ }
+
+ tbl.handler = getOptionsHandler(db, noDefaultProfiles)
+ tbl.args = optionsTable
+
+ AceDBOptions.optionTables[db] = tbl
+ return tbl
+end
+
+-- upgrade existing tables
+for db,tbl in pairs(AceDBOptions.optionTables) do
+ tbl.handler = getOptionsHandler(db)
+ tbl.args = optionsTable
+end
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceDBOptions-3.0/AceDBOptions-3.0.xml b/ElvUI_OptionsUI/Libraries/Ace3/AceDBOptions-3.0/AceDBOptions-3.0.xml
new file mode 100644
index 0000000..2668fb0
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceDBOptions-3.0/AceDBOptions-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/AceGUI-3.0.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/AceGUI-3.0.lua
new file mode 100644
index 0000000..07b5217
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/AceGUI-3.0.lua
@@ -0,0 +1,1054 @@
+--- **AceGUI-3.0** provides access to numerous widgets which can be used to create GUIs.
+-- AceGUI is used by AceConfigDialog to create the option GUIs, but you can use it by itself
+-- to create any custom GUI. There are more extensive examples in the test suite in the Ace3
+-- stand-alone distribution.
+--
+-- **Note**: When using AceGUI-3.0 directly, please do not modify the frames of the widgets directly,
+-- as any "unknown" change to the widgets will cause addons that get your widget out of the widget pool
+-- to misbehave. If you think some part of a widget should be modifiable, please open a ticket, and we"ll
+-- implement a proper API to modify it.
+-- @usage
+-- local AceGUI = LibStub("AceGUI-3.0")
+-- -- Create a container frame
+-- local f = AceGUI:Create("Frame")
+-- f:SetCallback("OnClose",function(widget) AceGUI:Release(widget) end)
+-- f:SetTitle("AceGUI-3.0 Example")
+-- f:SetStatusText("Status Bar")
+-- f:SetLayout("Flow")
+-- -- Create a button
+-- local btn = AceGUI:Create("Button")
+-- btn:SetWidth(170)
+-- btn:SetText("Button !")
+-- btn:SetCallback("OnClick", function() print("Click!") end)
+-- -- Add the button to the container
+-- f:AddChild(btn)
+-- @class file
+-- @name AceGUI-3.0
+-- @release $Id$
+local ACEGUI_MAJOR, ACEGUI_MINOR = "AceGUI-3.0", 41
+local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
+
+if not AceGUI then return end -- No upgrade needed
+
+-- Lua APIs
+local tconcat, tinsert = table.concat, table.insert
+local select, pairs, next, type = select, pairs, next, type
+local error, assert, loadstring = error, assert, loadstring
+local setmetatable, rawget, rawset = setmetatable, rawget, rawset
+local math_max = math.max
+
+-- WoW APIs
+local UIParent = UIParent
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: geterrorhandler, LibStub
+
+--local con = LibStub("AceConsole-3.0",true)
+
+AceGUI.WidgetRegistry = AceGUI.WidgetRegistry or {}
+AceGUI.LayoutRegistry = AceGUI.LayoutRegistry or {}
+AceGUI.WidgetBase = AceGUI.WidgetBase or {}
+AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {}
+AceGUI.WidgetVersions = AceGUI.WidgetVersions or {}
+
+-- local upvalues
+local WidgetRegistry = AceGUI.WidgetRegistry
+local LayoutRegistry = AceGUI.LayoutRegistry
+local WidgetVersions = AceGUI.WidgetVersions
+
+--[[
+ xpcall safecall implementation
+]]
+local xpcall = xpcall
+
+local function errorhandler(err)
+ return geterrorhandler()(err)
+end
+
+local function CreateDispatcher(argCount)
+ local code = [[
+ local xpcall, eh = ...
+ local method, ARGS
+ local function call() return method(ARGS) end
+
+ local function dispatch(func, ...)
+ method = func
+ if not method then return end
+ ARGS = ...
+ return xpcall(call, eh)
+ end
+
+ return dispatch
+ ]]
+
+ local ARGS = {}
+ for i = 1, argCount do ARGS[i] = "arg"..i end
+ code = code:gsub("ARGS", tconcat(ARGS, ", "))
+ return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
+end
+
+local Dispatchers = setmetatable({}, {__index=function(self, argCount)
+ local dispatcher = CreateDispatcher(argCount)
+ rawset(self, argCount, dispatcher)
+ return dispatcher
+end})
+Dispatchers[0] = function(func)
+ return xpcall(func, errorhandler)
+end
+
+local function safecall(func, ...)
+ return Dispatchers[select("#", ...)](func, ...)
+end
+
+-- Recycling functions
+local newWidget, delWidget
+do
+ -- Version Upgrade in Minor 29
+ -- Internal Storage of the objects changed, from an array table
+ -- to a hash table, and additionally we introduced versioning on
+ -- the widgets which would discard all widgets from a pre-29 version
+ -- anyway, so we just clear the storage now, and don't try to
+ -- convert the storage tables to the new format.
+ -- This should generally not cause *many* widgets to end up in trash,
+ -- since once dialogs are opened, all addons should be loaded already
+ -- and AceGUI should be on the latest version available on the users
+ -- setup.
+ -- -- nevcairiel - Nov 2nd, 2009
+ if oldminor and oldminor < 29 and AceGUI.objPools then
+ AceGUI.objPools = nil
+ end
+
+ AceGUI.objPools = AceGUI.objPools or {}
+ local objPools = AceGUI.objPools
+ --Returns a new instance, if none are available either returns a new table or calls the given contructor
+ function newWidget(type)
+ if not WidgetRegistry[type] then
+ error("Attempt to instantiate unknown widget type", 2)
+ end
+
+ if not objPools[type] then
+ objPools[type] = {}
+ end
+
+ local newObj = next(objPools[type])
+ if not newObj then
+ newObj = WidgetRegistry[type]()
+ newObj.AceGUIWidgetVersion = WidgetVersions[type]
+ else
+ objPools[type][newObj] = nil
+ -- if the widget is older then the latest, don't even try to reuse it
+ -- just forget about it, and grab a new one.
+ if not newObj.AceGUIWidgetVersion or newObj.AceGUIWidgetVersion < WidgetVersions[type] then
+ return newWidget(type)
+ end
+ end
+ return newObj
+ end
+ -- Releases an instance to the Pool
+ function delWidget(obj,type)
+ if not objPools[type] then
+ objPools[type] = {}
+ end
+ if objPools[type][obj] then
+ error("Attempt to Release Widget that is already released", 2)
+ end
+ objPools[type][obj] = true
+ end
+end
+
+
+-------------------
+-- API Functions --
+-------------------
+
+-- Gets a widget Object
+
+--- Create a new Widget of the given type.
+-- This function will instantiate a new widget (or use one from the widget pool), and call the
+-- OnAcquire function on it, before returning.
+-- @param type The type of the widget.
+-- @return The newly created widget.
+function AceGUI:Create(type)
+ if WidgetRegistry[type] then
+ local widget = newWidget(type)
+
+ if rawget(widget, "Acquire") then
+ widget.OnAcquire = widget.Acquire
+ widget.Acquire = nil
+ elseif rawget(widget, "Aquire") then
+ widget.OnAcquire = widget.Aquire
+ widget.Aquire = nil
+ end
+
+ if rawget(widget, "Release") then
+ widget.OnRelease = rawget(widget, "Release")
+ widget.Release = nil
+ end
+
+ if widget.OnAcquire then
+ widget:OnAcquire()
+ else
+ error(("Widget type %s doesn't supply an OnAcquire Function"):format(type))
+ end
+ -- Set the default Layout ("List")
+ safecall(widget.SetLayout, widget, "List")
+ safecall(widget.ResumeLayout, widget)
+ return widget
+ end
+end
+
+--- Releases a widget Object.
+-- This function calls OnRelease on the widget and places it back in the widget pool.
+-- Any data on the widget is being erased, and the widget will be hidden.\\
+-- If this widget is a Container-Widget, all of its Child-Widgets will be releases as well.
+-- @param widget The widget to release
+function AceGUI:Release(widget)
+ if widget.isQueuedForRelease then return end
+ widget.isQueuedForRelease = true
+ safecall(widget.PauseLayout, widget)
+ widget.frame:Hide()
+ widget:Fire("OnRelease")
+ safecall(widget.ReleaseChildren, widget)
+
+ if widget.OnRelease then
+ widget:OnRelease()
+-- else
+-- error(("Widget type %s doesn't supply an OnRelease Function"):format(widget.type))
+ end
+ for k in pairs(widget.userdata) do
+ widget.userdata[k] = nil
+ end
+ for k in pairs(widget.events) do
+ widget.events[k] = nil
+ end
+ widget.width = nil
+ widget.relWidth = nil
+ widget.height = nil
+ widget.relHeight = nil
+ widget.noAutoHeight = nil
+ widget.frame:ClearAllPoints()
+ widget.frame:Hide()
+ widget.frame:SetParent(UIParent)
+ widget.frame.width = nil
+ widget.frame.height = nil
+ if widget.content then
+ widget.content.width = nil
+ widget.content.height = nil
+ end
+ widget.isQueuedForRelease = nil
+ delWidget(widget, widget.type)
+end
+
+--- Check if a widget is currently in the process of being released
+-- This function check if this widget, or any of its parents (in which case it'll be released shortly as well)
+-- are currently being released. This allows addon to handle any callbacks accordingly.
+-- @param widget The widget to check
+function AceGUI:IsReleasing(widget)
+ if widget.isQueuedForRelease then
+ return true
+ end
+
+ if widget.parent and widget.parent.AceGUIWidgetVersion then
+ return AceGUI:IsReleasing(widget.parent)
+ end
+
+ return false
+end
+
+-----------
+-- Focus --
+-----------
+
+
+--- Called when a widget has taken focus.
+-- e.g. Dropdowns opening, Editboxes gaining kb focus
+-- @param widget The widget that should be focused
+function AceGUI:SetFocus(widget)
+ if self.FocusedWidget and self.FocusedWidget ~= widget then
+ safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
+ end
+ self.FocusedWidget = widget
+end
+
+
+--- Called when something has happened that could cause widgets with focus to drop it
+-- e.g. titlebar of a frame being clicked
+function AceGUI:ClearFocus()
+ if self.FocusedWidget then
+ safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
+ self.FocusedWidget = nil
+ end
+end
+
+-------------
+-- Widgets --
+-------------
+--[[
+ Widgets must provide the following functions
+ OnAcquire() - Called when the object is acquired, should set everything to a default hidden state
+
+ And the following members
+ frame - the frame or derivitive object that will be treated as the widget for size and anchoring purposes
+ type - the type of the object, same as the name given to :RegisterWidget()
+
+ Widgets contain a table called userdata, this is a safe place to store data associated with the wigdet
+ It will be cleared automatically when a widget is released
+ Placing values directly into a widget object should be avoided
+
+ If the Widget can act as a container for other Widgets the following
+ content - frame or derivitive that children will be anchored to
+
+ The Widget can supply the following Optional Members
+ :OnRelease() - Called when the object is Released, should remove any additional anchors and clear any data
+ :OnWidthSet(width) - Called when the width of the widget is changed
+ :OnHeightSet(height) - Called when the height of the widget is changed
+ Widgets should not use the OnSizeChanged events of thier frame or content members, use these methods instead
+ AceGUI already sets a handler to the event
+ :LayoutFinished(width, height) - called after a layout has finished, the width and height will be the width and height of the
+ area used for controls. These can be nil if the layout used the existing size to layout the controls.
+
+]]
+
+--------------------------
+-- Widget Base Template --
+--------------------------
+do
+ local WidgetBase = AceGUI.WidgetBase
+
+ WidgetBase.SetParent = function(self, parent)
+ local frame = self.frame
+ frame:SetParent(nil)
+ frame:SetParent(parent.content)
+ self.parent = parent
+ end
+
+ WidgetBase.SetCallback = function(self, name, func)
+ if type(func) == "function" then
+ self.events[name] = func
+ end
+ end
+
+ WidgetBase.Fire = function(self, name, ...)
+ if self.events[name] then
+ local success, ret = safecall(self.events[name], self, name, ...)
+ if success then
+ return ret
+ end
+ end
+ end
+
+ WidgetBase.SetWidth = function(self, width)
+ self.frame:SetWidth(width)
+ self.frame.width = width
+ if self.OnWidthSet then
+ self:OnWidthSet(width)
+ end
+ end
+
+ WidgetBase.SetRelativeWidth = function(self, width)
+ if width <= 0 or width > 1 then
+ error(":SetRelativeWidth(width): Invalid relative width.", 2)
+ end
+ self.relWidth = width
+ self.width = "relative"
+ end
+
+ WidgetBase.SetHeight = function(self, height)
+ self.frame:SetHeight(height)
+ self.frame.height = height
+ if self.OnHeightSet then
+ self:OnHeightSet(height)
+ end
+ end
+
+ --[[ WidgetBase.SetRelativeHeight = function(self, height)
+ if height <= 0 or height > 1 then
+ error(":SetRelativeHeight(height): Invalid relative height.", 2)
+ end
+ self.relHeight = height
+ self.height = "relative"
+ end ]]
+
+ WidgetBase.IsVisible = function(self)
+ return self.frame:IsVisible()
+ end
+
+ WidgetBase.IsShown= function(self)
+ return self.frame:IsShown()
+ end
+
+ WidgetBase.Release = function(self)
+ AceGUI:Release(self)
+ end
+
+ WidgetBase.IsReleasing = function(self)
+ return AceGUI:IsReleasing(self)
+ end
+
+ WidgetBase.SetPoint = function(self, ...)
+ return self.frame:SetPoint(...)
+ end
+
+ WidgetBase.ClearAllPoints = function(self)
+ return self.frame:ClearAllPoints()
+ end
+
+ WidgetBase.GetNumPoints = function(self)
+ return self.frame:GetNumPoints()
+ end
+
+ WidgetBase.GetPoint = function(self, ...)
+ return self.frame:GetPoint(...)
+ end
+
+ WidgetBase.GetUserDataTable = function(self)
+ return self.userdata
+ end
+
+ WidgetBase.SetUserData = function(self, key, value)
+ self.userdata[key] = value
+ end
+
+ WidgetBase.GetUserData = function(self, key)
+ return self.userdata[key]
+ end
+
+ WidgetBase.IsFullHeight = function(self)
+ return self.height == "fill"
+ end
+
+ WidgetBase.SetFullHeight = function(self, isFull)
+ if isFull then
+ self.height = "fill"
+ else
+ self.height = nil
+ end
+ end
+
+ WidgetBase.IsFullWidth = function(self)
+ return self.width == "fill"
+ end
+
+ WidgetBase.SetFullWidth = function(self, isFull)
+ if isFull then
+ self.width = "fill"
+ else
+ self.width = nil
+ end
+ end
+
+-- local function LayoutOnUpdate(this)
+-- this:SetScript("OnUpdate",nil)
+-- this.obj:PerformLayout()
+-- end
+
+ local WidgetContainerBase = AceGUI.WidgetContainerBase
+
+ WidgetContainerBase.PauseLayout = function(self)
+ self.LayoutPaused = true
+ end
+
+ WidgetContainerBase.ResumeLayout = function(self)
+ self.LayoutPaused = nil
+ end
+
+ WidgetContainerBase.PerformLayout = function(self)
+ if self.LayoutPaused then
+ return
+ end
+ safecall(self.LayoutFunc, self.content, self.children)
+ end
+
+ --call this function to layout, makes sure layed out objects get a frame to get sizes etc
+ WidgetContainerBase.DoLayout = function(self)
+ self:PerformLayout()
+-- if not self.parent then
+-- self.frame:SetScript("OnUpdate", LayoutOnUpdate)
+-- end
+ end
+
+ WidgetContainerBase.AddChild = function(self, child, beforeWidget)
+ if beforeWidget then
+ local siblingIndex = 1
+ for _, widget in pairs(self.children) do
+ if widget == beforeWidget then
+ break
+ end
+ siblingIndex = siblingIndex + 1
+ end
+ tinsert(self.children, siblingIndex, child)
+ else
+ tinsert(self.children, child)
+ end
+ child:SetParent(self)
+ child.frame:Show()
+ self:DoLayout()
+ end
+
+ WidgetContainerBase.AddChildren = function(self, ...)
+ for i = 1, select("#", ...) do
+ local child = select(i, ...)
+ tinsert(self.children, child)
+ child:SetParent(self)
+ child.frame:Show()
+ end
+ self:DoLayout()
+ end
+
+ WidgetContainerBase.ReleaseChildren = function(self)
+ local children = self.children
+ for i = 1,#children do
+ AceGUI:Release(children[i])
+ children[i] = nil
+ end
+ end
+
+ WidgetContainerBase.SetLayout = function(self, Layout)
+ self.LayoutFunc = AceGUI:GetLayout(Layout)
+ end
+
+ WidgetContainerBase.SetAutoAdjustHeight = function(self, adjust)
+ if adjust then
+ self.noAutoHeight = nil
+ else
+ self.noAutoHeight = true
+ end
+ end
+
+ local function FrameResize(this)
+ local self = this.obj
+ if this:GetWidth() and this:GetHeight() then
+ if self.OnWidthSet then
+ self:OnWidthSet(this:GetWidth())
+ end
+ if self.OnHeightSet then
+ self:OnHeightSet(this:GetHeight())
+ end
+ end
+ end
+
+ local function ContentResize(this)
+ if this:GetWidth() and this:GetHeight() then
+ this.width = this:GetWidth()
+ this.height = this:GetHeight()
+ this.obj:DoLayout()
+ end
+ end
+
+ setmetatable(WidgetContainerBase, {__index=WidgetBase})
+
+ --One of these function should be called on each Widget Instance as part of its creation process
+
+ --- Register a widget-class as a container for newly created widgets.
+ -- @param widget The widget class
+ function AceGUI:RegisterAsContainer(widget)
+ widget.children = {}
+ widget.userdata = {}
+ widget.events = {}
+ widget.base = WidgetContainerBase
+ widget.content.obj = widget
+ widget.frame.obj = widget
+ widget.content:SetScript("OnSizeChanged", ContentResize)
+ widget.frame:SetScript("OnSizeChanged", FrameResize)
+ setmetatable(widget, {__index = WidgetContainerBase})
+ widget:SetLayout("List")
+ return widget
+ end
+
+ --- Register a widget-class as a widget.
+ -- @param widget The widget class
+ function AceGUI:RegisterAsWidget(widget)
+ widget.userdata = {}
+ widget.events = {}
+ widget.base = WidgetBase
+ widget.frame.obj = widget
+ widget.frame:SetScript("OnSizeChanged", FrameResize)
+ setmetatable(widget, {__index = WidgetBase})
+ return widget
+ end
+end
+
+
+
+
+------------------
+-- Widget API --
+------------------
+
+--- Registers a widget Constructor, this function returns a new instance of the Widget
+-- @param Name The name of the widget
+-- @param Constructor The widget constructor function
+-- @param Version The version of the widget
+function AceGUI:RegisterWidgetType(Name, Constructor, Version)
+ assert(type(Constructor) == "function")
+ assert(type(Version) == "number")
+
+ local oldVersion = WidgetVersions[Name]
+ if oldVersion and oldVersion >= Version then return end
+
+ WidgetVersions[Name] = Version
+ WidgetRegistry[Name] = Constructor
+end
+
+--- Registers a Layout Function
+-- @param Name The name of the layout
+-- @param LayoutFunc Reference to the layout function
+function AceGUI:RegisterLayout(Name, LayoutFunc)
+ assert(type(LayoutFunc) == "function")
+ if type(Name) == "string" then
+ Name = Name:upper()
+ end
+ LayoutRegistry[Name] = LayoutFunc
+end
+
+--- Get a Layout Function from the registry
+-- @param Name The name of the layout
+function AceGUI:GetLayout(Name)
+ if type(Name) == "string" then
+ Name = Name:upper()
+ end
+ return LayoutRegistry[Name]
+end
+
+AceGUI.counts = AceGUI.counts or {}
+
+--- A type-based counter to count the number of widgets created.
+-- This is used by widgets that require a named frame, e.g. when a Blizzard
+-- Template requires it.
+-- @param type The widget type
+function AceGUI:GetNextWidgetNum(type)
+ if not self.counts[type] then
+ self.counts[type] = 0
+ end
+ self.counts[type] = self.counts[type] + 1
+ return self.counts[type]
+end
+
+--- Return the number of created widgets for this type.
+-- In contrast to GetNextWidgetNum, the number is not incremented.
+-- @param type The widget type
+function AceGUI:GetWidgetCount(type)
+ return self.counts[type] or 0
+end
+
+--- Return the version of the currently registered widget type.
+-- @param type The widget type
+function AceGUI:GetWidgetVersion(type)
+ return WidgetVersions[type]
+end
+
+-------------
+-- Layouts --
+-------------
+
+--[[
+ A Layout is a func that takes 2 parameters
+ content - the frame that widgets will be placed inside
+ children - a table containing the widgets to layout
+]]
+
+-- Very simple Layout, Children are stacked on top of each other down the left side
+AceGUI:RegisterLayout("List",
+ function(content, children)
+ local height = 0
+ local width = content.width or content:GetWidth() or 0
+ for i = 1, #children do
+ local child = children[i]
+
+ local frame = child.frame
+ frame:ClearAllPoints()
+ frame:Show()
+ if i == 1 then
+ frame:SetPoint("TOPLEFT", content)
+ else
+ frame:SetPoint("TOPLEFT", children[i-1].frame, "BOTTOMLEFT")
+ end
+
+ if child.width == "fill" then
+ child:SetWidth(width)
+ frame:SetPoint("RIGHT", content)
+
+ if child.DoLayout then
+ child:DoLayout()
+ end
+ elseif child.width == "relative" then
+ child:SetWidth(width * child.relWidth)
+
+ if child.DoLayout then
+ child:DoLayout()
+ end
+ end
+
+ height = height + (frame.height or frame:GetHeight() or 0)
+ end
+ safecall(content.obj.LayoutFinished, content.obj, nil, height)
+ end)
+
+-- A single control fills the whole content area
+AceGUI:RegisterLayout("Fill",
+ function(content, children)
+ if children[1] then
+ children[1]:SetWidth(content:GetWidth() or 0)
+ children[1]:SetHeight(content:GetHeight() or 0)
+ children[1].frame:ClearAllPoints()
+ children[1].frame:SetAllPoints(content)
+ children[1].frame:Show()
+ safecall(content.obj.LayoutFinished, content.obj, nil, children[1].frame:GetHeight())
+ end
+ end)
+
+local layoutrecursionblock = nil
+local function safelayoutcall(object, func, ...)
+ layoutrecursionblock = true
+ object[func](object, ...)
+ layoutrecursionblock = nil
+end
+
+AceGUI:RegisterLayout("Flow",
+ function(content, children)
+ if layoutrecursionblock then return end
+ --used height so far
+ local height = 0
+ --width used in the current row
+ local usedwidth = 0
+ --height of the current row
+ local rowheight = 0
+ local rowoffset = 0
+
+ local width = content.width or content:GetWidth() or 0
+
+ --control at the start of the row
+ local rowstart
+ local rowstartoffset
+ local isfullheight
+
+ local frameoffset
+ local lastframeoffset
+ local oversize
+ for i = 1, #children do
+ local child = children[i]
+ oversize = nil
+ local frame = child.frame
+ local frameheight = frame.height or frame:GetHeight() or 0
+ local framewidth = frame.width or frame:GetWidth() or 0
+ lastframeoffset = frameoffset
+ -- HACK: Why did we set a frameoffset of (frameheight / 2) ?
+ -- That was moving all widgets half the widgets size down, is that intended?
+ -- Actually, it seems to be neccessary for many cases, we'll leave it in for now.
+ -- If widgets seem to anchor weirdly with this, provide a valid alignoffset for them.
+ -- TODO: Investigate moar!
+ frameoffset = child.alignoffset or (frameheight / 2)
+
+ if child.width == "relative" then
+ framewidth = width * child.relWidth
+ end
+
+ frame:Show()
+ frame:ClearAllPoints()
+ if i == 1 then
+ -- anchor the first control to the top left
+ frame:SetPoint("TOPLEFT", content)
+ rowheight = frameheight
+ rowoffset = frameoffset
+ rowstart = frame
+ rowstartoffset = frameoffset
+ usedwidth = framewidth
+ if usedwidth > width then
+ oversize = true
+ end
+ else
+ -- if there isn't available width for the control start a new row
+ -- if a control is "fill" it will be on a row of its own full width
+ if usedwidth == 0 or ((framewidth) + usedwidth > width) or child.width == "fill" then
+ if isfullheight then
+ -- a previous row has already filled the entire height, there's nothing we can usefully do anymore
+ -- (maybe error/warn about this?)
+ break
+ end
+ --anchor the previous row, we will now know its height and offset
+ rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
+ height = height + rowheight + 3
+ --save this as the rowstart so we can anchor it after the row is complete and we have the max height and offset of controls in it
+ rowstart = frame
+ rowstartoffset = frameoffset
+ rowheight = frameheight
+ rowoffset = frameoffset
+ usedwidth = framewidth
+ if usedwidth > width then
+ oversize = true
+ end
+ -- put the control on the current row, adding it to the width and checking if the height needs to be increased
+ else
+ --handles cases where the new height is higher than either control because of the offsets
+ --math.max(rowheight-rowoffset+frameoffset, frameheight-frameoffset+rowoffset)
+
+ --offset is always the larger of the two offsets
+ rowoffset = math_max(rowoffset, frameoffset)
+ rowheight = math_max(rowheight, rowoffset + (frameheight / 2))
+
+ frame:SetPoint("TOPLEFT", children[i-1].frame, "TOPRIGHT", 0, frameoffset - lastframeoffset)
+ usedwidth = framewidth + usedwidth
+ end
+ end
+
+ if child.width == "fill" then
+ safelayoutcall(child, "SetWidth", width)
+ frame:SetPoint("RIGHT", content)
+
+ usedwidth = 0
+ rowstart = frame
+ rowstartoffset = frameoffset
+
+ if child.DoLayout then
+ child:DoLayout()
+ end
+ rowheight = frame.height or frame:GetHeight() or 0
+ rowoffset = child.alignoffset or (rowheight / 2)
+ rowstartoffset = rowoffset
+ elseif child.width == "relative" then
+ safelayoutcall(child, "SetWidth", width * child.relWidth)
+
+ if child.DoLayout then
+ child:DoLayout()
+ end
+ elseif oversize then
+ if width > 1 then
+ frame:SetPoint("RIGHT", content)
+ end
+ end
+
+ if child.height == "fill" then
+ frame:SetPoint("BOTTOM", content)
+ isfullheight = true
+ end
+ end
+
+ --anchor the last row, if its full height needs a special case since its height has just been changed by the anchor
+ if isfullheight then
+ rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -height)
+ elseif rowstart then
+ rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
+ end
+
+ height = height + rowheight + 3
+ safecall(content.obj.LayoutFinished, content.obj, nil, height)
+ end)
+
+-- Get alignment method and value. Possible alignment methods are a callback, a number, "start", "middle", "end", "fill" or "TOPLEFT", "BOTTOMRIGHT" etc.
+local GetCellAlign = function (dir, tableObj, colObj, cellObj, cell, child)
+ local fn = cellObj and (cellObj["align" .. dir] or cellObj.align)
+ or colObj and (colObj["align" .. dir] or colObj.align)
+ or tableObj["align" .. dir] or tableObj.align
+ or "CENTERLEFT"
+ local child, cell, val = child or 0, cell or 0, nil
+
+ if type(fn) == "string" then
+ fn = fn:lower()
+ fn = dir == "V" and (fn:sub(1, 3) == "top" and "start" or fn:sub(1, 6) == "bottom" and "end" or fn:sub(1, 6) == "center" and "middle")
+ or dir == "H" and (fn:sub(-4) == "left" and "start" or fn:sub(-5) == "right" and "end" or fn:sub(-6) == "center" and "middle")
+ or fn
+ val = (fn == "start" or fn == "fill") and 0 or fn == "end" and cell - child or (cell - child) / 2
+ elseif type(fn) == "function" then
+ val = fn(child or 0, cell, dir)
+ else
+ val = fn
+ end
+
+ return fn, max(0, min(val, cell))
+end
+
+-- Get width or height for multiple cells combined
+local GetCellDimension = function (dir, laneDim, from, to, space)
+ local dim = 0
+ for cell=from,to do
+ dim = dim + (laneDim[cell] or 0)
+ end
+ return dim + max(0, to - from) * (space or 0)
+end
+
+--[[ Options
+============
+Container:
+ - columns ({col, col, ...}): Column settings. "col" can be a number (<= 0: content width, <1: rel. width, <10: weight, >=10: abs. width) or a table with column setting.
+ - space, spaceH, spaceV: Overall, horizontal and vertical spacing between cells.
+ - align, alignH, alignV: Overall, horizontal and vertical cell alignment. See GetCellAlign() for possible values.
+Columns:
+ - width: Fixed column width (nil or <=0: content width, <1: rel. width, >=1: abs. width).
+ - min or 1: Min width for content based width
+ - max or 2: Max width for content based width
+ - weight: Flexible column width. The leftover width after accounting for fixed-width columns is distributed to weighted columns according to their weights.
+ - align, alignH, alignV: Overwrites the container setting for alignment.
+Cell:
+ - colspan: Makes a cell span multiple columns.
+ - rowspan: Makes a cell span multiple rows.
+ - align, alignH, alignV: Overwrites the container and column setting for alignment.
+]]
+AceGUI:RegisterLayout("Table",
+ function (content, children)
+ local obj = content.obj
+ obj:PauseLayout()
+
+ local tableObj = obj:GetUserData("table")
+ local cols = tableObj.columns
+ local spaceH = tableObj.spaceH or tableObj.space or 0
+ local spaceV = tableObj.spaceV or tableObj.space or 0
+ local totalH = (content:GetWidth() or content.width or 0) - spaceH * (#cols - 1)
+
+ -- We need to reuse these because layout events can come in very frequently
+ local layoutCache = obj:GetUserData("layoutCache")
+ if not layoutCache then
+ layoutCache = {{}, {}, {}, {}, {}, {}}
+ obj:SetUserData("layoutCache", layoutCache)
+ end
+ local t, laneH, laneV, rowspans, rowStart, colStart = unpack(layoutCache)
+
+ -- Create the grid
+ local n, slotFound = 0
+ for i,child in ipairs(children) do
+ if child:IsShown() then
+ repeat
+ n = n + 1
+ local col = (n - 1) % #cols + 1
+ local row = ceil(n / #cols)
+ local rowspan = rowspans[col]
+ local cell = rowspan and rowspan.child or child
+ local cellObj = cell:GetUserData("cell")
+ slotFound = not rowspan
+
+ -- Rowspan
+ if not rowspan and cellObj and cellObj.rowspan then
+ rowspan = {child = child, from = row, to = row + cellObj.rowspan - 1}
+ rowspans[col] = rowspan
+ end
+ if rowspan and i == #children then
+ rowspan.to = row
+ end
+
+ -- Colspan
+ local colspan = max(0, min((cellObj and cellObj.colspan or 1) - 1, #cols - col))
+ n = n + colspan
+
+ -- Place the cell
+ if not rowspan or rowspan.to == row then
+ t[n] = cell
+ rowStart[cell] = rowspan and rowspan.from or row
+ colStart[cell] = col
+
+ if rowspan then
+ rowspans[col] = nil
+ end
+ end
+ until slotFound
+ end
+ end
+
+ local rows = ceil(n / #cols)
+
+ -- Determine fixed size cols and collect weights
+ local extantH, totalWeight = totalH, 0
+ for col,colObj in ipairs(cols) do
+ laneH[col] = 0
+
+ if type(colObj) == "number" then
+ colObj = {[colObj >= 1 and colObj < 10 and "weight" or "width"] = colObj}
+ cols[col] = colObj
+ end
+
+ if colObj.weight then
+ -- Weight
+ totalWeight = totalWeight + (colObj.weight or 1)
+ else
+ if not colObj.width or colObj.width <= 0 then
+ -- Content width
+ for row=1,rows do
+ local child = t[(row - 1) * #cols + col]
+ if child then
+ local f = child.frame
+ f:ClearAllPoints()
+ local childH = f:GetWidth() or 0
+
+ laneH[col] = max(laneH[col], childH - GetCellDimension("H", laneH, colStart[child], col - 1, spaceH))
+ end
+ end
+
+ laneH[col] = max(colObj.min or colObj[1] or 0, min(laneH[col], colObj.max or colObj[2] or laneH[col]))
+ else
+ -- Rel./Abs. width
+ laneH[col] = colObj.width < 1 and colObj.width * totalH or colObj.width
+ end
+ extantH = max(0, extantH - laneH[col])
+ end
+ end
+
+ -- Determine sizes based on weight
+ local scale = totalWeight > 0 and extantH / totalWeight or 0
+ for col,colObj in pairs(cols) do
+ if colObj.weight then
+ laneH[col] = scale * colObj.weight
+ end
+ end
+
+ -- Arrange children
+ for row=1,rows do
+ local rowV = 0
+
+ -- Horizontal placement and sizing
+ for col=1,#cols do
+ local child = t[(row - 1) * #cols + col]
+ if child then
+ local colObj = cols[colStart[child]]
+ local cellObj = child:GetUserData("cell")
+ local offsetH = GetCellDimension("H", laneH, 1, colStart[child] - 1, spaceH) + (colStart[child] == 1 and 0 or spaceH)
+ local cellH = GetCellDimension("H", laneH, colStart[child], col, spaceH)
+
+ local f = child.frame
+ f:ClearAllPoints()
+ local childH = f:GetWidth() or 0
+
+ local alignFn, align = GetCellAlign("H", tableObj, colObj, cellObj, cellH, childH)
+ f:SetPoint("LEFT", content, offsetH + align, 0)
+ if child:IsFullWidth() or alignFn == "fill" or childH > cellH then
+ f:SetPoint("RIGHT", content, "LEFT", offsetH + align + cellH, 0)
+ end
+
+ if child.DoLayout then
+ child:DoLayout()
+ end
+
+ rowV = max(rowV, (f:GetHeight() or 0) - GetCellDimension("V", laneV, rowStart[child], row - 1, spaceV))
+ end
+ end
+
+ laneV[row] = rowV
+
+ -- Vertical placement and sizing
+ for col=1,#cols do
+ local child = t[(row - 1) * #cols + col]
+ if child then
+ local colObj = cols[colStart[child]]
+ local cellObj = child:GetUserData("cell")
+ local offsetV = GetCellDimension("V", laneV, 1, rowStart[child] - 1, spaceV) + (rowStart[child] == 1 and 0 or spaceV)
+ local cellV = GetCellDimension("V", laneV, rowStart[child], row, spaceV)
+
+ local f = child.frame
+ local childV = f:GetHeight() or 0
+
+ local alignFn, align = GetCellAlign("V", tableObj, colObj, cellObj, cellV, childV)
+ if child:IsFullHeight() or alignFn == "fill" then
+ f:SetHeight(cellV)
+ end
+ f:SetPoint("TOP", content, 0, -(offsetV + align))
+ end
+ end
+ end
+
+ -- Calculate total height
+ local totalV = GetCellDimension("V", laneV, 1, #laneV, spaceV)
+
+ -- Cleanup
+ for _,v in pairs(layoutCache) do wipe(v) end
+
+ safecall(obj.LayoutFinished, obj, nil, totalV)
+ obj:ResumeLayout()
+ end)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/AceGUI-3.0.xml b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/AceGUI-3.0.xml
new file mode 100644
index 0000000..843a3dc
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/AceGUI-3.0.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua
new file mode 100644
index 0000000..9a48f8b
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua
@@ -0,0 +1,138 @@
+--[[-----------------------------------------------------------------------------
+BlizOptionsGroup Container
+Simple container widget for the integration of AceGUI into the Blizzard Interface Options
+-------------------------------------------------------------------------------]]
+local Type, Version = "BlizOptionsGroup", 21
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs = pairs
+
+-- WoW APIs
+local CreateFrame = CreateFrame
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+
+local function OnShow(frame)
+ frame.obj:Fire("OnShow")
+end
+
+local function OnHide(frame)
+ frame.obj:Fire("OnHide")
+end
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+
+local function okay(frame)
+ frame.obj:Fire("okay")
+end
+
+local function cancel(frame)
+ frame.obj:Fire("cancel")
+end
+
+local function default(frame)
+ frame.obj:Fire("default")
+end
+
+local function refresh(frame)
+ frame.obj:Fire("refresh")
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetName()
+ self:SetTitle()
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ local contentwidth = width - 63
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - 26
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end,
+
+ ["SetName"] = function(self, name, parent)
+ self.frame.name = name
+ self.frame.parent = parent
+ end,
+
+ ["SetTitle"] = function(self, title)
+ local content = self.content
+ content:ClearAllPoints()
+ if not title or title == "" then
+ content:SetPoint("TOPLEFT", 10, -10)
+ self.label:SetText("")
+ else
+ content:SetPoint("TOPLEFT", 10, -40)
+ self.label:SetText(title)
+ end
+ content:SetPoint("BOTTOMRIGHT", -10, 10)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Frame")
+ frame:Hide()
+
+ -- support functions for the Blizzard Interface Options
+ frame.okay = okay
+ frame.cancel = cancel
+ frame.default = default
+ frame.refresh = refresh
+
+ frame:SetScript("OnHide", OnHide)
+ frame:SetScript("OnShow", OnShow)
+
+ local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
+ label:SetPoint("TOPLEFT", 10, -15)
+ label:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", 10, -45)
+ label:SetJustifyH("LEFT")
+ label:SetJustifyV("TOP")
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, frame)
+ content:SetPoint("TOPLEFT", 10, -10)
+ content:SetPoint("BOTTOMRIGHT", -10, 10)
+
+ local widget = {
+ label = label,
+ frame = frame,
+ content = content,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua
new file mode 100644
index 0000000..4b09d64
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua
@@ -0,0 +1,157 @@
+--[[-----------------------------------------------------------------------------
+DropdownGroup Container
+Container controlled by a dropdown on the top.
+-------------------------------------------------------------------------------]]
+local Type, Version = "DropdownGroup", 21
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local assert, pairs, type = assert, pairs, type
+
+-- WoW APIs
+local CreateFrame = CreateFrame
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function SelectedGroup(self, event, value)
+ local group = self.parentgroup
+ local status = group.status or group.localstatus
+ status.selected = value
+ self.parentgroup:Fire("OnGroupSelected", value)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self.dropdown:SetText("")
+ self:SetDropdownWidth(200)
+ self:SetTitle("")
+ end,
+
+ ["OnRelease"] = function(self)
+ self.dropdown.list = nil
+ self.status = nil
+ for k in pairs(self.localstatus) do
+ self.localstatus[k] = nil
+ end
+ end,
+
+ ["SetTitle"] = function(self, title)
+ self.titletext:SetText(title)
+ self.dropdown.frame:ClearAllPoints()
+ if title and title ~= "" then
+ self.dropdown.frame:SetPoint("TOPRIGHT", -2, 0)
+ else
+ self.dropdown.frame:SetPoint("TOPLEFT", -1, 0)
+ end
+ end,
+
+ ["SetGroupList"] = function(self,list,order)
+ self.dropdown:SetList(list,order)
+ end,
+
+ ["SetStatusTable"] = function(self, status)
+ assert(type(status) == "table")
+ self.status = status
+ end,
+
+ ["SetGroup"] = function(self,group)
+ self.dropdown:SetValue(group)
+ local status = self.status or self.localstatus
+ status.selected = group
+ self:Fire("OnGroupSelected", group)
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ local contentwidth = width - 26
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - 63
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end,
+
+ ["LayoutFinished"] = function(self, width, height)
+ self:SetHeight((height or 0) + 63)
+ end,
+
+ ["SetDropdownWidth"] = function(self, width)
+ self.dropdown:SetWidth(width)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local PaneBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 5, bottom = 3 }
+}
+
+local function Constructor()
+ local frame = CreateFrame("Frame")
+ frame:SetHeight(100)
+ frame:SetWidth(100)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ local titletext = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ titletext:SetPoint("TOPLEFT", 4, -5)
+ titletext:SetPoint("TOPRIGHT", -4, -5)
+ titletext:SetJustifyH("LEFT")
+ titletext:SetHeight(18)
+
+ local dropdown = AceGUI:Create("Dropdown")
+ dropdown.frame:SetParent(frame)
+ dropdown.frame:SetFrameLevel(dropdown.frame:GetFrameLevel() + 2)
+ dropdown:SetCallback("OnValueChanged", SelectedGroup)
+ dropdown.frame:SetPoint("TOPLEFT", -1, 0)
+ dropdown.frame:Show()
+ dropdown:SetLabel("")
+
+ local border = CreateFrame("Frame", nil, frame)
+ border:SetPoint("TOPLEFT", 0, -26)
+ border:SetPoint("BOTTOMRIGHT", 0, 3)
+ border:SetBackdrop(PaneBackdrop)
+ border:SetBackdropColor(0.1,0.1,0.1,0.5)
+ border:SetBackdropBorderColor(0.4,0.4,0.4)
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, border)
+ content:SetPoint("TOPLEFT", 10, -10)
+ content:SetPoint("BOTTOMRIGHT", -10, 10)
+
+ local widget = {
+ frame = frame,
+ localstatus = {},
+ titletext = titletext,
+ dropdown = dropdown,
+ border = border,
+ content = content,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ dropdown.parentgroup = widget
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua
new file mode 100644
index 0000000..afc35de
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua
@@ -0,0 +1,316 @@
+--[[-----------------------------------------------------------------------------
+Frame Container
+-------------------------------------------------------------------------------]]
+local Type, Version = "Frame", 25
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs, assert, type = pairs, assert, type
+local wipe = table.wipe
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: CLOSE
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Button_OnClick(frame)
+ PlaySound("gsTitleOptionExit")
+ frame.obj:Hide()
+end
+
+local function Frame_OnShow(frame)
+ frame.obj:Fire("OnShow")
+end
+
+local function Frame_OnClose(frame)
+ frame.obj:Fire("OnClose")
+end
+
+local function Frame_OnMouseDown(frame)
+ AceGUI:ClearFocus()
+end
+
+local function Title_OnMouseDown(frame)
+ frame:GetParent():StartMoving()
+ AceGUI:ClearFocus()
+end
+
+local function MoverSizer_OnMouseUp(mover)
+ local frame = mover:GetParent()
+ frame:StopMovingOrSizing()
+ local self = frame.obj
+ local status = self.status or self.localstatus
+ status.width = frame:GetWidth()
+ status.height = frame:GetHeight()
+ status.top = frame:GetTop()
+ status.left = frame:GetLeft()
+end
+
+local function SizerSE_OnMouseDown(frame)
+ frame:GetParent():StartSizing("BOTTOMRIGHT")
+ AceGUI:ClearFocus()
+end
+
+local function SizerS_OnMouseDown(frame)
+ frame:GetParent():StartSizing("BOTTOM")
+ AceGUI:ClearFocus()
+end
+
+local function SizerE_OnMouseDown(frame)
+ frame:GetParent():StartSizing("RIGHT")
+ AceGUI:ClearFocus()
+end
+
+local function StatusBar_OnEnter(frame)
+ frame.obj:Fire("OnEnterStatusBar")
+end
+
+local function StatusBar_OnLeave(frame)
+ frame.obj:Fire("OnLeaveStatusBar")
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self.frame:SetParent(UIParent)
+ self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
+ self:SetTitle()
+ self:SetStatusText()
+ self:ApplyStatus()
+ self:Show()
+ self:EnableResize(true)
+ end,
+
+ ["OnRelease"] = function(self)
+ self.status = nil
+ wipe(self.localstatus)
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ local contentwidth = width - 34
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - 57
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end,
+
+ ["SetTitle"] = function(self, title)
+ self.titletext:SetText(title)
+ self.titlebg:SetWidth((self.titletext:GetWidth() or 0) + 10)
+ end,
+
+ ["SetStatusText"] = function(self, text)
+ self.statustext:SetText(text)
+ end,
+
+ ["Hide"] = function(self)
+ self.frame:Hide()
+ end,
+
+ ["Show"] = function(self)
+ self.frame:Show()
+ end,
+
+ ["EnableResize"] = function(self, state)
+ local func = state and "Show" or "Hide"
+ self.sizer_se[func](self.sizer_se)
+ self.sizer_s[func](self.sizer_s)
+ self.sizer_e[func](self.sizer_e)
+ end,
+
+ -- called to set an external table to store status in
+ ["SetStatusTable"] = function(self, status)
+ assert(type(status) == "table")
+ self.status = status
+ self:ApplyStatus()
+ end,
+
+ ["ApplyStatus"] = function(self)
+ local status = self.status or self.localstatus
+ local frame = self.frame
+ self:SetWidth(status.width or 700)
+ self:SetHeight(status.height or 500)
+ frame:ClearAllPoints()
+ if status.top and status.left then
+ frame:SetPoint("TOP", UIParent, "BOTTOM", 0, status.top)
+ frame:SetPoint("LEFT", UIParent, "LEFT", status.left, 0)
+ else
+ frame:SetPoint("CENTER")
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local FrameBackdrop = {
+ bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
+ edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
+ tile = true, tileSize = 32, edgeSize = 32,
+ insets = { left = 8, right = 8, top = 8, bottom = 8 }
+}
+
+local PaneBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 5, bottom = 3 }
+}
+
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:Hide()
+
+ frame:EnableMouse(true)
+ frame:SetMovable(true)
+ frame:SetResizable(true)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+ frame:SetBackdrop(FrameBackdrop)
+ frame:SetBackdropColor(0, 0, 0, 1)
+ frame:SetMinResize(400, 200)
+ frame:SetToplevel(true)
+ frame:SetScript("OnShow", Frame_OnShow)
+ frame:SetScript("OnHide", Frame_OnClose)
+ frame:SetScript("OnMouseDown", Frame_OnMouseDown)
+
+ local closebutton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
+ closebutton:SetScript("OnClick", Button_OnClick)
+ closebutton:SetPoint("BOTTOMRIGHT", -27, 17)
+ closebutton:SetHeight(20)
+ closebutton:SetWidth(100)
+ closebutton:SetText(CLOSE)
+
+ local statusbg = CreateFrame("Button", nil, frame)
+ statusbg:SetPoint("BOTTOMLEFT", 15, 15)
+ statusbg:SetPoint("BOTTOMRIGHT", -132, 15)
+ statusbg:SetHeight(24)
+ statusbg:SetBackdrop(PaneBackdrop)
+ statusbg:SetBackdropColor(0.1,0.1,0.1)
+ statusbg:SetBackdropBorderColor(0.4,0.4,0.4)
+ statusbg:SetScript("OnEnter", StatusBar_OnEnter)
+ statusbg:SetScript("OnLeave", StatusBar_OnLeave)
+
+ local statustext = statusbg:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ statustext:SetPoint("TOPLEFT", 7, -2)
+ statustext:SetPoint("BOTTOMRIGHT", -7, 2)
+ statustext:SetHeight(20)
+ statustext:SetJustifyH("LEFT")
+ statustext:SetText("")
+
+ local titlebg = frame:CreateTexture(nil, "OVERLAY")
+ titlebg:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
+ titlebg:SetTexCoord(0.31, 0.67, 0, 0.63)
+ titlebg:SetPoint("TOP", 0, 12)
+ titlebg:SetWidth(100)
+ titlebg:SetHeight(40)
+
+ local title = CreateFrame("Frame", nil, frame)
+ title:EnableMouse(true)
+ title:SetScript("OnMouseDown", Title_OnMouseDown)
+ title:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
+ title:SetAllPoints(titlebg)
+
+ local titletext = title:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ titletext:SetPoint("TOP", titlebg, "TOP", 0, -14)
+
+ local titlebg_l = frame:CreateTexture(nil, "OVERLAY")
+ titlebg_l:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
+ titlebg_l:SetTexCoord(0.21, 0.31, 0, 0.63)
+ titlebg_l:SetPoint("RIGHT", titlebg, "LEFT")
+ titlebg_l:SetWidth(30)
+ titlebg_l:SetHeight(40)
+
+ local titlebg_r = frame:CreateTexture(nil, "OVERLAY")
+ titlebg_r:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
+ titlebg_r:SetTexCoord(0.67, 0.77, 0, 0.63)
+ titlebg_r:SetPoint("LEFT", titlebg, "RIGHT")
+ titlebg_r:SetWidth(30)
+ titlebg_r:SetHeight(40)
+
+ local sizer_se = CreateFrame("Frame", nil, frame)
+ sizer_se:SetPoint("BOTTOMRIGHT")
+ sizer_se:SetWidth(25)
+ sizer_se:SetHeight(25)
+ sizer_se:EnableMouse()
+ sizer_se:SetScript("OnMouseDown",SizerSE_OnMouseDown)
+ sizer_se:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
+
+ local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
+ line1:SetWidth(14)
+ line1:SetHeight(14)
+ line1:SetPoint("BOTTOMRIGHT", -8, 8)
+ line1:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
+ local x = 0.1 * 14/17
+ line1:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
+
+ local line2 = sizer_se:CreateTexture(nil, "BACKGROUND")
+ line2:SetWidth(8)
+ line2:SetHeight(8)
+ line2:SetPoint("BOTTOMRIGHT", -8, 8)
+ line2:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
+ local x = 0.1 * 8/17
+ line2:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
+
+ local sizer_s = CreateFrame("Frame", nil, frame)
+ sizer_s:SetPoint("BOTTOMRIGHT", -25, 0)
+ sizer_s:SetPoint("BOTTOMLEFT")
+ sizer_s:SetHeight(25)
+ sizer_s:EnableMouse(true)
+ sizer_s:SetScript("OnMouseDown", SizerS_OnMouseDown)
+ sizer_s:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
+
+ local sizer_e = CreateFrame("Frame", nil, frame)
+ sizer_e:SetPoint("BOTTOMRIGHT", 0, 25)
+ sizer_e:SetPoint("TOPRIGHT")
+ sizer_e:SetWidth(25)
+ sizer_e:EnableMouse(true)
+ sizer_e:SetScript("OnMouseDown", SizerE_OnMouseDown)
+ sizer_e:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, frame)
+ content:SetPoint("TOPLEFT", 17, -27)
+ content:SetPoint("BOTTOMRIGHT", -17, 40)
+
+ local widget = {
+ localstatus = {},
+ titletext = titletext,
+ statustext = statustext,
+ titlebg = titlebg,
+ sizer_se = sizer_se,
+ sizer_s = sizer_s,
+ sizer_e = sizer_e,
+ content = content,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ closebutton.obj, statusbg.obj = widget, widget
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua
new file mode 100644
index 0000000..f3db7d6
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua
@@ -0,0 +1,103 @@
+--[[-----------------------------------------------------------------------------
+InlineGroup Container
+Simple container widget that creates a visible "box" with an optional title.
+-------------------------------------------------------------------------------]]
+local Type, Version = "InlineGroup", 21
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs = pairs
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetWidth(300)
+ self:SetHeight(100)
+ self:SetTitle("")
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetTitle"] = function(self,title)
+ self.titletext:SetText(title)
+ end,
+
+
+ ["LayoutFinished"] = function(self, width, height)
+ if self.noAutoHeight then return end
+ self:SetHeight((height or 0) + 40)
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ local contentwidth = width - 20
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - 20
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local PaneBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 5, bottom = 3 }
+}
+
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ local titletext = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ titletext:SetPoint("TOPLEFT", 14, 0)
+ titletext:SetPoint("TOPRIGHT", -14, 0)
+ titletext:SetJustifyH("LEFT")
+ titletext:SetHeight(18)
+
+ local border = CreateFrame("Frame", nil, frame)
+ border:SetPoint("TOPLEFT", 0, -17)
+ border:SetPoint("BOTTOMRIGHT", -1, 3)
+ border:SetBackdrop(PaneBackdrop)
+ border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
+ border:SetBackdropBorderColor(0.4, 0.4, 0.4)
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, border)
+ content:SetPoint("TOPLEFT", 10, -10)
+ content:SetPoint("BOTTOMRIGHT", -10, 10)
+
+ local widget = {
+ frame = frame,
+ content = content,
+ titletext = titletext,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua
new file mode 100644
index 0000000..cc4172f
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua
@@ -0,0 +1,215 @@
+--[[-----------------------------------------------------------------------------
+ScrollFrame Container
+Plain container that scrolls its content and doesn't grow in height.
+-------------------------------------------------------------------------------]]
+local Type, Version = "ScrollFrame", 26
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs, assert, type = pairs, assert, type
+local min, max, floor = math.min, math.max, math.floor
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function FixScrollOnUpdate(frame)
+ frame:SetScript("OnUpdate", nil)
+ frame.obj:FixScroll()
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function ScrollFrame_OnMouseWheel(frame, value)
+ frame.obj:MoveScroll(value)
+end
+
+local function ScrollFrame_OnSizeChanged(frame)
+ frame:SetScript("OnUpdate", FixScrollOnUpdate)
+end
+
+local function ScrollBar_OnScrollValueChanged(frame, value)
+ frame.obj:SetScroll(value)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetScroll(0)
+ self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
+ end,
+
+ ["OnRelease"] = function(self)
+ self.status = nil
+ for k in pairs(self.localstatus) do
+ self.localstatus[k] = nil
+ end
+ self.scrollframe:SetPoint("BOTTOMRIGHT")
+ self.scrollbar:Hide()
+ self.scrollBarShown = nil
+ self.content.height, self.content.width, self.content.original_width = nil, nil, nil
+ end,
+
+ ["SetScroll"] = function(self, value)
+ local status = self.status or self.localstatus
+ local viewheight = self.scrollframe:GetHeight()
+ local height = self.content:GetHeight()
+ local offset
+
+ if viewheight > height then
+ offset = 0
+ else
+ offset = floor((height - viewheight) / 1000.0 * value)
+ end
+ self.content:ClearAllPoints()
+ self.content:SetPoint("TOPLEFT", 0, offset)
+ self.content:SetPoint("TOPRIGHT", 0, offset)
+ status.offset = offset
+ status.scrollvalue = value
+ end,
+
+ ["MoveScroll"] = function(self, value)
+ local status = self.status or self.localstatus
+ local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
+
+ if self.scrollBarShown then
+ local diff = height - viewheight
+ local delta = 1
+ if value < 0 then
+ delta = -1
+ end
+ self.scrollbar:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
+ end
+ end,
+
+ ["FixScroll"] = function(self)
+ if self.updateLock then return end
+ self.updateLock = true
+ local status = self.status or self.localstatus
+ local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
+ local offset = status.offset or 0
+ -- Give us a margin of error of 2 pixels to stop some conditions that i would blame on floating point inaccuracys
+ -- No-one is going to miss 2 pixels at the bottom of the frame, anyhow!
+ if viewheight < height + 2 then
+ if self.scrollBarShown then
+ self.scrollBarShown = nil
+ self.scrollbar:Hide()
+ self.scrollbar:SetValue(0)
+ self.scrollframe:SetPoint("BOTTOMRIGHT")
+ if self.content.original_width then
+ self.content.width = self.content.original_width
+ end
+ self:DoLayout()
+ end
+ else
+ if not self.scrollBarShown then
+ self.scrollBarShown = true
+ self.scrollbar:Show()
+ self.scrollframe:SetPoint("BOTTOMRIGHT", -20, 0)
+ if self.content.original_width then
+ self.content.width = self.content.original_width - 20
+ end
+ self:DoLayout()
+ end
+ local value = (offset / (viewheight - height) * 1000)
+ if value > 1000 then value = 1000 end
+ self.scrollbar:SetValue(value)
+ self:SetScroll(value)
+ if value < 1000 then
+ self.content:ClearAllPoints()
+ self.content:SetPoint("TOPLEFT", 0, offset)
+ self.content:SetPoint("TOPRIGHT", 0, offset)
+ status.offset = offset
+ end
+ end
+ self.updateLock = nil
+ end,
+
+ ["LayoutFinished"] = function(self, width, height)
+ self.content:SetHeight(height or 0 + 20)
+
+ -- update the scrollframe
+ self:FixScroll()
+
+ -- schedule another update when everything has "settled"
+ self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
+ end,
+
+ ["SetStatusTable"] = function(self, status)
+ assert(type(status) == "table")
+ self.status = status
+ if not status.scrollvalue then
+ status.scrollvalue = 0
+ end
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ content.width = width - (self.scrollBarShown and 20 or 0)
+ content.original_width = width
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ content.height = height
+ end
+}
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ local num = AceGUI:GetNextWidgetNum(Type)
+
+ local scrollframe = CreateFrame("ScrollFrame", nil, frame)
+ scrollframe:SetPoint("TOPLEFT")
+ scrollframe:SetPoint("BOTTOMRIGHT")
+ scrollframe:EnableMouseWheel(true)
+ scrollframe:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel)
+ scrollframe:SetScript("OnSizeChanged", ScrollFrame_OnSizeChanged)
+
+ local scrollbar = CreateFrame("Slider", ("AceConfigDialogScrollFrame%dScrollBar"):format(num), scrollframe, "UIPanelScrollBarTemplate")
+ scrollbar:SetPoint("TOPLEFT", scrollframe, "TOPRIGHT", 4, -16)
+ scrollbar:SetPoint("BOTTOMLEFT", scrollframe, "BOTTOMRIGHT", 4, 16)
+ scrollbar:SetMinMaxValues(0, 1000)
+ scrollbar:SetValueStep(1)
+ scrollbar:SetValue(0)
+ scrollbar:SetWidth(16)
+ scrollbar:Hide()
+ -- set the script as the last step, so it doesn't fire yet
+ scrollbar:SetScript("OnValueChanged", ScrollBar_OnScrollValueChanged)
+
+ local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
+ scrollbg:SetAllPoints(scrollbar)
+ scrollbg:SetTexture(0, 0, 0, 0.4)
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, scrollframe)
+ content:SetPoint("TOPLEFT")
+ content:SetPoint("TOPRIGHT")
+ content:SetHeight(400)
+ scrollframe:SetScrollChild(content)
+
+ local widget = {
+ localstatus = { scrollvalue = 0 },
+ scrollframe = scrollframe,
+ scrollbar = scrollbar,
+ content = content,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ scrollframe.obj, scrollbar.obj = widget, widget
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua
new file mode 100644
index 0000000..57512c3
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua
@@ -0,0 +1,69 @@
+--[[-----------------------------------------------------------------------------
+SimpleGroup Container
+Simple container widget that just groups widgets.
+-------------------------------------------------------------------------------]]
+local Type, Version = "SimpleGroup", 20
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs = pairs
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetWidth(300)
+ self:SetHeight(100)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["LayoutFinished"] = function(self, width, height)
+ if self.noAutoHeight then return end
+ self:SetHeight(height or 0)
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ content:SetWidth(width)
+ content.width = width
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ content:SetHeight(height)
+ content.height = height
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, frame)
+ content:SetPoint("TOPLEFT")
+ content:SetPoint("BOTTOMRIGHT")
+
+ local widget = {
+ frame = frame,
+ content = content,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua
new file mode 100644
index 0000000..dda3206
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua
@@ -0,0 +1,349 @@
+--[[-----------------------------------------------------------------------------
+TabGroup Container
+Container that uses tabs on top to switch between groups.
+-------------------------------------------------------------------------------]]
+local Type, Version = "TabGroup", 31
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs, ipairs, assert, type, wipe = pairs, ipairs, assert, type, wipe
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame, UIParent = CreateFrame, UIParent
+local _G = _G
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: PanelTemplates_TabResize, PanelTemplates_SetDisabledTabState, PanelTemplates_SelectTab, PanelTemplates_DeselectTab
+
+-- local upvalue storage used by BuildTabs
+local widths = {}
+local rowwidths = {}
+local rowends = {}
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function UpdateTabLook(frame)
+ if frame.disabled then
+ PanelTemplates_SetDisabledTabState(frame)
+ elseif frame.selected then
+ PanelTemplates_SelectTab(frame)
+ else
+ PanelTemplates_DeselectTab(frame)
+ end
+end
+
+local function Tab_SetText(frame, text)
+ frame:_SetText(text)
+ local width = frame.obj.frame.width or frame.obj.frame:GetWidth() or 0
+ PanelTemplates_TabResize(frame, 0, nil, width)
+end
+
+local function Tab_SetSelected(frame, selected)
+ frame.selected = selected
+ UpdateTabLook(frame)
+end
+
+local function Tab_SetDisabled(frame, disabled)
+ frame.disabled = disabled
+ UpdateTabLook(frame)
+end
+
+local function BuildTabsOnUpdate(frame)
+ local self = frame.obj
+ self:BuildTabs()
+ frame:SetScript("OnUpdate", nil)
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Tab_OnClick(frame)
+ if not (frame.selected or frame.disabled) then
+ PlaySound("igCharacterInfoTab")
+ frame.obj:SelectTab(frame.value)
+ end
+end
+
+local function Tab_OnEnter(frame)
+ local self = frame.obj
+ self:Fire("OnTabEnter", self.tabs[frame.id].value, frame)
+end
+
+local function Tab_OnLeave(frame)
+ local self = frame.obj
+ self:Fire("OnTabLeave", self.tabs[frame.id].value, frame)
+end
+
+local function Tab_OnShow(frame)
+ _G[frame:GetName().."HighlightTexture"]:SetWidth(frame:GetTextWidth() + 30)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetTitle()
+ end,
+
+ ["OnRelease"] = function(self)
+ self.status = nil
+ for k in pairs(self.localstatus) do
+ self.localstatus[k] = nil
+ end
+ self.tablist = nil
+ for _, tab in pairs(self.tabs) do
+ tab:Hide()
+ end
+ end,
+
+ ["CreateTab"] = function(self, id)
+ local tabname = ("AceGUITabGroup%dTab%d"):format(self.num, id)
+ local tab = CreateFrame("Button", tabname, self.border, "OptionsFrameTabButtonTemplate")
+ tab.obj = self
+ tab.id = id
+
+ tab.text = _G[tabname .. "Text"]
+ tab.text:ClearAllPoints()
+ tab.text:SetPoint("LEFT", 14, -3)
+ tab.text:SetPoint("RIGHT", -12, -3)
+
+ tab:SetScript("OnClick", Tab_OnClick)
+ tab:SetScript("OnEnter", Tab_OnEnter)
+ tab:SetScript("OnLeave", Tab_OnLeave)
+ tab:SetScript("OnShow", Tab_OnShow)
+
+ tab._SetText = tab.SetText
+ tab.SetText = Tab_SetText
+ tab.SetSelected = Tab_SetSelected
+ tab.SetDisabled = Tab_SetDisabled
+
+ return tab
+ end,
+
+ ["SetTitle"] = function(self, text)
+ self.titletext:SetText(text or "")
+ if text and text ~= "" then
+ self.alignoffset = 25
+ else
+ self.alignoffset = 18
+ end
+ self:BuildTabs()
+ end,
+
+ ["SetStatusTable"] = function(self, status)
+ assert(type(status) == "table")
+ self.status = status
+ end,
+
+ ["SelectTab"] = function(self, value)
+ local status = self.status or self.localstatus
+ local found
+ for i, v in ipairs(self.tabs) do
+ if v.value == value then
+ v:SetSelected(true)
+ found = true
+ else
+ v:SetSelected(false)
+ end
+ end
+ status.selected = value
+ if found then
+ self:Fire("OnGroupSelected",value)
+ end
+ end,
+
+ ["SetTabs"] = function(self, tabs)
+ self.tablist = tabs
+ self:BuildTabs()
+ end,
+
+
+ ["BuildTabs"] = function(self)
+ local hastitle = (self.titletext:GetText() and self.titletext:GetText() ~= "")
+ local tablist = self.tablist
+ local tabs = self.tabs
+
+ if not tablist then return end
+
+ local width = self.frame.width or self.frame:GetWidth() or 0
+
+ wipe(widths)
+ wipe(rowwidths)
+ wipe(rowends)
+
+ --Place Text into tabs and get thier initial width
+ for i, v in ipairs(tablist) do
+ local tab = tabs[i]
+ if not tab then
+ tab = self:CreateTab(i)
+ tabs[i] = tab
+ end
+
+ tab:Show()
+ tab:SetText(v.text)
+ tab:SetDisabled(v.disabled)
+ tab.value = v.value
+
+ widths[i] = tab:GetWidth() - 6 --tabs are anchored 10 pixels from the right side of the previous one to reduce spacing, but add a fixed 4px padding for the text
+ end
+
+ for i = (#tablist)+1, #tabs, 1 do
+ tabs[i]:Hide()
+ end
+
+ --First pass, find the minimum number of rows needed to hold all tabs and the initial tab layout
+ local numtabs = #tablist
+ local numrows = 1
+ local usedwidth = 0
+
+ for i = 1, #tablist do
+ --If this is not the first tab of a row and there isn't room for it
+ if usedwidth ~= 0 and (width - usedwidth - widths[i]) < 0 then
+ rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
+ rowends[numrows] = i - 1
+ numrows = numrows + 1
+ usedwidth = 0
+ end
+ usedwidth = usedwidth + widths[i]
+ end
+ rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
+ rowends[numrows] = #tablist
+
+ --Fix for single tabs being left on the last row, move a tab from the row above if applicable
+ if numrows > 1 then
+ --if the last row has only one tab
+ if rowends[numrows-1] == numtabs-1 then
+ --if there are more than 2 tabs in the 2nd last row
+ if (numrows == 2 and rowends[numrows-1] > 2) or (rowends[numrows] - rowends[numrows-1] > 2) then
+ --move 1 tab from the second last row to the last, if there is enough space
+ if (rowwidths[numrows] + widths[numtabs-1]) <= width then
+ rowends[numrows-1] = rowends[numrows-1] - 1
+ rowwidths[numrows] = rowwidths[numrows] + widths[numtabs-1]
+ rowwidths[numrows-1] = rowwidths[numrows-1] - widths[numtabs-1]
+ end
+ end
+ end
+ end
+
+ --anchor the rows as defined and resize tabs to fill thier row
+ local starttab = 1
+ for row, endtab in ipairs(rowends) do
+ local first = true
+ for tabno = starttab, endtab do
+ local tab = tabs[tabno]
+ tab:ClearAllPoints()
+ if first then
+ tab:SetPoint("TOPLEFT", self.frame, "TOPLEFT", 0, -(hastitle and 14 or 7)-(row-1)*20 )
+ first = false
+ else
+ tab:SetPoint("LEFT", tabs[tabno-1], "RIGHT", -10, 0)
+ end
+ end
+
+ -- equal padding for each tab to fill the available width,
+ -- if the used space is above 75% already
+ -- the 18 pixel is the typical width of a scrollbar, so we can have a tab group inside a scrolling frame,
+ -- and not have the tabs jump around funny when switching between tabs that need scrolling and those that don't
+ local padding = 0
+ if not (numrows == 1 and rowwidths[1] < width*0.75 - 18) then
+ padding = (width - rowwidths[row]) / (endtab - starttab+1)
+ end
+
+ for i = starttab, endtab do
+ PanelTemplates_TabResize(tabs[i], padding + 4, nil, width)
+ end
+ starttab = endtab + 1
+ end
+
+ self.borderoffset = (hastitle and 17 or 10)+((numrows)*20)
+ self.border:SetPoint("TOPLEFT", 1, -self.borderoffset)
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ local contentwidth = width - 60
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ self:BuildTabs(self)
+ self.frame:SetScript("OnUpdate", BuildTabsOnUpdate)
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - (self.borderoffset + 23)
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end,
+
+ ["LayoutFinished"] = function(self, width, height)
+ if self.noAutoHeight then return end
+ self:SetHeight((height or 0) + (self.borderoffset + 23))
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local PaneBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 5, bottom = 3 }
+}
+
+local function Constructor()
+ local num = AceGUI:GetNextWidgetNum(Type)
+ local frame = CreateFrame("Frame",nil,UIParent)
+ frame:SetHeight(100)
+ frame:SetWidth(100)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ local titletext = frame:CreateFontString(nil,"OVERLAY","GameFontNormal")
+ titletext:SetPoint("TOPLEFT", 14, 0)
+ titletext:SetPoint("TOPRIGHT", -14, 0)
+ titletext:SetJustifyH("LEFT")
+ titletext:SetHeight(18)
+ titletext:SetText("")
+
+ local border = CreateFrame("Frame", nil, frame)
+ border:SetPoint("TOPLEFT", 1, -27)
+ border:SetPoint("BOTTOMRIGHT", -1, 3)
+ border:SetBackdrop(PaneBackdrop)
+ border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
+ border:SetBackdropBorderColor(0.4, 0.4, 0.4)
+
+ local content = CreateFrame("Frame", nil, border)
+ content:SetPoint("TOPLEFT", 10, -7)
+ content:SetPoint("BOTTOMRIGHT", -10, 7)
+
+ local widget = {
+ num = num,
+ frame = frame,
+ localstatus = {},
+ alignoffset = 18,
+ titletext = titletext,
+ border = border,
+ borderoffset = 27,
+ tabs = {},
+ content = content,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua
new file mode 100644
index 0000000..a05741f
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua
@@ -0,0 +1,705 @@
+--[[-----------------------------------------------------------------------------
+TreeGroup Container
+Container that uses a tree control to switch between groups.
+-------------------------------------------------------------------------------]]
+local Type, Version = "TreeGroup", 43
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type
+local math_min, math_max, floor = math.min, math.max, floor
+local select, tremove, unpack, tconcat = select, table.remove, unpack, table.concat
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: GameTooltip, FONT_COLOR_CODE_CLOSE
+
+-- Recycling functions
+local new, del
+do
+ local pool = setmetatable({},{__mode='k'})
+ function new()
+ local t = next(pool)
+ if t then
+ pool[t] = nil
+ return t
+ else
+ return {}
+ end
+ end
+ function del(t)
+ for k in pairs(t) do
+ t[k] = nil
+ end
+ pool[t] = true
+ end
+end
+
+local DEFAULT_TREE_WIDTH = 175
+local DEFAULT_TREE_SIZABLE = true
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function GetButtonUniqueValue(line)
+ local parent = line.parent
+ if parent and parent.value then
+ return GetButtonUniqueValue(parent).."\001"..line.value
+ else
+ return line.value
+ end
+end
+
+local function UpdateButton(button, treeline, selected, canExpand, isExpanded)
+ local self = button.obj
+ local toggle = button.toggle
+ local text = treeline.text or ""
+ local icon = treeline.icon
+ local iconCoords = treeline.iconCoords
+ local level = treeline.level
+ local value = treeline.value
+ local uniquevalue = treeline.uniquevalue
+ local disabled = treeline.disabled
+
+ button.treeline = treeline
+ button.value = value
+ button.uniquevalue = uniquevalue
+ if selected then
+ button:LockHighlight()
+ button.selected = true
+ else
+ button:UnlockHighlight()
+ button.selected = false
+ end
+ button.level = level
+ if ( level == 1 ) then
+ button:SetNormalFontObject("GameFontNormal")
+ button:SetHighlightFontObject("GameFontHighlight")
+ button.text:SetPoint("LEFT", (icon and 16 or 0) + 8, 2)
+ else
+ button:SetNormalFontObject("GameFontHighlightSmall")
+ button:SetHighlightFontObject("GameFontHighlightSmall")
+ button.text:SetPoint("LEFT", (icon and 16 or 0) + 8 * level, 2)
+ end
+
+ if disabled then
+ button:EnableMouse(false)
+ button.text:SetText("|cff808080"..text..FONT_COLOR_CODE_CLOSE)
+ else
+ button.text:SetText(text)
+ button:EnableMouse(true)
+ end
+
+ if icon then
+ button.icon:SetTexture(icon)
+ button.icon:SetPoint("LEFT", 8 * level, (level == 1) and 0 or 1)
+ else
+ button.icon:SetTexture(nil)
+ end
+
+ if iconCoords then
+ button.icon:SetTexCoord(unpack(iconCoords))
+ else
+ button.icon:SetTexCoord(0, 1, 0, 1)
+ end
+
+ if canExpand then
+ if not isExpanded then
+ toggle:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-UP")
+ toggle:SetPushedTexture("Interface\\Buttons\\UI-PlusButton-DOWN")
+ else
+ toggle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP")
+ toggle:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-DOWN")
+ end
+ toggle:Show()
+ else
+ toggle:Hide()
+ end
+end
+
+local function ShouldDisplayLevel(tree)
+ local result = false
+ for k, v in ipairs(tree) do
+ if v.children == nil and v.visible ~= false then
+ result = true
+ elseif v.children then
+ result = result or ShouldDisplayLevel(v.children)
+ end
+ if result then return result end
+ end
+ return false
+end
+
+local function addLine(self, v, tree, level, parent)
+ local line = new()
+ line.value = v.value
+ line.text = v.text
+ line.icon = v.icon
+ line.iconCoords = v.iconCoords
+ line.disabled = v.disabled
+ line.tree = tree
+ line.level = level
+ line.parent = parent
+ line.visible = v.visible
+ line.uniquevalue = GetButtonUniqueValue(line)
+ if v.children then
+ line.hasChildren = true
+ else
+ line.hasChildren = nil
+ end
+ self.lines[#self.lines+1] = line
+ return line
+end
+
+--fire an update after one frame to catch the treeframes height
+local function FirstFrameUpdate(frame)
+ local self = frame.obj
+ frame:SetScript("OnUpdate", nil)
+ self:RefreshTree()
+end
+
+local function BuildUniqueValue(...)
+ local n = select('#', ...)
+ if n == 1 then
+ return ...
+ else
+ return (...).."\001"..BuildUniqueValue(select(2,...))
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Expand_OnClick(frame)
+ local button = frame.button
+ local self = button.obj
+ local status = (self.status or self.localstatus).groups
+ status[button.uniquevalue] = not status[button.uniquevalue]
+ self:RefreshTree()
+end
+
+local function Button_OnClick(frame)
+ local self = frame.obj
+ self:Fire("OnClick", frame.uniquevalue, frame.selected)
+ if not frame.selected then
+ self:SetSelected(frame.uniquevalue)
+ frame.selected = true
+ frame:LockHighlight()
+ self:RefreshTree()
+ end
+ AceGUI:ClearFocus()
+end
+
+local function Button_OnDoubleClick(button)
+ local self = button.obj
+ local status = (self.status or self.localstatus).groups
+ status[button.uniquevalue] = not status[button.uniquevalue]
+ self:RefreshTree()
+end
+
+local function Button_OnEnter(frame)
+ local self = frame.obj
+ self:Fire("OnButtonEnter", frame.uniquevalue, frame)
+
+ if self.enabletooltips then
+ GameTooltip:SetOwner(frame, "ANCHOR_NONE")
+ GameTooltip:SetPoint("LEFT",frame,"RIGHT")
+ GameTooltip:SetText(frame.text:GetText() or "", 1, .82, 0, 1)
+
+ GameTooltip:Show()
+ end
+end
+
+local function Button_OnLeave(frame)
+ local self = frame.obj
+ self:Fire("OnButtonLeave", frame.uniquevalue, frame)
+
+ if self.enabletooltips then
+ GameTooltip:Hide()
+ end
+end
+
+local function OnScrollValueChanged(frame, value)
+ if frame.obj.noupdate then return end
+ local self = frame.obj
+ local status = self.status or self.localstatus
+ status.scrollvalue = value
+ self:RefreshTree()
+ AceGUI:ClearFocus()
+end
+
+local function Tree_OnSizeChanged(frame)
+ frame.obj:RefreshTree()
+end
+
+local function Tree_OnMouseWheel(frame, delta)
+ local self = frame.obj
+ if self.showscroll then
+ local scrollbar = self.scrollbar
+ local min, max = scrollbar:GetMinMaxValues()
+ local value = scrollbar:GetValue()
+ local newvalue = math_min(max,math_max(min,value - delta))
+ if value ~= newvalue then
+ scrollbar:SetValue(newvalue)
+ end
+ end
+end
+
+local function Dragger_OnLeave(frame)
+ frame:SetBackdropColor(1, 1, 1, 0)
+end
+
+local function Dragger_OnEnter(frame)
+ frame:SetBackdropColor(1, 1, 1, 0.8)
+end
+
+local function Dragger_OnMouseDown(frame)
+ local treeframe = frame:GetParent()
+ treeframe:StartSizing("RIGHT")
+end
+
+local function Dragger_OnMouseUp(frame)
+ local treeframe = frame:GetParent()
+ local self = treeframe.obj
+ local treeframeParent = treeframe:GetParent()
+ treeframe:StopMovingOrSizing()
+ --treeframe:SetScript("OnUpdate", nil)
+ treeframe:SetUserPlaced(false)
+ --Without this :GetHeight will get stuck on the current height, causing the tree contents to not resize
+ treeframe:SetHeight(0)
+ treeframe:ClearAllPoints()
+ treeframe:SetPoint("TOPLEFT", treeframeParent, "TOPLEFT",0,0)
+ treeframe:SetPoint("BOTTOMLEFT", treeframeParent, "BOTTOMLEFT",0,0)
+
+ local status = self.status or self.localstatus
+ status.treewidth = treeframe:GetWidth()
+
+ treeframe.obj:Fire("OnTreeResize",treeframe:GetWidth())
+ -- recalculate the content width
+ treeframe.obj:OnWidthSet(status.fullwidth)
+ -- update the layout of the content
+ treeframe.obj:DoLayout()
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetTreeWidth(DEFAULT_TREE_WIDTH, DEFAULT_TREE_SIZABLE)
+ self:EnableButtonTooltips(true)
+ end,
+
+ ["OnRelease"] = function(self)
+ self.status = nil
+ for k, v in pairs(self.localstatus) do
+ if k == "groups" then
+ for k2 in pairs(v) do
+ v[k2] = nil
+ end
+ else
+ self.localstatus[k] = nil
+ end
+ end
+ self.localstatus.scrollvalue = 0
+ self.localstatus.treewidth = DEFAULT_TREE_WIDTH
+ self.localstatus.treesizable = DEFAULT_TREE_SIZABLE
+ end,
+
+ ["EnableButtonTooltips"] = function(self, enable)
+ self.enabletooltips = enable
+ end,
+
+ ["CreateButton"] = function(self)
+ local num = AceGUI:GetNextWidgetNum("TreeGroupButton")
+ local button = CreateFrame("Button", ("AceGUI30TreeButton%d"):format(num), self.treeframe, "OptionsListButtonTemplate")
+ button.obj = self
+
+ local icon = button:CreateTexture(nil, "OVERLAY")
+ icon:SetWidth(14)
+ icon:SetHeight(14)
+ button.icon = icon
+
+ button:SetScript("OnClick",Button_OnClick)
+ button:SetScript("OnDoubleClick", Button_OnDoubleClick)
+ button:SetScript("OnEnter",Button_OnEnter)
+ button:SetScript("OnLeave",Button_OnLeave)
+
+ button.toggle.button = button
+ button.toggle:SetScript("OnClick",Expand_OnClick)
+
+ button.text:SetHeight(14) -- Prevents text wrapping
+
+ return button
+ end,
+
+ ["SetStatusTable"] = function(self, status)
+ assert(type(status) == "table")
+ self.status = status
+ if not status.groups then
+ status.groups = {}
+ end
+ if not status.scrollvalue then
+ status.scrollvalue = 0
+ end
+ if not status.treewidth then
+ status.treewidth = DEFAULT_TREE_WIDTH
+ end
+ if status.treesizable == nil then
+ status.treesizable = DEFAULT_TREE_SIZABLE
+ end
+ self:SetTreeWidth(status.treewidth,status.treesizable)
+ self:RefreshTree()
+ end,
+
+ --sets the tree to be displayed
+ ["SetTree"] = function(self, tree, filter)
+ self.filter = filter
+ if tree then
+ assert(type(tree) == "table")
+ end
+ self.tree = tree
+ self:RefreshTree()
+ end,
+
+ ["BuildLevel"] = function(self, tree, level, parent)
+ local groups = (self.status or self.localstatus).groups
+
+ for i, v in ipairs(tree) do
+ if v.children then
+ if not self.filter or ShouldDisplayLevel(v.children) then
+ local line = addLine(self, v, tree, level, parent)
+ if groups[line.uniquevalue] then
+ self:BuildLevel(v.children, level+1, line)
+ end
+ end
+ elseif v.visible ~= false or not self.filter then
+ addLine(self, v, tree, level, parent)
+ end
+ end
+ end,
+
+ ["RefreshTree"] = function(self,scrollToSelection)
+ local buttons = self.buttons
+ local lines = self.lines
+
+ for i, v in ipairs(buttons) do
+ v:Hide()
+ end
+ while lines[1] do
+ local t = tremove(lines)
+ for k in pairs(t) do
+ t[k] = nil
+ end
+ del(t)
+ end
+
+ if not self.tree then return end
+ --Build the list of visible entries from the tree and status tables
+ local status = self.status or self.localstatus
+ local groupstatus = status.groups
+ local tree = self.tree
+
+ local treeframe = self.treeframe
+
+ status.scrollToSelection = status.scrollToSelection or scrollToSelection -- needs to be cached in case the control hasn't been drawn yet (code bails out below)
+
+ self:BuildLevel(tree, 1)
+
+ local numlines = #lines
+
+ local maxlines = (floor(((self.treeframe:GetHeight()or 0) - 20 ) / 18))
+ if maxlines <= 0 then return end
+
+ local first, last
+
+ scrollToSelection = status.scrollToSelection
+ status.scrollToSelection = nil
+
+ if numlines <= maxlines then
+ --the whole tree fits in the frame
+ status.scrollvalue = 0
+ self:ShowScroll(false)
+ first, last = 1, numlines
+ else
+ self:ShowScroll(true)
+ --scrolling will be needed
+ self.noupdate = true
+ self.scrollbar:SetMinMaxValues(0, numlines - maxlines)
+ --check if we are scrolled down too far
+ if numlines - status.scrollvalue < maxlines then
+ status.scrollvalue = numlines - maxlines
+ end
+ self.noupdate = nil
+ first, last = status.scrollvalue+1, status.scrollvalue + maxlines
+ --show selection?
+ if scrollToSelection and status.selected then
+ local show
+ for i,line in ipairs(lines) do -- find the line number
+ if line.uniquevalue==status.selected then
+ show=i
+ end
+ end
+ if not show then
+ -- selection was deleted or something?
+ elseif show>=first and show<=last then
+ -- all good
+ else
+ -- scrolling needed!
+ if show 100 and status.treewidth > maxtreewidth then
+ self:SetTreeWidth(maxtreewidth, status.treesizable)
+ end
+ treeframe:SetMaxResize(maxtreewidth, 1600)
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - 20
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end,
+
+ ["SetTreeWidth"] = function(self, treewidth, resizable)
+ if not resizable then
+ if type(treewidth) == 'number' then
+ resizable = false
+ elseif type(treewidth) == 'boolean' then
+ resizable = treewidth
+ treewidth = DEFAULT_TREE_WIDTH
+ else
+ resizable = false
+ treewidth = DEFAULT_TREE_WIDTH
+ end
+ end
+ self.treeframe:SetWidth(treewidth)
+ self.dragger:EnableMouse(resizable)
+
+ local status = self.status or self.localstatus
+ status.treewidth = treewidth
+ status.treesizable = resizable
+
+ -- recalculate the content width
+ if status.fullwidth then
+ self:OnWidthSet(status.fullwidth)
+ end
+ end,
+
+ ["GetTreeWidth"] = function(self)
+ local status = self.status or self.localstatus
+ return status.treewidth or DEFAULT_TREE_WIDTH
+ end,
+
+ ["LayoutFinished"] = function(self, width, height)
+ if self.noAutoHeight then return end
+ self:SetHeight((height or 0) + 20)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local PaneBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 5, bottom = 3 }
+}
+
+local DraggerBackdrop = {
+ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+ edgeFile = nil,
+ tile = true, tileSize = 16, edgeSize = 0,
+ insets = { left = 3, right = 3, top = 7, bottom = 7 }
+}
+
+local function Constructor()
+ local num = AceGUI:GetNextWidgetNum(Type)
+ local frame = CreateFrame("Frame", nil, UIParent)
+
+ local treeframe = CreateFrame("Frame", nil, frame)
+ treeframe:SetPoint("TOPLEFT")
+ treeframe:SetPoint("BOTTOMLEFT")
+ treeframe:SetWidth(DEFAULT_TREE_WIDTH)
+ treeframe:EnableMouseWheel(true)
+ treeframe:SetBackdrop(PaneBackdrop)
+ treeframe:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
+ treeframe:SetBackdropBorderColor(0.4, 0.4, 0.4)
+ treeframe:SetResizable(true)
+ treeframe:SetMinResize(100, 1)
+ treeframe:SetMaxResize(400, 1600)
+ treeframe:SetScript("OnUpdate", FirstFrameUpdate)
+ treeframe:SetScript("OnSizeChanged", Tree_OnSizeChanged)
+ treeframe:SetScript("OnMouseWheel", Tree_OnMouseWheel)
+
+ local dragger = CreateFrame("Frame", nil, treeframe)
+ dragger:SetWidth(8)
+ dragger:SetPoint("TOP", treeframe, "TOPRIGHT")
+ dragger:SetPoint("BOTTOM", treeframe, "BOTTOMRIGHT")
+ dragger:SetBackdrop(DraggerBackdrop)
+ dragger:SetBackdropColor(1, 1, 1, 0)
+ dragger:SetScript("OnEnter", Dragger_OnEnter)
+ dragger:SetScript("OnLeave", Dragger_OnLeave)
+ dragger:SetScript("OnMouseDown", Dragger_OnMouseDown)
+ dragger:SetScript("OnMouseUp", Dragger_OnMouseUp)
+
+ local scrollbar = CreateFrame("Slider", ("AceConfigDialogTreeGroup%dScrollBar"):format(num), treeframe, "UIPanelScrollBarTemplate")
+ scrollbar:SetScript("OnValueChanged", nil)
+ scrollbar:SetPoint("TOPRIGHT", -10, -26)
+ scrollbar:SetPoint("BOTTOMRIGHT", -10, 26)
+ scrollbar:SetMinMaxValues(0,0)
+ scrollbar:SetValueStep(1)
+ scrollbar:SetValue(0)
+ scrollbar:SetWidth(16)
+ scrollbar:SetScript("OnValueChanged", OnScrollValueChanged)
+
+ local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
+ scrollbg:SetAllPoints(scrollbar)
+ scrollbg:SetTexture(0,0,0,0.4)
+
+ local border = CreateFrame("Frame",nil,frame)
+ border:SetPoint("TOPLEFT", treeframe, "TOPRIGHT")
+ border:SetPoint("BOTTOMRIGHT")
+ border:SetBackdrop(PaneBackdrop)
+ border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
+ border:SetBackdropBorderColor(0.4, 0.4, 0.4)
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, border)
+ content:SetPoint("TOPLEFT", 10, -10)
+ content:SetPoint("BOTTOMRIGHT", -10, 10)
+
+ local widget = {
+ frame = frame,
+ lines = {},
+ levels = {},
+ buttons = {},
+ hasChildren = {},
+ localstatus = { groups = {}, scrollvalue = 0 },
+ filter = false,
+ treeframe = treeframe,
+ dragger = dragger,
+ scrollbar = scrollbar,
+ border = border,
+ content = content,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ treeframe.obj, dragger.obj, scrollbar.obj = widget, widget, widget
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-Window.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-Window.lua
new file mode 100644
index 0000000..f8e0141
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIContainer-Window.lua
@@ -0,0 +1,336 @@
+local AceGUI = LibStub("AceGUI-3.0")
+
+-- Lua APIs
+local pairs, assert, type = pairs, assert, type
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: GameFontNormal
+
+----------------
+-- Main Frame --
+----------------
+--[[
+ Events :
+ OnClose
+
+]]
+do
+ local Type = "Window"
+ local Version = 5
+
+ local function frameOnShow(this)
+ this.obj:Fire("OnShow")
+ end
+
+ local function frameOnClose(this)
+ this.obj:Fire("OnClose")
+ end
+
+ local function closeOnClick(this)
+ PlaySound("gsTitleOptionExit")
+ this.obj:Hide()
+ end
+
+ local function frameOnMouseDown(this)
+ AceGUI:ClearFocus()
+ end
+
+ local function titleOnMouseDown(this)
+ this:GetParent():StartMoving()
+ AceGUI:ClearFocus()
+ end
+
+ local function frameOnMouseUp(this)
+ local frame = this:GetParent()
+ frame:StopMovingOrSizing()
+ local self = frame.obj
+ local status = self.status or self.localstatus
+ status.width = frame:GetWidth()
+ status.height = frame:GetHeight()
+ status.top = frame:GetTop()
+ status.left = frame:GetLeft()
+ end
+
+ local function sizerseOnMouseDown(this)
+ this:GetParent():StartSizing("BOTTOMRIGHT")
+ AceGUI:ClearFocus()
+ end
+
+ local function sizersOnMouseDown(this)
+ this:GetParent():StartSizing("BOTTOM")
+ AceGUI:ClearFocus()
+ end
+
+ local function sizereOnMouseDown(this)
+ this:GetParent():StartSizing("RIGHT")
+ AceGUI:ClearFocus()
+ end
+
+ local function sizerOnMouseUp(this)
+ this:GetParent():StopMovingOrSizing()
+ end
+
+ local function SetTitle(self,title)
+ self.titletext:SetText(title)
+ end
+
+ local function SetStatusText(self,text)
+ -- self.statustext:SetText(text)
+ end
+
+ local function Hide(self)
+ self.frame:Hide()
+ end
+
+ local function Show(self)
+ self.frame:Show()
+ end
+
+ local function OnAcquire(self)
+ self.frame:SetParent(UIParent)
+ self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
+ self:ApplyStatus()
+ self:EnableResize(true)
+ self:Show()
+ end
+
+ local function OnRelease(self)
+ self.status = nil
+ for k in pairs(self.localstatus) do
+ self.localstatus[k] = nil
+ end
+ end
+
+ -- called to set an external table to store status in
+ local function SetStatusTable(self, status)
+ assert(type(status) == "table")
+ self.status = status
+ self:ApplyStatus()
+ end
+
+ local function ApplyStatus(self)
+ local status = self.status or self.localstatus
+ local frame = self.frame
+ self:SetWidth(status.width or 700)
+ self:SetHeight(status.height or 500)
+ if status.top and status.left then
+ frame:SetPoint("TOP",UIParent,"BOTTOM",0,status.top)
+ frame:SetPoint("LEFT",UIParent,"LEFT",status.left,0)
+ else
+ frame:SetPoint("CENTER",UIParent,"CENTER")
+ end
+ end
+
+ local function OnWidthSet(self, width)
+ local content = self.content
+ local contentwidth = width - 34
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ end
+
+
+ local function OnHeightSet(self, height)
+ local content = self.content
+ local contentheight = height - 57
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end
+
+ local function EnableResize(self, state)
+ local func = state and "Show" or "Hide"
+ self.sizer_se[func](self.sizer_se)
+ self.sizer_s[func](self.sizer_s)
+ self.sizer_e[func](self.sizer_e)
+ end
+
+ local function Constructor()
+ local frame = CreateFrame("Frame",nil,UIParent)
+ local self = {}
+ self.type = "Window"
+
+ self.Hide = Hide
+ self.Show = Show
+ self.SetTitle = SetTitle
+ self.OnRelease = OnRelease
+ self.OnAcquire = OnAcquire
+ self.SetStatusText = SetStatusText
+ self.SetStatusTable = SetStatusTable
+ self.ApplyStatus = ApplyStatus
+ self.OnWidthSet = OnWidthSet
+ self.OnHeightSet = OnHeightSet
+ self.EnableResize = EnableResize
+
+ self.localstatus = {}
+
+ self.frame = frame
+ frame.obj = self
+ frame:SetWidth(700)
+ frame:SetHeight(500)
+ frame:SetPoint("CENTER",UIParent,"CENTER",0,0)
+ frame:EnableMouse()
+ frame:SetMovable(true)
+ frame:SetResizable(true)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+ frame:SetScript("OnMouseDown", frameOnMouseDown)
+
+ frame:SetScript("OnShow",frameOnShow)
+ frame:SetScript("OnHide",frameOnClose)
+ frame:SetMinResize(240,240)
+ frame:SetToplevel(true)
+
+ local titlebg = frame:CreateTexture(nil, "BACKGROUND")
+ titlebg:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Title-Background]])
+ titlebg:SetPoint("TOPLEFT", 9, -6)
+ titlebg:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", -28, -24)
+
+ local dialogbg = frame:CreateTexture(nil, "BACKGROUND")
+ dialogbg:SetTexture([[Interface\Tooltips\UI-Tooltip-Background]])
+ dialogbg:SetPoint("TOPLEFT", 8, -24)
+ dialogbg:SetPoint("BOTTOMRIGHT", -6, 8)
+ dialogbg:SetVertexColor(0, 0, 0, .75)
+
+ local topleft = frame:CreateTexture(nil, "BORDER")
+ topleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
+ topleft:SetWidth(64)
+ topleft:SetHeight(64)
+ topleft:SetPoint("TOPLEFT")
+ topleft:SetTexCoord(0.501953125, 0.625, 0, 1)
+
+ local topright = frame:CreateTexture(nil, "BORDER")
+ topright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
+ topright:SetWidth(64)
+ topright:SetHeight(64)
+ topright:SetPoint("TOPRIGHT")
+ topright:SetTexCoord(0.625, 0.75, 0, 1)
+
+ local top = frame:CreateTexture(nil, "BORDER")
+ top:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
+ top:SetHeight(64)
+ top:SetPoint("TOPLEFT", topleft, "TOPRIGHT")
+ top:SetPoint("TOPRIGHT", topright, "TOPLEFT")
+ top:SetTexCoord(0.25, 0.369140625, 0, 1)
+
+ local bottomleft = frame:CreateTexture(nil, "BORDER")
+ bottomleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
+ bottomleft:SetWidth(64)
+ bottomleft:SetHeight(64)
+ bottomleft:SetPoint("BOTTOMLEFT")
+ bottomleft:SetTexCoord(0.751953125, 0.875, 0, 1)
+
+ local bottomright = frame:CreateTexture(nil, "BORDER")
+ bottomright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
+ bottomright:SetWidth(64)
+ bottomright:SetHeight(64)
+ bottomright:SetPoint("BOTTOMRIGHT")
+ bottomright:SetTexCoord(0.875, 1, 0, 1)
+
+ local bottom = frame:CreateTexture(nil, "BORDER")
+ bottom:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
+ bottom:SetHeight(64)
+ bottom:SetPoint("BOTTOMLEFT", bottomleft, "BOTTOMRIGHT")
+ bottom:SetPoint("BOTTOMRIGHT", bottomright, "BOTTOMLEFT")
+ bottom:SetTexCoord(0.376953125, 0.498046875, 0, 1)
+
+ local left = frame:CreateTexture(nil, "BORDER")
+ left:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
+ left:SetWidth(64)
+ left:SetPoint("TOPLEFT", topleft, "BOTTOMLEFT")
+ left:SetPoint("BOTTOMLEFT", bottomleft, "TOPLEFT")
+ left:SetTexCoord(0.001953125, 0.125, 0, 1)
+
+ local right = frame:CreateTexture(nil, "BORDER")
+ right:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
+ right:SetWidth(64)
+ right:SetPoint("TOPRIGHT", topright, "BOTTOMRIGHT")
+ right:SetPoint("BOTTOMRIGHT", bottomright, "TOPRIGHT")
+ right:SetTexCoord(0.1171875, 0.2421875, 0, 1)
+
+ local close = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
+ close:SetPoint("TOPRIGHT", 2, 1)
+ close:SetScript("OnClick", closeOnClick)
+ self.closebutton = close
+ close.obj = self
+
+ local titletext = frame:CreateFontString(nil, "ARTWORK")
+ titletext:SetFontObject(GameFontNormal)
+ titletext:SetPoint("TOPLEFT", 12, -8)
+ titletext:SetPoint("TOPRIGHT", -32, -8)
+ self.titletext = titletext
+
+ local title = CreateFrame("Button", nil, frame)
+ title:SetPoint("TOPLEFT", titlebg)
+ title:SetPoint("BOTTOMRIGHT", titlebg)
+ title:EnableMouse()
+ title:SetScript("OnMouseDown",titleOnMouseDown)
+ title:SetScript("OnMouseUp", frameOnMouseUp)
+ self.title = title
+
+ local sizer_se = CreateFrame("Frame",nil,frame)
+ sizer_se:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,0)
+ sizer_se:SetWidth(25)
+ sizer_se:SetHeight(25)
+ sizer_se:EnableMouse()
+ sizer_se:SetScript("OnMouseDown",sizerseOnMouseDown)
+ sizer_se:SetScript("OnMouseUp", sizerOnMouseUp)
+ self.sizer_se = sizer_se
+
+ local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
+ self.line1 = line1
+ line1:SetWidth(14)
+ line1:SetHeight(14)
+ line1:SetPoint("BOTTOMRIGHT", -8, 8)
+ line1:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
+ local x = 0.1 * 14/17
+ line1:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
+
+ local line2 = sizer_se:CreateTexture(nil, "BACKGROUND")
+ self.line2 = line2
+ line2:SetWidth(8)
+ line2:SetHeight(8)
+ line2:SetPoint("BOTTOMRIGHT", -8, 8)
+ line2:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
+ local x = 0.1 * 8/17
+ line2:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
+
+ local sizer_s = CreateFrame("Frame",nil,frame)
+ sizer_s:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-25,0)
+ sizer_s:SetPoint("BOTTOMLEFT",frame,"BOTTOMLEFT",0,0)
+ sizer_s:SetHeight(25)
+ sizer_s:EnableMouse()
+ sizer_s:SetScript("OnMouseDown",sizersOnMouseDown)
+ sizer_s:SetScript("OnMouseUp", sizerOnMouseUp)
+ self.sizer_s = sizer_s
+
+ local sizer_e = CreateFrame("Frame",nil,frame)
+ sizer_e:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,25)
+ sizer_e:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
+ sizer_e:SetWidth(25)
+ sizer_e:EnableMouse()
+ sizer_e:SetScript("OnMouseDown",sizereOnMouseDown)
+ sizer_e:SetScript("OnMouseUp", sizerOnMouseUp)
+ self.sizer_e = sizer_e
+
+ --Container Support
+ local content = CreateFrame("Frame",nil,frame)
+ self.content = content
+ content.obj = self
+ content:SetPoint("TOPLEFT",frame,"TOPLEFT",12,-32)
+ content:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-12,13)
+
+ AceGUI:RegisterAsContainer(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(Type,Constructor,Version)
+end
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Button-ElvUI.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Button-ElvUI.lua
new file mode 100644
index 0000000..bb129cf
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Button-ElvUI.lua
@@ -0,0 +1,179 @@
+--[[-----------------------------------------------------------------------------
+Button Widget (Modified to change text color on SetDisabled method)
+Graphical Button.
+-------------------------------------------------------------------------------]]
+local Type, Version = "Button-ElvUI", 2
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs = pairs
+
+-- WoW APIs
+local _G = _G
+local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent
+local IsShiftKeyDown = IsShiftKeyDown
+-- GLOBALS: GameTooltip, ElvUI
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local dragdropButton
+local function lockTooltip()
+ GameTooltip:SetOwner(UIParent, "ANCHOR_CURSOR")
+ GameTooltip:SetText(" ")
+ GameTooltip:Show()
+end
+local function dragdrop_OnMouseDown(frame, ...)
+ if frame.obj.dragOnMouseDown then
+ dragdropButton.mouseDownFrame = frame
+ dragdropButton:SetText(frame.obj.value or "Unknown")
+ dragdropButton:SetSize(frame:GetSize())
+ frame.obj.dragOnMouseDown(frame, ...)
+ end
+end
+local function dragdrop_OnMouseUp(frame, ...)
+ if frame.obj.dragOnMouseUp then
+ frame:SetAlpha(1)
+ GameTooltip:Hide()
+ dragdropButton:Hide()
+ if dragdropButton.enteredFrame and dragdropButton.enteredFrame ~= frame and dragdropButton.enteredFrame:IsMouseOver() then
+ frame.obj.dragOnMouseUp(frame, ...)
+ frame.obj.ActivateMultiControl(frame.obj, ...)
+ end
+ dragdropButton.enteredFrame = nil
+ dragdropButton.mouseDownFrame = nil
+ end
+end
+local function dragdrop_OnLeave(frame, ...)
+ if frame.obj.dragOnLeave then
+ if dragdropButton.mouseDownFrame then
+ lockTooltip()
+ end
+ if frame == dragdropButton.mouseDownFrame then
+ frame:SetAlpha(0)
+ dragdropButton:Show()
+ frame.obj.dragOnLeave(frame, ...)
+ end
+ end
+end
+local function dragdrop_OnEnter(frame, ...)
+ if frame.obj.dragOnEnter and dragdropButton:IsShown() then
+ dragdropButton.enteredFrame = frame
+ lockTooltip()
+ frame.obj.dragOnEnter(frame, ...)
+ end
+end
+local function dragdrop_OnClick(frame, ...)
+ local button = ...
+ if frame.obj.dragOnClick and button == "RightButton" then
+ frame.obj.dragOnClick(frame, ...)
+ frame.obj.ActivateMultiControl(frame.obj, ...)
+ elseif frame.obj.stateSwitchOnClick and (button == "LeftButton") and IsShiftKeyDown() then
+ frame.obj.stateSwitchOnClick(frame, ...)
+ frame.obj.ActivateMultiControl(frame.obj, ...)
+ end
+end
+
+local function Button_OnClick(frame, ...)
+ AceGUI:ClearFocus()
+ PlaySound("igMainMenuOption")
+ frame.obj:Fire("OnClick", ...)
+end
+
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ -- restore default values
+ self:SetHeight(24)
+ self:SetWidth(200)
+ self:SetDisabled(false)
+ self:SetAutoWidth(false)
+ self:SetText()
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetText"] = function(self, text)
+ self.text:SetText(text)
+ if self.autoWidth then
+ self:SetWidth(self.text:GetStringWidth() + 30)
+ end
+ end,
+
+ ["SetAutoWidth"] = function(self, autoWidth)
+ self.autoWidth = autoWidth
+ if self.autoWidth then
+ self:SetWidth(self.text:GetStringWidth() + 30)
+ end
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ self.text:SetTextColor(0.4, 0.4, 0.4)
+ else
+ self.frame:Enable()
+ self.text:SetTextColor(1, 0.82, 0)
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local name = "AceGUI30Button" .. AceGUI:GetNextWidgetNum(Type)
+ local frame = CreateFrame("Button", name, UIParent, "UIPanelButtonTemplate2")
+ frame:Hide()
+ frame:EnableMouse(true)
+ frame:RegisterForClicks("AnyUp")
+ frame:SetScript("OnClick", Button_OnClick)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+
+ -- dragdrop
+ if not dragdropButton then
+ dragdropButton = CreateFrame("Button", "ElvUIAceGUI30DragDropButton", UIParent, "UIPanelButtonTemplate")
+ dragdropButton:SetFrameStrata("TOOLTIP")
+ dragdropButton:SetFrameLevel(5)
+ dragdropButton:SetPoint('BOTTOM', GameTooltip, "BOTTOM", 0, 10)
+ dragdropButton:Hide()
+ ElvUI[1]:GetModule('Skins'):HandleButton(dragdropButton)
+ end
+ frame:HookScript("OnClick", dragdrop_OnClick)
+ frame:HookScript("OnEnter", dragdrop_OnEnter)
+ frame:HookScript("OnLeave", dragdrop_OnLeave)
+ frame:HookScript("OnMouseUp", dragdrop_OnMouseUp)
+ frame:HookScript("OnMouseDown", dragdrop_OnMouseDown)
+
+ local text = frame:GetFontString()
+ text:ClearAllPoints()
+ text:SetPoint("TOPLEFT", 15, -1)
+ text:SetPoint("BOTTOMRIGHT", -15, 1)
+ text:SetJustifyV("MIDDLE")
+
+ local widget = {
+ text = text,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Button.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Button.lua
new file mode 100644
index 0000000..8912296
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Button.lua
@@ -0,0 +1,103 @@
+--[[-----------------------------------------------------------------------------
+Button Widget
+Graphical Button.
+-------------------------------------------------------------------------------]]
+local Type, Version = "Button", 23
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs = pairs
+
+-- WoW APIs
+local _G = _G
+local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Button_OnClick(frame, ...)
+ AceGUI:ClearFocus()
+ PlaySound("igMainMenuOption")
+ frame.obj:Fire("OnClick", ...)
+end
+
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ -- restore default values
+ self:SetHeight(24)
+ self:SetWidth(200)
+ self:SetDisabled(false)
+ self:SetAutoWidth(false)
+ self:SetText()
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetText"] = function(self, text)
+ self.text:SetText(text)
+ if self.autoWidth then
+ self:SetWidth(self.text:GetStringWidth() + 30)
+ end
+ end,
+
+ ["SetAutoWidth"] = function(self, autoWidth)
+ self.autoWidth = autoWidth
+ if self.autoWidth then
+ self:SetWidth(self.text:GetStringWidth() + 30)
+ end
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ else
+ self.frame:Enable()
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local name = "AceGUI30Button" .. AceGUI:GetNextWidgetNum(Type)
+ local frame = CreateFrame("Button", name, UIParent, "UIPanelButtonTemplate2")
+ frame:Hide()
+
+ frame:EnableMouse(true)
+ frame:SetScript("OnClick", Button_OnClick)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+
+ local text = frame:GetFontString()
+ text:ClearAllPoints()
+ text:SetPoint("TOPLEFT", 15, -1)
+ text:SetPoint("BOTTOMRIGHT", -15, 1)
+ text:SetJustifyV("MIDDLE")
+
+ local widget = {
+ text = text,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua
new file mode 100644
index 0000000..e908447
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua
@@ -0,0 +1,295 @@
+--[[-----------------------------------------------------------------------------
+Checkbox Widget
+-------------------------------------------------------------------------------]]
+local Type, Version = "CheckBox", 26
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local select, pairs = select, pairs
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: SetDesaturation, GameFontHighlight
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function AlignImage(self)
+ local img = self.image:GetTexture()
+ self.text:ClearAllPoints()
+ if not img then
+ self.text:SetPoint("LEFT", self.checkbg, "RIGHT")
+ self.text:SetPoint("RIGHT")
+ else
+ self.text:SetPoint("LEFT", self.image, "RIGHT", 1, 0)
+ self.text:SetPoint("RIGHT")
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function CheckBox_OnMouseDown(frame)
+ local self = frame.obj
+ if not self.disabled then
+ if self.image:GetTexture() then
+ self.text:SetPoint("LEFT", self.image,"RIGHT", 2, -1)
+ else
+ self.text:SetPoint("LEFT", self.checkbg, "RIGHT", 1, -1)
+ end
+ end
+ AceGUI:ClearFocus()
+end
+
+local function CheckBox_OnMouseUp(frame)
+ local self = frame.obj
+ if not self.disabled then
+ self:ToggleChecked()
+
+ if self.checked then
+ PlaySound("igMainMenuOptionCheckBoxOn")
+ else -- for both nil and false (tristate)
+ PlaySound("igMainMenuOptionCheckBoxOff")
+ end
+
+ self:Fire("OnValueChanged", self.checked)
+ AlignImage(self)
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetType()
+ self:SetValue(false)
+ self:SetTriState(nil)
+ -- height is calculated from the width and required space for the description
+ self:SetWidth(200)
+ self:SetImage()
+ self:SetDisabled(nil)
+ self:SetDescription(nil)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["OnWidthSet"] = function(self, width)
+ if self.desc then
+ self.desc:SetWidth(width - 30)
+ if self.desc:GetText() and self.desc:GetText() ~= "" then
+ self:SetHeight(28 + self.desc:GetStringHeight())
+ end
+ end
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ self.text:SetTextColor(0.5, 0.5, 0.5)
+ SetDesaturation(self.check, true)
+ if self.desc then
+ self.desc:SetTextColor(0.5, 0.5, 0.5)
+ end
+ else
+ self.frame:Enable()
+ self.text:SetTextColor(1, 1, 1)
+ if self.tristate and self.checked == nil then
+ SetDesaturation(self.check, true)
+ else
+ SetDesaturation(self.check, false)
+ end
+ if self.desc then
+ self.desc:SetTextColor(1, 1, 1)
+ end
+ end
+ end,
+
+ ["SetValue"] = function(self, value)
+ local check = self.check
+ self.checked = value
+ if value then
+ SetDesaturation(check, false)
+ check:Show()
+ else
+ --Nil is the unknown tristate value
+ if self.tristate and value == nil then
+ SetDesaturation(check, true)
+ check:Show()
+ else
+ SetDesaturation(check, false)
+ check:Hide()
+ end
+ end
+ self:SetDisabled(self.disabled)
+ end,
+
+ ["GetValue"] = function(self)
+ return self.checked
+ end,
+
+ ["SetTriState"] = function(self, enabled)
+ self.tristate = enabled
+ self:SetValue(self:GetValue())
+ end,
+
+ ["SetType"] = function(self, type)
+ local checkbg = self.checkbg
+ local check = self.check
+ local highlight = self.highlight
+
+ local size
+ if type == "radio" then
+ size = 16
+ checkbg:SetTexture("Interface\\Buttons\\UI-RadioButton")
+ checkbg:SetTexCoord(0, 0.25, 0, 1)
+ check:SetTexture("Interface\\Buttons\\UI-RadioButton")
+ check:SetTexCoord(0.25, 0.5, 0, 1)
+ check:SetBlendMode("ADD")
+ highlight:SetTexture("Interface\\Buttons\\UI-RadioButton")
+ highlight:SetTexCoord(0.5, 0.75, 0, 1)
+ else
+ size = 24
+ checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
+ checkbg:SetTexCoord(0, 1, 0, 1)
+ check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+ check:SetTexCoord(0, 1, 0, 1)
+ check:SetBlendMode("BLEND")
+ highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
+ highlight:SetTexCoord(0, 1, 0, 1)
+ end
+ checkbg:SetHeight(size)
+ checkbg:SetWidth(size)
+ end,
+
+ ["ToggleChecked"] = function(self)
+ local value = self:GetValue()
+ if self.tristate then
+ --cycle in true, nil, false order
+ if value then
+ self:SetValue(nil)
+ elseif value == nil then
+ self:SetValue(false)
+ else
+ self:SetValue(true)
+ end
+ else
+ self:SetValue(not self:GetValue())
+ end
+ end,
+
+ ["SetLabel"] = function(self, label)
+ self.text:SetText(label)
+ end,
+
+ ["SetDescription"] = function(self, desc)
+ if desc then
+ if not self.desc then
+ local desc = self.frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
+ desc:ClearAllPoints()
+ desc:SetPoint("TOPLEFT", self.checkbg, "TOPRIGHT", 5, -21)
+ desc:SetWidth(self.frame.width - 30)
+ desc:SetJustifyH("LEFT")
+ desc:SetJustifyV("TOP")
+ self.desc = desc
+ end
+ self.desc:Show()
+ --self.text:SetFontObject(GameFontNormal)
+ self.desc:SetText(desc)
+ self:SetHeight(28 + self.desc:GetStringHeight())
+ else
+ if self.desc then
+ self.desc:SetText("")
+ self.desc:Hide()
+ end
+ --self.text:SetFontObject(GameFontHighlight)
+ self:SetHeight(24)
+ end
+ end,
+
+ ["SetImage"] = function(self, path, ...)
+ local image = self.image
+ image:SetTexture(path)
+
+ if image:GetTexture() then
+ local n = select("#", ...)
+ if n == 4 or n == 8 then
+ image:SetTexCoord(...)
+ else
+ image:SetTexCoord(0, 1, 0, 1)
+ end
+ end
+ AlignImage(self)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Button", nil, UIParent)
+ frame:Hide()
+
+ frame:EnableMouse(true)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+ frame:SetScript("OnMouseDown", CheckBox_OnMouseDown)
+ frame:SetScript("OnMouseUp", CheckBox_OnMouseUp)
+
+ local checkbg = frame:CreateTexture(nil, "ARTWORK")
+ checkbg:SetWidth(24)
+ checkbg:SetHeight(24)
+ checkbg:SetPoint("TOPLEFT")
+ checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
+
+ local check = frame:CreateTexture(nil, "OVERLAY")
+ check:SetAllPoints(checkbg)
+ check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+
+ local text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
+ text:SetJustifyH("LEFT")
+ text:SetHeight(18)
+ text:SetPoint("LEFT", checkbg, "RIGHT")
+ text:SetPoint("RIGHT")
+
+ local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
+ highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
+ highlight:SetBlendMode("ADD")
+ highlight:SetAllPoints(checkbg)
+
+ local image = frame:CreateTexture(nil, "OVERLAY")
+ image:SetHeight(16)
+ image:SetWidth(16)
+ image:SetPoint("LEFT", checkbg, "RIGHT", 1, 0)
+
+ local widget = {
+ checkbg = checkbg,
+ check = check,
+ text = text,
+ highlight = highlight,
+ image = image,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua
new file mode 100644
index 0000000..82abfcc
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua
@@ -0,0 +1,205 @@
+--[[-----------------------------------------------------------------------------
+ColorPicker Widget
+-------------------------------------------------------------------------------]]
+local Type, Version = "ColorPicker-ElvUI", 25
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs = pairs
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: ColorPickerFrame, OpacitySliderFrame, ColorPPDefault
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function ColorCallback(self, r, g, b, a, isAlpha)
+ -- this will block an infinite loop from `E.GrabColorPickerValues`
+ -- which is caused when we set values into the color picker again on `OnValueChanged`
+ if ColorPickerFrame.noColorCallback then return end
+
+ if not self.HasAlpha then
+ a = 1
+ end
+ self:SetColor(r, g, b, a)
+ if ColorPickerFrame:IsVisible() then
+ --colorpicker is still open
+ self:Fire("OnValueChanged", r, g, b, a)
+ else
+ --colorpicker is closed, color callback is first, ignore it,
+ --alpha callback is the final call after it closes so confirm now
+ if isAlpha then
+ self:Fire("OnValueConfirmed", r, g, b, a)
+ end
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function ColorSwatch_OnClick(frame)
+ ColorPickerFrame:Hide()
+ local self = frame.obj
+ if not self.disabled then
+ ColorPickerFrame:SetFrameStrata("FULLSCREEN_DIALOG")
+ ColorPickerFrame:SetFrameLevel(frame:GetFrameLevel() + 10)
+ ColorPickerFrame:SetClampedToScreen(true)
+
+ ColorPickerFrame.func = function()
+ local r, g, b = ColorPickerFrame:GetColorRGB()
+ local a = 1 - OpacitySliderFrame:GetValue()
+ ColorCallback(self, r, g, b, a)
+ end
+
+ ColorPickerFrame.hasOpacity = self.HasAlpha
+ ColorPickerFrame.opacityFunc = function()
+ local r, g, b = ColorPickerFrame:GetColorRGB()
+ local a = 1 - OpacitySliderFrame:GetValue()
+ ColorCallback(self, r, g, b, a, true)
+ end
+
+ local r, g, b, a = self.r, self.g, self.b, self.a
+ if self.HasAlpha then
+ ColorPickerFrame.opacity = 1 - (a or 0)
+ end
+ ColorPickerFrame:SetColorRGB(r, g, b)
+
+ if ColorPPDefault and self.dR and self.dG and self.dB then
+ local alpha = 1
+ if self.dA then alpha = 1 - self.dA end
+ if not ColorPPDefault.colors then ColorPPDefault.colors = {} end
+ ColorPPDefault.colors.r, ColorPPDefault.colors.g, ColorPPDefault.colors.b, ColorPPDefault.colors.a = self.dR, self.dG, self.dB, alpha
+ end
+
+ ColorPickerFrame.cancelFunc = function()
+ ColorCallback(self, r, g, b, a, true)
+ end
+
+ ColorPickerFrame:Show()
+ end
+ AceGUI:ClearFocus()
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetHeight(24)
+ self:SetWidth(200)
+ self:SetHasAlpha(false)
+ self:SetColor(0, 0, 0, 1)
+ self:SetDisabled(nil)
+ self:SetLabel(nil)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetLabel"] = function(self, text)
+ self.text:SetText(text)
+ end,
+
+ ["SetColor"] = function(self, r, g, b, a, defaultR, defaultG, defaultB, defaultA)
+ self.r = r
+ self.g = g
+ self.b = b
+ self.a = a or 1
+ self.dR = defaultR or self.dR
+ self.dG = defaultG or self.dG
+ self.dB = defaultB or self.dB
+ self.dA = defaultA or self.dA
+ self.colorSwatch:SetVertexColor(r, g, b, a)
+ end,
+
+ ["SetHasAlpha"] = function(self, HasAlpha)
+ self.HasAlpha = HasAlpha
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if self.disabled then
+ self.frame:Disable()
+ self.text:SetTextColor(0.5, 0.5, 0.5)
+ else
+ self.frame:Enable()
+ self.text:SetTextColor(1, 1, 1)
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Button", nil, UIParent)
+ frame:Hide()
+
+ frame:EnableMouse(true)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+ frame:SetScript("OnClick", ColorSwatch_OnClick)
+
+ local colorSwatch = frame:CreateTexture(nil, "OVERLAY")
+ colorSwatch:SetWidth(19)
+ colorSwatch:SetHeight(19)
+ colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
+ colorSwatch:SetPoint("LEFT")
+
+ local texture = frame:CreateTexture(nil, "BACKGROUND")
+ colorSwatch.background = texture
+ texture:SetWidth(16)
+ texture:SetHeight(16)
+ texture:SetTexture(1, 1, 1)
+ texture:SetPoint("CENTER", colorSwatch)
+ texture:Show()
+
+ local checkers = frame:CreateTexture(nil, "BACKGROUND")
+ colorSwatch.checkers = checkers
+ checkers:SetWidth(14)
+ checkers:SetHeight(14)
+ checkers:SetTexture("Tileset\\Generic\\Checkers")
+ checkers:SetTexCoord(.25, 0, 0.5, .25)
+ checkers:SetDesaturated(true)
+ checkers:SetVertexColor(1, 1, 1, 0.75)
+ checkers:SetPoint("CENTER", colorSwatch)
+ checkers:Show()
+
+ local text = frame:CreateFontString(nil,"OVERLAY","GameFontHighlight")
+ text:SetHeight(24)
+ text:SetJustifyH("LEFT")
+ text:SetTextColor(1, 1, 1)
+ text:SetPoint("LEFT", colorSwatch, "RIGHT", 2, 0)
+ text:SetPoint("RIGHT")
+
+ --local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
+ --highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
+ --highlight:SetBlendMode("ADD")
+ --highlight:SetAllPoints(frame)
+
+ local widget = {
+ colorSwatch = colorSwatch,
+ text = text,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua
new file mode 100644
index 0000000..a57e30a
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua
@@ -0,0 +1,471 @@
+--[[ $Id$ ]]--
+
+local AceGUI = LibStub("AceGUI-3.0")
+
+-- Lua APIs
+local select, assert = select, assert
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame = CreateFrame
+
+local function fixlevels(parent,...)
+ local i = 1
+ local child = select(i, ...)
+ while child do
+ child:SetFrameLevel(parent:GetFrameLevel()+1)
+ fixlevels(child, child:GetChildren())
+ i = i + 1
+ child = select(i, ...)
+ end
+end
+
+local function fixstrata(strata, parent, ...)
+ local i = 1
+ local child = select(i, ...)
+ parent:SetFrameStrata(strata)
+ while child do
+ fixstrata(strata, child, child:GetChildren())
+ i = i + 1
+ child = select(i, ...)
+ end
+end
+
+-- ItemBase is the base "class" for all dropdown items.
+-- Each item has to use ItemBase.Create(widgetType) to
+-- create an initial 'self' value.
+-- ItemBase will add common functions and ui event handlers.
+-- Be sure to keep basic usage when you override functions.
+
+local ItemBase = {
+ -- NOTE: The ItemBase version is added to each item's version number
+ -- to ensure proper updates on ItemBase changes.
+ -- Use at least 1000er steps.
+ version = 1000,
+ counter = 0,
+}
+
+function ItemBase.Frame_OnEnter(this)
+ local self = this.obj
+
+ if self.useHighlight then
+ self.highlight:Show()
+ end
+ self:Fire("OnEnter")
+
+ if self.specialOnEnter then
+ self.specialOnEnter(self)
+ end
+end
+
+function ItemBase.Frame_OnLeave(this)
+ local self = this.obj
+
+ self.highlight:Hide()
+ self:Fire("OnLeave")
+
+ if self.specialOnLeave then
+ self.specialOnLeave(self)
+ end
+end
+
+-- exported, AceGUI callback
+function ItemBase.OnAcquire(self)
+ self.frame:SetToplevel(true)
+ self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
+end
+
+-- exported, AceGUI callback
+function ItemBase.OnRelease(self)
+ self:SetDisabled(false)
+ self.pullout = nil
+ self.frame:SetParent(nil)
+ self.frame:ClearAllPoints()
+ self.frame:Hide()
+end
+
+-- exported
+-- NOTE: this is called by a Dropdown-Pullout.
+-- Do not call this method directly
+function ItemBase.SetPullout(self, pullout)
+ self.pullout = pullout
+
+ self.frame:SetParent(nil)
+ self.frame:SetParent(pullout.itemFrame)
+ self.parent = pullout.itemFrame
+ fixlevels(pullout.itemFrame, pullout.itemFrame:GetChildren())
+end
+
+-- exported
+function ItemBase.SetText(self, text)
+ self.text:SetText(text or "")
+end
+
+-- exported
+function ItemBase.GetText(self)
+ return self.text:GetText()
+end
+
+-- exported
+function ItemBase.SetPoint(self, ...)
+ self.frame:SetPoint(...)
+end
+
+-- exported
+function ItemBase.Show(self)
+ self.frame:Show()
+end
+
+-- exported
+function ItemBase.Hide(self)
+ self.frame:Hide()
+end
+
+-- exported
+function ItemBase.SetDisabled(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.useHighlight = false
+ self.text:SetTextColor(.5, .5, .5)
+ else
+ self.useHighlight = true
+ self.text:SetTextColor(1, 1, 1)
+ end
+end
+
+-- exported
+-- NOTE: this is called by a Dropdown-Pullout.
+-- Do not call this method directly
+function ItemBase.SetOnLeave(self, func)
+ self.specialOnLeave = func
+end
+
+-- exported
+-- NOTE: this is called by a Dropdown-Pullout.
+-- Do not call this method directly
+function ItemBase.SetOnEnter(self, func)
+ self.specialOnEnter = func
+end
+
+function ItemBase.Create(type)
+ -- NOTE: Most of the following code is copied from AceGUI-3.0/Dropdown widget
+ local count = AceGUI:GetNextWidgetNum(type)
+ local frame = CreateFrame("Button", "AceGUI30DropDownItem"..count)
+ local self = {}
+ self.frame = frame
+ frame.obj = self
+ self.type = type
+
+ self.useHighlight = true
+
+ frame:SetHeight(17)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
+ text:SetTextColor(1,1,1)
+ text:SetJustifyH("LEFT")
+ text:SetPoint("TOPLEFT",frame,"TOPLEFT",18,0)
+ text:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-8,0)
+ self.text = text
+
+ local highlight = frame:CreateTexture(nil, "OVERLAY")
+ highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
+ highlight:SetBlendMode("ADD")
+ highlight:SetHeight(14)
+ highlight:ClearAllPoints()
+ highlight:SetPoint("RIGHT",frame,"RIGHT",-3,0)
+ highlight:SetPoint("LEFT",frame,"LEFT",5,0)
+ highlight:Hide()
+ self.highlight = highlight
+
+ local check = frame:CreateTexture("OVERLAY")
+ check:SetWidth(16)
+ check:SetHeight(16)
+ check:SetPoint("LEFT",frame,"LEFT",3,-1)
+ check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+ check:Hide()
+ self.check = check
+
+ local sub = frame:CreateTexture("OVERLAY")
+ sub:SetWidth(16)
+ sub:SetHeight(16)
+ sub:SetPoint("RIGHT",frame,"RIGHT",-3,-1)
+ sub:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow")
+ sub:Hide()
+ self.sub = sub
+
+ frame:SetScript("OnEnter", ItemBase.Frame_OnEnter)
+ frame:SetScript("OnLeave", ItemBase.Frame_OnLeave)
+
+ self.OnAcquire = ItemBase.OnAcquire
+ self.OnRelease = ItemBase.OnRelease
+
+ self.SetPullout = ItemBase.SetPullout
+ self.GetText = ItemBase.GetText
+ self.SetText = ItemBase.SetText
+ self.SetDisabled = ItemBase.SetDisabled
+
+ self.SetPoint = ItemBase.SetPoint
+ self.Show = ItemBase.Show
+ self.Hide = ItemBase.Hide
+
+ self.SetOnLeave = ItemBase.SetOnLeave
+ self.SetOnEnter = ItemBase.SetOnEnter
+
+ return self
+end
+
+-- Register a dummy LibStub library to retrieve the ItemBase, so other addons can use it.
+local IBLib = LibStub:NewLibrary("AceGUI-3.0-DropDown-ItemBase", ItemBase.version)
+if IBLib then
+ IBLib.GetItemBase = function() return ItemBase end
+end
+
+--[[
+ Template for items:
+
+-- Item:
+--
+do
+ local widgetType = "Dropdown-Item-"
+ local widgetVersion = 1
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
+--]]
+
+-- Item: Header
+-- A single text entry.
+-- Special: Different text color and no highlight
+do
+ local widgetType = "Dropdown-Item-Header"
+ local widgetVersion = 1
+
+ local function OnEnter(this)
+ local self = this.obj
+ self:Fire("OnEnter")
+
+ if self.specialOnEnter then
+ self.specialOnEnter(self)
+ end
+ end
+
+ local function OnLeave(this)
+ local self = this.obj
+ self:Fire("OnLeave")
+
+ if self.specialOnLeave then
+ self.specialOnLeave(self)
+ end
+ end
+
+ -- exported, override
+ local function SetDisabled(self, disabled)
+ ItemBase.SetDisabled(self, disabled)
+ if not disabled then
+ self.text:SetTextColor(1, 1, 0)
+ end
+ end
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ self.SetDisabled = SetDisabled
+
+ self.frame:SetScript("OnEnter", OnEnter)
+ self.frame:SetScript("OnLeave", OnLeave)
+
+ self.text:SetTextColor(1, 1, 0)
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
+
+-- Item: Execute
+-- A simple button
+do
+ local widgetType = "Dropdown-Item-Execute"
+ local widgetVersion = 1
+
+ local function Frame_OnClick(this, button)
+ local self = this.obj
+ if self.disabled then return end
+ self:Fire("OnClick")
+ if self.pullout then
+ self.pullout:Close()
+ end
+ end
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ self.frame:SetScript("OnClick", Frame_OnClick)
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
+
+-- Item: Toggle
+-- Some sort of checkbox for dropdown menus.
+-- Does not close the pullout on click.
+do
+ local widgetType = "Dropdown-Item-Toggle"
+ local widgetVersion = 3
+
+ local function UpdateToggle(self)
+ if self.value then
+ self.check:Show()
+ else
+ self.check:Hide()
+ end
+ end
+
+ local function OnRelease(self)
+ ItemBase.OnRelease(self)
+ self:SetValue(nil)
+ end
+
+ local function Frame_OnClick(this, button)
+ local self = this.obj
+ if self.disabled then return end
+ self.value = not self.value
+ if self.value then
+ PlaySound("igMainMenuOptionCheckBoxOn")
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff")
+ end
+ UpdateToggle(self)
+ self:Fire("OnValueChanged", self.value)
+ end
+
+ -- exported
+ local function SetValue(self, value)
+ self.value = value
+ UpdateToggle(self)
+ end
+
+ -- exported
+ local function GetValue(self)
+ return self.value
+ end
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ self.frame:SetScript("OnClick", Frame_OnClick)
+
+ self.SetValue = SetValue
+ self.GetValue = GetValue
+ self.OnRelease = OnRelease
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
+
+-- Item: Menu
+-- Shows a submenu on mouse over
+-- Does not close the pullout on click
+do
+ local widgetType = "Dropdown-Item-Menu"
+ local widgetVersion = 2
+
+ local function OnEnter(this)
+ local self = this.obj
+ self:Fire("OnEnter")
+
+ if self.specialOnEnter then
+ self.specialOnEnter(self)
+ end
+
+ self.highlight:Show()
+
+ if not self.disabled and self.submenu then
+ self.submenu:Open("TOPLEFT", self.frame, "TOPRIGHT", self.pullout:GetRightBorderWidth(), 0, self.frame:GetFrameLevel() + 100)
+ end
+ end
+
+ local function OnHide(this)
+ local self = this.obj
+ if self.submenu then
+ self.submenu:Close()
+ end
+ end
+
+ -- exported
+ local function SetMenu(self, menu)
+ assert(menu.type == "Dropdown-Pullout")
+ self.submenu = menu
+ end
+
+ -- exported
+ local function CloseMenu(self)
+ self.submenu:Close()
+ end
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ self.sub:Show()
+
+ self.frame:SetScript("OnEnter", OnEnter)
+ self.frame:SetScript("OnHide", OnHide)
+
+ self.SetMenu = SetMenu
+ self.CloseMenu = CloseMenu
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
+
+-- Item: Separator
+-- A single line to separate items
+do
+ local widgetType = "Dropdown-Item-Separator"
+ local widgetVersion = 1
+
+ -- exported, override
+ local function SetDisabled(self, disabled)
+ ItemBase.SetDisabled(self, disabled)
+ self.useHighlight = false
+ end
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ self.SetDisabled = SetDisabled
+
+ local line = self.frame:CreateTexture(nil, "OVERLAY")
+ line:SetHeight(1)
+ line:SetTexture(.5, .5, .5)
+ line:SetPoint("LEFT", self.frame, "LEFT", 10, 0)
+ line:SetPoint("RIGHT", self.frame, "RIGHT", -10, 0)
+
+ self.text:Hide()
+
+ self.useHighlight = false
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua
new file mode 100644
index 0000000..70e5e9d
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua
@@ -0,0 +1,768 @@
+--[[ $Id$ ]]--
+local AceGUI = LibStub("AceGUI-3.0")
+
+-- Lua APIs
+local min, max, floor = math.min, math.max, math.floor
+local select, pairs, ipairs, type, tostring = select, pairs, ipairs, type, tostring
+local tsort, tonumber = table.sort, tonumber
+
+-- WoW APIs
+local PlaySound = PlaySound
+local UIParent, CreateFrame = UIParent, CreateFrame
+local _G = _G
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: CLOSE
+
+local function fixlevels(parent,...)
+ local i = 1
+ local child = select(i, ...)
+ while child do
+ child:SetFrameLevel(parent:GetFrameLevel()+1)
+ fixlevels(child, child:GetChildren())
+ i = i + 1
+ child = select(i, ...)
+ end
+end
+
+local function fixstrata(strata, parent, ...)
+ local i = 1
+ local child = select(i, ...)
+ parent:SetFrameStrata(strata)
+ while child do
+ fixstrata(strata, child, child:GetChildren())
+ i = i + 1
+ child = select(i, ...)
+ end
+end
+
+do
+ local widgetType = "Dropdown-Pullout"
+ local widgetVersion = 3
+
+ --[[ Static data ]]--
+
+ local backdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
+ edgeSize = 32,
+ tileSize = 32,
+ tile = true,
+ insets = { left = 11, right = 12, top = 12, bottom = 11 },
+ }
+ local sliderBackdrop = {
+ bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
+ edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
+ tile = true, tileSize = 8, edgeSize = 8,
+ insets = { left = 3, right = 3, top = 3, bottom = 3 }
+ }
+
+ local defaultWidth = 200
+ local defaultMaxHeight = 600
+
+ --[[ UI Event Handlers ]]--
+
+ -- HACK: This should be no part of the pullout, but there
+ -- is no other 'clean' way to response to any item-OnEnter
+ -- Used to close Submenus when an other item is entered
+ local function OnEnter(item)
+ local self = item.pullout
+ for k, v in ipairs(self.items) do
+ if v.CloseMenu and v ~= item then
+ v:CloseMenu()
+ end
+ end
+ end
+
+ -- See the note in Constructor() for each scroll related function
+ local function OnMouseWheel(this, value)
+ this.obj:MoveScroll(value)
+ end
+
+ local function OnScrollValueChanged(this, value)
+ this.obj:SetScroll(value)
+ end
+
+ local function OnSizeChanged(this)
+ this.obj:FixScroll()
+ end
+
+ --[[ Exported methods ]]--
+
+ -- exported
+ local function SetScroll(self, value)
+ local status = self.scrollStatus
+ local frame, child = self.scrollFrame, self.itemFrame
+ local height, viewheight = frame:GetHeight(), child:GetHeight()
+
+ local offset
+ if height > viewheight then
+ offset = 0
+ else
+ offset = floor((viewheight - height) / 1000 * value)
+ end
+ child:ClearAllPoints()
+ child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
+ child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", self.slider:IsShown() and -12 or 0, offset)
+ status.offset = offset
+ status.scrollvalue = value
+ end
+
+ -- exported
+ local function MoveScroll(self, value)
+ local status = self.scrollStatus
+ local frame, child = self.scrollFrame, self.itemFrame
+ local height, viewheight = frame:GetHeight(), child:GetHeight()
+
+ if height > viewheight then
+ self.slider:Hide()
+ else
+ self.slider:Show()
+ local diff = height - viewheight
+ local delta = 1
+ if value < 0 then
+ delta = -1
+ end
+ self.slider:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
+ end
+ end
+
+ -- exported
+ local function FixScroll(self)
+ local status = self.scrollStatus
+ local frame, child = self.scrollFrame, self.itemFrame
+ local height, viewheight = frame:GetHeight(), child:GetHeight()
+ local offset = status.offset or 0
+
+ if viewheight < height then
+ self.slider:Hide()
+ child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, offset)
+ self.slider:SetValue(0)
+ else
+ self.slider:Show()
+ local value = (offset / (viewheight - height) * 1000)
+ if value > 1000 then value = 1000 end
+ self.slider:SetValue(value)
+ self:SetScroll(value)
+ if value < 1000 then
+ child:ClearAllPoints()
+ child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
+ child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -12, offset)
+ status.offset = offset
+ end
+ end
+ end
+
+ -- exported, AceGUI callback
+ local function OnAcquire(self)
+ self.frame:SetParent(UIParent)
+ --self.itemFrame:SetToplevel(true)
+ end
+
+ -- exported, AceGUI callback
+ local function OnRelease(self)
+ self:Clear()
+ self.frame:ClearAllPoints()
+ self.frame:Hide()
+ end
+
+ -- exported
+ local function AddItem(self, item)
+ self.items[#self.items + 1] = item
+
+ local h = #self.items * 16
+ self.itemFrame:SetHeight(h)
+ self.frame:SetHeight(min(h + 34, self.maxHeight)) -- +34: 20 for scrollFrame placement (10 offset) and +14 for item placement
+
+ item.frame:SetPoint("LEFT", self.itemFrame, "LEFT")
+ item.frame:SetPoint("RIGHT", self.itemFrame, "RIGHT")
+
+ item:SetPullout(self)
+ item:SetOnEnter(OnEnter)
+ end
+
+ -- exported
+ local function Open(self, point, relFrame, relPoint, x, y)
+ local items = self.items
+ local frame = self.frame
+ local itemFrame = self.itemFrame
+
+ frame:SetPoint(point, relFrame, relPoint, x, y)
+
+
+ local height = 8
+ for i, item in pairs(items) do
+ if i == 1 then
+ item:SetPoint("TOP", itemFrame, "TOP", 0, -2)
+ else
+ item:SetPoint("TOP", items[i-1].frame, "BOTTOM", 0, 1)
+ end
+
+ item:Show()
+
+ height = height + 16
+ end
+ itemFrame:SetHeight(height)
+ fixstrata("TOOLTIP", frame, frame:GetChildren())
+ frame:Show()
+ self:Fire("OnOpen")
+ end
+
+ -- exported
+ local function Close(self)
+ self.frame:Hide()
+ self:Fire("OnClose")
+ end
+
+ -- exported
+ local function Clear(self)
+ local items = self.items
+ for i, item in pairs(items) do
+ AceGUI:Release(item)
+ items[i] = nil
+ end
+ end
+
+ -- exported
+ local function IterateItems(self)
+ return ipairs(self.items)
+ end
+
+ -- exported
+ local function SetHideOnLeave(self, val)
+ self.hideOnLeave = val
+ end
+
+ -- exported
+ local function SetMaxHeight(self, height)
+ self.maxHeight = height or defaultMaxHeight
+ if self.frame:GetHeight() > height then
+ self.frame:SetHeight(height)
+ elseif (self.itemFrame:GetHeight() + 34) < height then
+ self.frame:SetHeight(self.itemFrame:GetHeight() + 34) -- see :AddItem
+ end
+ end
+
+ -- exported
+ local function GetRightBorderWidth(self)
+ return 6 + (self.slider:IsShown() and 12 or 0)
+ end
+
+ -- exported
+ local function GetLeftBorderWidth(self)
+ return 6
+ end
+
+ --[[ Constructor ]]--
+
+ local function Constructor()
+ local count = AceGUI:GetNextWidgetNum(widgetType)
+ local frame = CreateFrame("Frame", "AceGUI30Pullout"..count, UIParent)
+ local self = {}
+ self.count = count
+ self.type = widgetType
+ self.frame = frame
+ frame.obj = self
+
+ self.OnAcquire = OnAcquire
+ self.OnRelease = OnRelease
+
+ self.AddItem = AddItem
+ self.Open = Open
+ self.Close = Close
+ self.Clear = Clear
+ self.IterateItems = IterateItems
+ self.SetHideOnLeave = SetHideOnLeave
+
+ self.SetScroll = SetScroll
+ self.MoveScroll = MoveScroll
+ self.FixScroll = FixScroll
+
+ self.SetMaxHeight = SetMaxHeight
+ self.GetRightBorderWidth = GetRightBorderWidth
+ self.GetLeftBorderWidth = GetLeftBorderWidth
+
+ self.items = {}
+
+ self.scrollStatus = {
+ scrollvalue = 0,
+ }
+
+ self.maxHeight = defaultMaxHeight
+
+ frame:SetBackdrop(backdrop)
+ frame:SetBackdropColor(0, 0, 0)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+ frame:SetClampedToScreen(true)
+ frame:SetWidth(defaultWidth)
+ frame:SetHeight(self.maxHeight)
+ --frame:SetToplevel(true)
+
+ -- NOTE: The whole scroll frame code is copied from the AceGUI-3.0 widget ScrollFrame
+ local scrollFrame = CreateFrame("ScrollFrame", nil, frame)
+ local itemFrame = CreateFrame("Frame", nil, scrollFrame)
+
+ self.scrollFrame = scrollFrame
+ self.itemFrame = itemFrame
+
+ scrollFrame.obj = self
+ itemFrame.obj = self
+
+ local slider = CreateFrame("Slider", "AceGUI30PulloutScrollbar"..count, scrollFrame)
+ slider:SetOrientation("VERTICAL")
+ slider:SetHitRectInsets(0, 0, -10, 0)
+ slider:SetBackdrop(sliderBackdrop)
+ slider:SetWidth(8)
+ slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
+ slider:SetFrameStrata("FULLSCREEN_DIALOG")
+ self.slider = slider
+ slider.obj = self
+
+ scrollFrame:SetScrollChild(itemFrame)
+ scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 6, -12)
+ scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -6, 12)
+ scrollFrame:EnableMouseWheel(true)
+ scrollFrame:SetScript("OnMouseWheel", OnMouseWheel)
+ scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
+ scrollFrame:SetToplevel(true)
+ scrollFrame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
+ itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", -12, 0)
+ itemFrame:SetHeight(400)
+ itemFrame:SetToplevel(true)
+ itemFrame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ slider:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", -16, 0)
+ slider:SetPoint("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", -16, 0)
+ slider:SetScript("OnValueChanged", OnScrollValueChanged)
+ slider:SetMinMaxValues(0, 1000)
+ slider:SetValueStep(1)
+ slider:SetValue(0)
+
+ scrollFrame:Show()
+ itemFrame:Show()
+ slider:Hide()
+
+ self:FixScroll()
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
+end
+
+do
+ local widgetType = "Dropdown"
+ local widgetVersion = 35
+
+ --[[ Static data ]]--
+
+ --[[ UI event handler ]]--
+
+ local function Control_OnEnter(this)
+ this.obj.button:LockHighlight()
+ this.obj:Fire("OnEnter")
+ end
+
+ local function Control_OnLeave(this)
+ this.obj.button:UnlockHighlight()
+ this.obj:Fire("OnLeave")
+ end
+
+ local function Dropdown_OnHide(this)
+ local self = this.obj
+ if self.open then
+ self.pullout:Close()
+ end
+ end
+
+ local function Dropdown_TogglePullout(this)
+ local self = this.obj
+ PlaySound("igMainMenuOptionCheckBoxOn") -- missleading name, but the Blizzard code uses this sound
+ if self.open then
+ self.open = nil
+ self.pullout:Close()
+ AceGUI:ClearFocus()
+ else
+ self.open = true
+ self.pullout:SetWidth(self.pulloutWidth or self.frame:GetWidth())
+ self.pullout:Open("TOPLEFT", self.frame, "BOTTOMLEFT", 0, self.label:IsShown() and -2 or 0)
+ AceGUI:SetFocus(self)
+ end
+ end
+
+ local function OnPulloutOpen(this)
+ local self = this.userdata.obj
+ local value = self.value
+
+ if not self.multiselect then
+ for i, item in this:IterateItems() do
+ item:SetValue(item.userdata.value == value)
+ end
+ end
+
+ self.open = true
+ self:Fire("OnOpened")
+ end
+
+ local function OnPulloutClose(this)
+ local self = this.userdata.obj
+ self.open = nil
+ self:Fire("OnClosed")
+ end
+
+ local function ShowMultiText(self)
+ local text
+ for i, widget in self.pullout:IterateItems() do
+ if widget.type == "Dropdown-Item-Toggle" then
+ if widget:GetValue() then
+ if text then
+ text = text..", "..widget:GetText()
+ else
+ text = widget:GetText()
+ end
+ end
+ end
+ end
+ self:SetText(text)
+ end
+
+ local function OnItemValueChanged(this, event, checked)
+ local self = this.userdata.obj
+
+ if self.multiselect then
+ self:Fire("OnValueChanged", this.userdata.value, checked)
+ ShowMultiText(self)
+ else
+ if checked then
+ self:SetValue(this.userdata.value)
+ self:Fire("OnValueChanged", this.userdata.value)
+ else
+ this:SetValue(true)
+ end
+ if self.open then
+ self.pullout:Close()
+ end
+ end
+ end
+
+ --[[ Exported methods ]]--
+
+ -- exported, AceGUI callback
+ local function OnAcquire(self)
+ local pullout = AceGUI:Create("Dropdown-Pullout")
+ self.pullout = pullout
+ pullout.userdata.obj = self
+ pullout:SetCallback("OnClose", OnPulloutClose)
+ pullout:SetCallback("OnOpen", OnPulloutOpen)
+ self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1)
+ fixlevels(self.pullout.frame, self.pullout.frame:GetChildren())
+
+ self:SetHeight(44)
+ self:SetWidth(200)
+ self:SetLabel()
+ self:SetPulloutWidth(nil)
+ self.list = {}
+ end
+
+ -- exported, AceGUI callback
+ local function OnRelease(self)
+ if self.open then
+ self.pullout:Close()
+ end
+ AceGUI:Release(self.pullout)
+ self.pullout = nil
+
+ self:SetText("")
+ self:SetDisabled(false)
+ self:SetMultiselect(false)
+
+ self.value = nil
+ self.list = nil
+ self.open = nil
+ self.hasClose = nil
+
+ self.frame:ClearAllPoints()
+ self.frame:Hide()
+ end
+
+ -- exported
+ local function SetDisabled(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.text:SetTextColor(0.5,0.5,0.5)
+ self.button:Disable()
+ self.button_cover:Disable()
+ self.label:SetTextColor(0.5,0.5,0.5)
+ else
+ self.button:Enable()
+ self.button_cover:Enable()
+ self.label:SetTextColor(1,.82,0)
+ self.text:SetTextColor(1,1,1)
+ end
+ end
+
+ -- exported
+ local function ClearFocus(self)
+ if self.open then
+ self.pullout:Close()
+ end
+ end
+
+ -- exported
+ local function SetText(self, text)
+ self.text:SetText(text or "")
+ end
+
+ -- exported
+ local function SetLabel(self, text)
+ if text and text ~= "" then
+ self.label:SetText(text)
+ self.label:Show()
+ self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,-14)
+ self:SetHeight(40)
+ self.alignoffset = 26
+ else
+ self.label:SetText("")
+ self.label:Hide()
+ self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,0)
+ self:SetHeight(26)
+ self.alignoffset = 12
+ end
+ end
+
+ -- exported
+ local function SetValue(self, value)
+ self:SetText(self.list[value] or "")
+ self.value = value
+ end
+
+ -- exported
+ local function GetValue(self)
+ return self.value
+ end
+
+ -- exported
+ local function SetItemValue(self, item, value)
+ if not self.multiselect then return end
+ for i, widget in self.pullout:IterateItems() do
+ if widget.userdata.value == item then
+ if widget.SetValue then
+ widget:SetValue(value)
+ end
+ end
+ end
+ ShowMultiText(self)
+ end
+
+ -- exported
+ local function SetItemDisabled(self, item, disabled)
+ for i, widget in self.pullout:IterateItems() do
+ if widget.userdata.value == item then
+ widget:SetDisabled(disabled)
+ end
+ end
+ end
+
+ local function AddListItem(self, value, text, itemType)
+ if not itemType then itemType = "Dropdown-Item-Toggle" end
+ local exists = AceGUI:GetWidgetVersion(itemType)
+ if not exists then error(("The given item type, %q, does not exist within AceGUI-3.0"):format(tostring(itemType)), 2) end
+
+ local item = AceGUI:Create(itemType)
+ item:SetText(text)
+ item.userdata.obj = self
+ item.userdata.value = value
+ item:SetCallback("OnValueChanged", OnItemValueChanged)
+ self.pullout:AddItem(item)
+ end
+
+ local function AddCloseButton(self)
+ if not self.hasClose then
+ local close = AceGUI:Create("Dropdown-Item-Execute")
+ close:SetText(CLOSE)
+ self.pullout:AddItem(close)
+ self.hasClose = true
+ end
+ end
+
+ -- exported
+ local sortlist = {}
+ local function sortTbl(x,y)
+ local num1, num2 = tonumber(x), tonumber(y)
+ if num1 and num2 then -- numeric comparison, either two numbers or numeric strings
+ return num1 < num2
+ else -- compare everything else tostring'ed
+ return tostring(x) < tostring(y)
+ end
+ end
+
+ -- these were added by ElvUI
+ local sortStr1, sortStr2 = "%((%d+)%)", "%[(%d+)]"
+ local sortValue = function(a,b)
+ if a and b and (a[2] and b[2]) then
+ local a2 = tonumber(a[2]:match(sortStr1) or a[2]:match(sortStr2))
+ local b2 = tonumber(b[2]:match(sortStr1) or b[2]:match(sortStr2))
+ if a2 and b2 and (a2 ~= b2) then
+ return a2 < b2 -- try to sort by the number inside of brackets if we can
+ end
+ return a[2] < b[2]
+ end
+ end
+
+ local function SetList(self, list, order, itemType, sortByValue)
+ self.list = list or {}
+ self.pullout:Clear()
+ self.hasClose = nil
+ if not list then return end
+
+ if type(order) ~= "table" then
+ if sortByValue then -- added by ElvUI
+ for k, v in pairs(list) do
+ sortlist[#sortlist + 1] = {k,v}
+ end
+ tsort(sortlist, sortValue)
+
+ for i, sortedList in ipairs(sortlist) do
+ AddListItem(self, sortedList[1], sortedList[2], itemType)
+ sortlist[i] = nil
+ end
+ else -- this is the default way (unchanged by ElvUI)
+ for v in pairs(list) do
+ sortlist[#sortlist + 1] = v
+ end
+ tsort(sortlist, sortTbl)
+
+ for i, key in ipairs(sortlist) do
+ AddListItem(self, key, list[key], itemType)
+ sortlist[i] = nil
+ end
+ end
+ else
+ for i, key in ipairs(order) do
+ AddListItem(self, key, list[key], itemType)
+ end
+ end
+ if self.multiselect then
+ ShowMultiText(self)
+ AddCloseButton(self)
+ end
+ end
+
+ -- exported
+ local function AddItem(self, value, text, itemType)
+ self.list[value] = text
+ AddListItem(self, value, text, itemType)
+ end
+
+ -- exported
+ local function SetMultiselect(self, multi)
+ self.multiselect = multi
+ if multi then
+ ShowMultiText(self)
+ AddCloseButton(self)
+ end
+ end
+
+ -- exported
+ local function GetMultiselect(self)
+ return self.multiselect
+ end
+
+ local function SetPulloutWidth(self, width)
+ self.pulloutWidth = width
+ end
+
+ --[[ Constructor ]]--
+
+ local function Constructor()
+ local count = AceGUI:GetNextWidgetNum(widgetType)
+ local frame = CreateFrame("Frame", nil, UIParent)
+ local dropdown = CreateFrame("Frame", "AceGUI30DropDown"..count, frame, "UIDropDownMenuTemplate")
+
+ local self = {}
+ self.type = widgetType
+ self.frame = frame
+ self.dropdown = dropdown
+ self.count = count
+ frame.obj = self
+ dropdown.obj = self
+
+ self.OnRelease = OnRelease
+ self.OnAcquire = OnAcquire
+
+ self.ClearFocus = ClearFocus
+
+ self.SetText = SetText
+ self.SetValue = SetValue
+ self.GetValue = GetValue
+ self.SetList = SetList
+ self.SetLabel = SetLabel
+ self.SetDisabled = SetDisabled
+ self.AddItem = AddItem
+ self.SetMultiselect = SetMultiselect
+ self.GetMultiselect = GetMultiselect
+ self.SetItemValue = SetItemValue
+ self.SetItemDisabled = SetItemDisabled
+ self.SetPulloutWidth = SetPulloutWidth
+
+ self.alignoffset = 26
+
+ frame:SetScript("OnHide",Dropdown_OnHide)
+
+ dropdown:ClearAllPoints()
+ dropdown:SetPoint("TOPLEFT",frame,"TOPLEFT",-15,0)
+ dropdown:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",17,0)
+ dropdown:SetScript("OnHide", nil)
+
+ local left = _G[dropdown:GetName() .. "Left"]
+ local middle = _G[dropdown:GetName() .. "Middle"]
+ local right = _G[dropdown:GetName() .. "Right"]
+
+ middle:ClearAllPoints()
+ right:ClearAllPoints()
+
+ middle:SetPoint("LEFT", left, "RIGHT", 0, 0)
+ middle:SetPoint("RIGHT", right, "LEFT", 0, 0)
+ right:SetPoint("TOPRIGHT", dropdown, "TOPRIGHT", 0, 17)
+
+ local button = _G[dropdown:GetName() .. "Button"]
+ self.button = button
+ button.obj = self
+ button:SetScript("OnEnter",Control_OnEnter)
+ button:SetScript("OnLeave",Control_OnLeave)
+ button:SetScript("OnClick",Dropdown_TogglePullout)
+
+ local button_cover = CreateFrame("BUTTON",nil,self.frame)
+ self.button_cover = button_cover
+ button_cover.obj = self
+ button_cover:SetPoint("TOPLEFT",self.frame,"BOTTOMLEFT",0,25)
+ button_cover:SetPoint("BOTTOMRIGHT",self.frame,"BOTTOMRIGHT")
+ button_cover:SetScript("OnEnter",Control_OnEnter)
+ button_cover:SetScript("OnLeave",Control_OnLeave)
+ button_cover:SetScript("OnClick",Dropdown_TogglePullout)
+
+ local text = _G[dropdown:GetName() .. "Text"]
+ self.text = text
+ text.obj = self
+ text:ClearAllPoints()
+ text:SetPoint("RIGHT", right, "RIGHT" ,-43, 2)
+ text:SetPoint("LEFT", left, "LEFT", 25, 2)
+
+ local label = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
+ label:SetPoint("TOPLEFT",frame,"TOPLEFT",0,0)
+ label:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
+ label:SetJustifyH("LEFT")
+ label:SetHeight(18)
+ label:Hide()
+ self.label = label
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
+end
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua
new file mode 100644
index 0000000..49b483c
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua
@@ -0,0 +1,263 @@
+--[[-----------------------------------------------------------------------------
+EditBox Widget
+-------------------------------------------------------------------------------]]
+local Type, Version = "EditBox", 28
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local tostring, pairs = tostring, pairs
+
+-- WoW APIs
+local PlaySound = PlaySound
+local GetCursorInfo, ClearCursor, GetSpellInfo = GetCursorInfo, ClearCursor, GetSpellInfo
+local CreateFrame, UIParent = CreateFrame, UIParent
+local _G = _G
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: AceGUIEditBoxInsertLink, ChatFontNormal, OKAY
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+if not AceGUIEditBoxInsertLink then
+ -- upgradeable hook
+ hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIEditBoxInsertLink(...) end)
+end
+
+function _G.AceGUIEditBoxInsertLink(text)
+ for i = 1, AceGUI:GetWidgetCount(Type) do
+ local editbox = _G["AceGUI-3.0EditBox"..i]
+ if editbox and editbox:IsVisible() and editbox:HasFocus() then
+ editbox:Insert(text)
+ return true
+ end
+ end
+end
+
+local function ShowButton(self)
+ if not self.disablebutton then
+ self.button:Show()
+ self.editbox:SetTextInsets(0, 20, 3, 3)
+ end
+end
+
+local function HideButton(self)
+ self.button:Hide()
+ self.editbox:SetTextInsets(0, 0, 3, 3)
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function Frame_OnShowFocus(frame)
+ frame.obj.editbox:SetFocus()
+ frame:SetScript("OnShow", nil)
+end
+
+local function EditBox_OnEscapePressed(frame)
+ AceGUI:ClearFocus()
+end
+
+local function EditBox_OnEnterPressed(frame)
+ local self = frame.obj
+ local value = frame:GetText()
+ local cancel = self:Fire("OnEnterPressed", value)
+ if not cancel then
+ PlaySound("igMainMenuOptionCheckBoxOn")
+ HideButton(self)
+ end
+end
+
+local function EditBox_OnReceiveDrag(frame)
+ local self = frame.obj
+ local type, id, info = GetCursorInfo()
+ local name
+ if type == "item" then
+ name = info
+ elseif type == "spell" then
+ name = GetSpellInfo(id, info)
+ elseif type == "macro" then
+ name = GetMacroInfo(id)
+ end
+ if name then
+ self:SetText(name)
+ self:Fire("OnEnterPressed", name)
+ ClearCursor()
+ HideButton(self)
+ AceGUI:ClearFocus()
+ end
+end
+
+local function EditBox_OnTextChanged(frame)
+ local self = frame.obj
+ local value = frame:GetText()
+ if tostring(value) ~= tostring(self.lasttext) then
+ self:Fire("OnTextChanged", value)
+ self.lasttext = value
+ ShowButton(self)
+ end
+end
+
+local function EditBox_OnFocusGained(frame)
+ AceGUI:SetFocus(frame.obj)
+end
+
+local function Button_OnClick(frame)
+ local editbox = frame.obj.editbox
+ editbox:ClearFocus()
+ EditBox_OnEnterPressed(editbox)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ -- height is controlled by SetLabel
+ self:SetWidth(200)
+ self:SetDisabled(false)
+ self:SetLabel()
+ self:SetText()
+ self:DisableButton(false)
+ self:SetMaxLetters(0)
+ end,
+
+ ["OnRelease"] = function(self)
+ self:ClearFocus()
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.editbox:EnableMouse(false)
+ self.editbox:ClearFocus()
+ self.editbox:SetTextColor(0.5,0.5,0.5)
+ self.label:SetTextColor(0.5,0.5,0.5)
+ else
+ self.editbox:EnableMouse(true)
+ self.editbox:SetTextColor(1,1,1)
+ self.label:SetTextColor(1,.82,0)
+ end
+ end,
+
+ ["SetText"] = function(self, text)
+ self.lasttext = text or ""
+ self.editbox:SetText(text or "")
+ self.editbox:SetCursorPosition(0)
+ HideButton(self)
+ end,
+
+ ["GetText"] = function(self, text)
+ return self.editbox:GetText()
+ end,
+
+ ["SetLabel"] = function(self, text)
+ if text and text ~= "" then
+ self.label:SetText(text)
+ self.label:Show()
+ self.editbox:SetPoint("TOPLEFT",self.frame,"TOPLEFT",7,-18)
+ self:SetHeight(44)
+ self.alignoffset = 30
+ else
+ self.label:SetText("")
+ self.label:Hide()
+ self.editbox:SetPoint("TOPLEFT",self.frame,"TOPLEFT",7,0)
+ self:SetHeight(26)
+ self.alignoffset = 12
+ end
+ end,
+
+ ["DisableButton"] = function(self, disabled)
+ self.disablebutton = disabled
+ if disabled then
+ HideButton(self)
+ end
+ end,
+
+ ["SetMaxLetters"] = function (self, num)
+ self.editbox:SetMaxLetters(num or 0)
+ end,
+
+ ["ClearFocus"] = function(self)
+ self.editbox:ClearFocus()
+ self.frame:SetScript("OnShow", nil)
+ end,
+
+ ["SetFocus"] = function(self)
+ self.editbox:SetFocus()
+ if not self.frame:IsShown() then
+ self.frame:SetScript("OnShow", Frame_OnShowFocus)
+ end
+ end,
+
+ ["HighlightText"] = function(self, from, to)
+ self.editbox:HighlightText(from, to)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local num = AceGUI:GetNextWidgetNum(Type)
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:Hide()
+
+ local editbox = CreateFrame("EditBox", "AceGUI-3.0EditBox"..num, frame, "InputBoxTemplate")
+ editbox:SetAutoFocus(false)
+ editbox:SetFontObject(ChatFontNormal)
+ editbox:SetScript("OnEnter", Control_OnEnter)
+ editbox:SetScript("OnLeave", Control_OnLeave)
+ editbox:SetScript("OnEscapePressed", EditBox_OnEscapePressed)
+ editbox:SetScript("OnEnterPressed", EditBox_OnEnterPressed)
+ editbox:SetScript("OnTextChanged", EditBox_OnTextChanged)
+ editbox:SetScript("OnReceiveDrag", EditBox_OnReceiveDrag)
+ editbox:SetScript("OnMouseDown", EditBox_OnReceiveDrag)
+ editbox:SetScript("OnEditFocusGained", EditBox_OnFocusGained)
+ editbox:SetTextInsets(0, 0, 3, 3)
+ editbox:SetMaxLetters(256)
+ editbox:SetPoint("BOTTOMLEFT", 6, 0)
+ editbox:SetPoint("BOTTOMRIGHT")
+ editbox:SetHeight(19)
+
+ local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
+ label:SetPoint("TOPLEFT", 0, -2)
+ label:SetPoint("TOPRIGHT", 0, -2)
+ label:SetJustifyH("LEFT")
+ label:SetHeight(18)
+
+ local button = CreateFrame("Button", nil, editbox, "UIPanelButtonTemplate")
+ button:SetWidth(40)
+ button:SetHeight(20)
+ button:SetPoint("RIGHT", -2, 0)
+ button:SetText(OKAY)
+ button:SetScript("OnClick", Button_OnClick)
+ button:Hide()
+
+ local widget = {
+ alignoffset = 30,
+ editbox = editbox,
+ label = label,
+ button = button,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ editbox.obj, button.obj = widget, widget
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua
new file mode 100644
index 0000000..1aaf3f5
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua
@@ -0,0 +1,78 @@
+--[[-----------------------------------------------------------------------------
+Heading Widget
+-------------------------------------------------------------------------------]]
+local Type, Version = "Heading", 20
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs = pairs
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetText()
+ self:SetFullWidth()
+ self:SetHeight(18)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetText"] = function(self, text)
+ self.label:SetText(text or "")
+ if text and text ~= "" then
+ self.left:SetPoint("RIGHT", self.label, "LEFT", -5, 0)
+ self.right:Show()
+ else
+ self.left:SetPoint("RIGHT", -3, 0)
+ self.right:Hide()
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:Hide()
+
+ local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
+ label:SetPoint("TOP")
+ label:SetPoint("BOTTOM")
+ label:SetJustifyH("CENTER")
+
+ local left = frame:CreateTexture(nil, "BACKGROUND")
+ left:SetHeight(8)
+ left:SetPoint("LEFT", 3, 0)
+ left:SetPoint("RIGHT", label, "LEFT", -5, 0)
+ left:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
+ left:SetTexCoord(0.81, 0.94, 0.5, 1)
+
+ local right = frame:CreateTexture(nil, "BACKGROUND")
+ right:SetHeight(8)
+ right:SetPoint("RIGHT", -3, 0)
+ right:SetPoint("LEFT", label, "RIGHT", 5, 0)
+ right:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
+ right:SetTexCoord(0.81, 0.94, 0.5, 1)
+
+ local widget = {
+ label = label,
+ left = left,
+ right = right,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua
new file mode 100644
index 0000000..5fcf128
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua
@@ -0,0 +1,140 @@
+--[[-----------------------------------------------------------------------------
+Icon Widget
+-------------------------------------------------------------------------------]]
+local Type, Version = "Icon", 21
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local select, pairs, print = select, pairs, print
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function Button_OnClick(frame, button)
+ frame.obj:Fire("OnClick", button)
+ AceGUI:ClearFocus()
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetHeight(110)
+ self:SetWidth(110)
+ self:SetLabel()
+ self:SetImage(nil)
+ self:SetImageSize(64, 64)
+ self:SetDisabled(false)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetLabel"] = function(self, text)
+ if text and text ~= "" then
+ self.label:Show()
+ self.label:SetText(text)
+ self:SetHeight(self.image:GetHeight() + 25)
+ else
+ self.label:Hide()
+ self:SetHeight(self.image:GetHeight() + 10)
+ end
+ end,
+
+ ["SetImage"] = function(self, path, ...)
+ local image = self.image
+ image:SetTexture(path)
+
+ if image:GetTexture() then
+ local n = select("#", ...)
+ if n == 4 or n == 8 then
+ image:SetTexCoord(...)
+ else
+ image:SetTexCoord(0, 1, 0, 1)
+ end
+ end
+ end,
+
+ ["SetImageSize"] = function(self, width, height)
+ self.image:SetWidth(width)
+ self.image:SetHeight(height)
+ --self.frame:SetWidth(width + 30)
+ if self.label:IsShown() then
+ self:SetHeight(height + 25)
+ else
+ self:SetHeight(height + 10)
+ end
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ self.label:SetTextColor(0.5, 0.5, 0.5)
+ self.image:SetVertexColor(0.5, 0.5, 0.5, 0.5)
+ else
+ self.frame:Enable()
+ self.label:SetTextColor(1, 1, 1)
+ self.image:SetVertexColor(1, 1, 1, 1)
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Button", nil, UIParent)
+ frame:Hide()
+
+ frame:EnableMouse(true)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+ frame:SetScript("OnClick", Button_OnClick)
+
+ local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlight")
+ label:SetPoint("BOTTOMLEFT")
+ label:SetPoint("BOTTOMRIGHT")
+ label:SetJustifyH("CENTER")
+ label:SetJustifyV("TOP")
+ label:SetHeight(18)
+
+ local image = frame:CreateTexture(nil, "BACKGROUND")
+ image:SetWidth(64)
+ image:SetHeight(64)
+ image:SetPoint("TOP", 0, -5)
+
+ local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
+ highlight:SetAllPoints(image)
+ highlight:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight")
+ highlight:SetTexCoord(0, 1, 0.23, 0.77)
+ highlight:SetBlendMode("ADD")
+
+ local widget = {
+ label = label,
+ image = image,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ widget.SetText = widget.SetLabel
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua
new file mode 100644
index 0000000..255dd97
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua
@@ -0,0 +1,94 @@
+--[[-----------------------------------------------------------------------------
+InteractiveLabel Widget
+-------------------------------------------------------------------------------]]
+local Type, Version = "InteractiveLabel", 21
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local select, pairs = select, pairs
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function Label_OnClick(frame, button)
+ frame.obj:Fire("OnClick", button)
+ AceGUI:ClearFocus()
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:LabelOnAcquire()
+ self:SetHighlight()
+ self:SetHighlightTexCoord()
+ self:SetDisabled(false)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetHighlight"] = function(self, ...)
+ self.highlight:SetTexture(...)
+ end,
+
+ ["SetHighlightTexCoord"] = function(self, ...)
+ local c = select("#", ...)
+ if c == 4 or c == 8 then
+ self.highlight:SetTexCoord(...)
+ else
+ self.highlight:SetTexCoord(0, 1, 0, 1)
+ end
+ end,
+
+ ["SetDisabled"] = function(self,disabled)
+ self.disabled = disabled
+ if disabled then
+ self.frame:EnableMouse(false)
+ self.label:SetTextColor(0.5, 0.5, 0.5)
+ else
+ self.frame:EnableMouse(true)
+ self.label:SetTextColor(1, 1, 1)
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ -- create a Label type that we will hijack
+ local label = AceGUI:Create("Label")
+
+ local frame = label.frame
+ frame:EnableMouse(true)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+ frame:SetScript("OnMouseDown", Label_OnClick)
+
+ local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
+ highlight:SetTexture(nil)
+ highlight:SetAllPoints()
+ highlight:SetBlendMode("ADD")
+
+ label.highlight = highlight
+ label.type = Type
+ label.LabelOnAcquire = label.OnAcquire
+ for method, func in pairs(methods) do
+ label[method] = func
+ end
+
+ return label
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
+
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua
new file mode 100644
index 0000000..cd423c9
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua
@@ -0,0 +1,249 @@
+--[[-----------------------------------------------------------------------------
+Keybinding Widget
+Set Keybindings in the Config UI.
+-------------------------------------------------------------------------------]]
+local Type, Version = "Keybinding", 25
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs = pairs
+
+-- WoW APIs
+local IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown = IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: NOT_BOUND
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function Keybinding_OnClick(frame, button)
+ if button == "LeftButton" or button == "RightButton" then
+ local self = frame.obj
+ if self.waitingForKey then
+ frame:EnableKeyboard(false)
+ frame:EnableMouseWheel(false)
+ self.msgframe:Hide()
+ frame:UnlockHighlight()
+ self.waitingForKey = nil
+ else
+ frame:EnableKeyboard(true)
+ frame:EnableMouseWheel(true)
+ self.msgframe:Show()
+ frame:LockHighlight()
+ self.waitingForKey = true
+ end
+ end
+ AceGUI:ClearFocus()
+end
+
+local ignoreKeys = {
+ ["BUTTON1"] = true, ["BUTTON2"] = true,
+ ["UNKNOWN"] = true,
+ ["LSHIFT"] = true, ["LCTRL"] = true, ["LALT"] = true,
+ ["RSHIFT"] = true, ["RCTRL"] = true, ["RALT"] = true,
+}
+local function Keybinding_OnKeyDown(frame, key)
+ local self = frame.obj
+ if self.waitingForKey then
+ local keyPressed = key
+ if keyPressed == "ESCAPE" then
+ keyPressed = ""
+ else
+ if ignoreKeys[keyPressed] then return end
+ if IsShiftKeyDown() then
+ keyPressed = "SHIFT-"..keyPressed
+ end
+ if IsControlKeyDown() then
+ keyPressed = "CTRL-"..keyPressed
+ end
+ if IsAltKeyDown() then
+ keyPressed = "ALT-"..keyPressed
+ end
+ end
+
+ frame:EnableKeyboard(false)
+ frame:EnableMouseWheel(false)
+ self.msgframe:Hide()
+ frame:UnlockHighlight()
+ self.waitingForKey = nil
+
+ if not self.disabled then
+ self:SetKey(keyPressed)
+ self:Fire("OnKeyChanged", keyPressed)
+ end
+ end
+end
+
+local function Keybinding_OnMouseDown(frame, button)
+ if button == "LeftButton" or button == "RightButton" then
+ return
+ elseif button == "MiddleButton" then
+ button = "BUTTON3"
+ elseif button == "Button4" then
+ button = "BUTTON4"
+ elseif button == "Button5" then
+ button = "BUTTON5"
+ end
+ Keybinding_OnKeyDown(frame, button)
+end
+
+local function Keybinding_OnMouseWheel(frame, direction)
+ local button
+ if direction >= 0 then
+ button = "MOUSEWHEELUP"
+ else
+ button = "MOUSEWHEELDOWN"
+ end
+ Keybinding_OnKeyDown(frame, button)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetWidth(200)
+ self:SetLabel("")
+ self:SetKey("")
+ self.waitingForKey = nil
+ self.msgframe:Hide()
+ self:SetDisabled(false)
+ self.button:EnableKeyboard(false)
+ self.button:EnableMouseWheel(false)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.button:Disable()
+ self.label:SetTextColor(0.5,0.5,0.5)
+ else
+ self.button:Enable()
+ self.label:SetTextColor(1,1,1)
+ end
+ end,
+
+ ["SetKey"] = function(self, key)
+ if (key or "") == "" then
+ self.button:SetText(NOT_BOUND)
+ self.button:SetNormalFontObject("GameFontNormal")
+ else
+ self.button:SetText(key)
+ self.button:SetNormalFontObject("GameFontHighlight")
+ end
+ end,
+
+ ["GetKey"] = function(self)
+ local key = self.button:GetText()
+ if key == NOT_BOUND then
+ key = nil
+ end
+ return key
+ end,
+
+ ["SetLabel"] = function(self, label)
+ self.label:SetText(label or "")
+ if (label or "") == "" then
+ self.alignoffset = nil
+ self:SetHeight(24)
+ else
+ self.alignoffset = 30
+ self:SetHeight(44)
+ end
+ end,
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+
+local ControlBackdrop = {
+ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 3, bottom = 3 }
+}
+
+local function keybindingMsgFixWidth(frame)
+ frame:SetWidth(frame.msg:GetWidth() + 10)
+ frame:SetScript("OnUpdate", nil)
+end
+
+local function Constructor()
+ local name = "AceGUI30KeybindingButton" .. AceGUI:GetNextWidgetNum(Type)
+
+ local frame = CreateFrame("Frame", nil, UIParent)
+ local button = CreateFrame("Button", name, frame, "UIPanelButtonTemplate2")
+
+ button:EnableMouse(true)
+ button:EnableMouseWheel(false)
+ button:RegisterForClicks("AnyDown")
+ button:SetScript("OnEnter", Control_OnEnter)
+ button:SetScript("OnLeave", Control_OnLeave)
+ button:SetScript("OnClick", Keybinding_OnClick)
+ button:SetScript("OnKeyDown", Keybinding_OnKeyDown)
+ button:SetScript("OnMouseDown", Keybinding_OnMouseDown)
+ button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel)
+ button:SetPoint("BOTTOMLEFT")
+ button:SetPoint("BOTTOMRIGHT")
+ button:SetHeight(24)
+ button:EnableKeyboard(false)
+
+ local text = button:GetFontString()
+ text:SetPoint("LEFT", 7, 0)
+ text:SetPoint("RIGHT", -7, 0)
+
+ local label = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
+ label:SetPoint("TOPLEFT")
+ label:SetPoint("TOPRIGHT")
+ label:SetJustifyH("CENTER")
+ label:SetHeight(18)
+
+ local msgframe = CreateFrame("Frame", nil, UIParent)
+ msgframe:SetHeight(30)
+ msgframe:SetBackdrop(ControlBackdrop)
+ msgframe:SetBackdropColor(0,0,0)
+ msgframe:SetFrameStrata("FULLSCREEN_DIALOG")
+ msgframe:SetFrameLevel(1000)
+ msgframe:SetToplevel(true)
+
+ local msg = msgframe:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ msg:SetText("Press a key to bind, ESC to clear the binding or click the button again to cancel.")
+ msgframe.msg = msg
+ msg:SetPoint("TOPLEFT", 5, -5)
+ msgframe:SetScript("OnUpdate", keybindingMsgFixWidth)
+ msgframe:SetPoint("BOTTOM", button, "TOP")
+ msgframe:Hide()
+
+ local widget = {
+ button = button,
+ label = label,
+ msgframe = msgframe,
+ frame = frame,
+ alignoffset = 30,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ button.obj = widget
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Label.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Label.lua
new file mode 100644
index 0000000..5c75f3b
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Label.lua
@@ -0,0 +1,179 @@
+--[[-----------------------------------------------------------------------------
+Label Widget
+Displays text and optionally an icon.
+-------------------------------------------------------------------------------]]
+local Type, Version = "Label", 27
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local max, select, pairs = math.max, select, pairs
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: GameFontHighlightSmall
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+
+local function UpdateImageAnchor(self)
+ if self.resizing then return end
+ local frame = self.frame
+ local width = frame.width or frame:GetWidth() or 0
+ local image = self.image
+ local label = self.label
+ local height
+
+ label:ClearAllPoints()
+ image:ClearAllPoints()
+
+ if self.imageshown then
+ local imagewidth = image:GetWidth()
+ if (width - imagewidth) < 200 or (label:GetText() or "") == "" then
+ -- image goes on top centered when less than 200 width for the text, or if there is no text
+ image:SetPoint("TOP")
+ label:SetPoint("TOP", image, "BOTTOM")
+ label:SetPoint("LEFT")
+ label:SetWidth(width)
+ height = image:GetHeight() + label:GetStringHeight()
+ else
+ -- image on the left
+ image:SetPoint("TOPLEFT")
+ if image:GetHeight() > label:GetStringHeight() then
+ label:SetPoint("LEFT", image, "RIGHT", 4, 0)
+ else
+ label:SetPoint("TOPLEFT", image, "TOPRIGHT", 4, 0)
+ end
+ label:SetWidth(width - imagewidth - 4)
+ height = max(image:GetHeight(), label:GetStringHeight())
+ end
+ else
+ -- no image shown
+ label:SetPoint("TOPLEFT")
+ label:SetWidth(width)
+ height = label:GetStringHeight()
+ end
+
+ -- avoid zero-height labels, since they can used as spacers
+ if not height or height == 0 then
+ height = 1
+ end
+
+ self.resizing = true
+ frame:SetHeight(height)
+ frame.height = height
+ self.resizing = nil
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ -- set the flag to stop constant size updates
+ self.resizing = true
+ -- height is set dynamically by the text and image size
+ self:SetWidth(200)
+ self:SetText()
+ self:SetImage(nil)
+ self:SetImageSize(16, 16)
+ self:SetColor()
+ self:SetFontObject()
+ self:SetJustifyH("LEFT")
+ self:SetJustifyV("TOP")
+
+ -- reset the flag
+ self.resizing = nil
+ -- run the update explicitly
+ UpdateImageAnchor(self)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["OnWidthSet"] = function(self, width)
+ UpdateImageAnchor(self)
+ end,
+
+ ["SetText"] = function(self, text)
+ self.label:SetText(text)
+ UpdateImageAnchor(self)
+ end,
+
+ ["SetColor"] = function(self, r, g, b)
+ if not (r and g and b) then
+ r, g, b = 1, 1, 1
+ end
+ self.label:SetVertexColor(r, g, b)
+ end,
+
+ ["SetImage"] = function(self, path, ...)
+ local image = self.image
+ image:SetTexture(path)
+
+ if image:GetTexture() then
+ self.imageshown = true
+ local n = select("#", ...)
+ if n == 4 or n == 8 then
+ image:SetTexCoord(...)
+ else
+ image:SetTexCoord(0, 1, 0, 1)
+ end
+ else
+ self.imageshown = nil
+ end
+ UpdateImageAnchor(self)
+ end,
+
+ ["SetFont"] = function(self, font, height, flags)
+ self.label:SetFont(font, height, flags)
+ UpdateImageAnchor(self)
+ end,
+
+ ["SetFontObject"] = function(self, font)
+ self:SetFont((font or GameFontHighlightSmall):GetFont())
+ end,
+
+ ["SetImageSize"] = function(self, width, height)
+ self.image:SetWidth(width)
+ self.image:SetHeight(height)
+ UpdateImageAnchor(self)
+ end,
+
+ ["SetJustifyH"] = function(self, justifyH)
+ self.label:SetJustifyH(justifyH)
+ end,
+
+ ["SetJustifyV"] = function(self, justifyV)
+ self.label:SetJustifyV(justifyV)
+ end,
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:Hide()
+
+ local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall")
+ local image = frame:CreateTexture(nil, "BACKGROUND")
+
+ -- create widget
+ local widget = {
+ label = label,
+ image = image,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua
new file mode 100644
index 0000000..ebc94a7
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua
@@ -0,0 +1,366 @@
+local Type, Version = "MultiLineEditBox", 28
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs = pairs
+
+-- WoW APIs
+local GetCursorInfo, GetSpellInfo, ClearCursor = GetCursorInfo, GetSpellInfo, ClearCursor
+local CreateFrame, UIParent = CreateFrame, UIParent
+local _G = _G
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: ACCEPT, ChatFontNormal
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+
+if not AceGUIMultiLineEditBoxInsertLink then
+ -- upgradeable hook
+ hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIMultiLineEditBoxInsertLink(...) end)
+end
+
+function _G.AceGUIMultiLineEditBoxInsertLink(text)
+ for i = 1, AceGUI:GetWidgetCount(Type) do
+ local editbox = _G[("MultiLineEditBox%uEdit"):format(i)]
+ if editbox and editbox:IsVisible() and editbox:HasFocus() then
+ editbox:Insert(text)
+ return true
+ end
+ end
+end
+
+
+local function Layout(self)
+ self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight)
+
+ if self.labelHeight == 0 then
+ self.scrollBar:SetPoint("TOP", self.frame, "TOP", 0, -23)
+ else
+ self.scrollBar:SetPoint("TOP", self.label, "BOTTOM", 0, -19)
+ end
+
+ if self.disablebutton then
+ self.scrollBar:SetPoint("BOTTOM", self.frame, "BOTTOM", 0, 21)
+ self.scrollBG:SetPoint("BOTTOMLEFT", 0, 4)
+ else
+ self.scrollBar:SetPoint("BOTTOM", self.button, "TOP", 0, 18)
+ self.scrollBG:SetPoint("BOTTOMLEFT", self.button, "TOPLEFT")
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function OnClick(self) -- Button
+ self = self.obj
+ self.editBox:ClearFocus()
+ if not self:Fire("OnEnterPressed", self.editBox:GetText()) then
+ self.button:Disable()
+ end
+end
+
+local function OnCursorChanged(self, _, y, _, cursorHeight) -- EditBox
+ self, y = self.obj.scrollFrame, -y
+ local offset = self:GetVerticalScroll()
+ if y < offset then
+ self:SetVerticalScroll(y)
+ else
+ y = y + cursorHeight - self:GetHeight()
+ if y > offset then
+ self:SetVerticalScroll(y)
+ end
+ end
+end
+
+local function OnEditFocusLost(self) -- EditBox
+ self:HighlightText(0, 0)
+ self.obj:Fire("OnEditFocusLost")
+end
+
+local function OnEnter(self) -- EditBox / ScrollFrame
+ self = self.obj
+ if not self.entered then
+ self.entered = true
+ self:Fire("OnEnter")
+ end
+end
+
+local function OnLeave(self) -- EditBox / ScrollFrame
+ self = self.obj
+ if self.entered then
+ self.entered = nil
+ self:Fire("OnLeave")
+ end
+end
+
+local function OnMouseUp(self) -- ScrollFrame
+ self = self.obj.editBox
+ self:SetFocus()
+ self:SetCursorPosition(self:GetNumLetters())
+end
+
+local function OnReceiveDrag(self) -- EditBox / ScrollFrame
+ local type, id, info = GetCursorInfo()
+ if type == "spell" then
+ info = GetSpellInfo(id, info)
+ elseif type ~= "item" then
+ return
+ end
+ ClearCursor()
+ self = self.obj
+ local editBox = self.editBox
+ if not editBox:HasFocus() then
+ editBox:SetFocus()
+ editBox:SetCursorPosition(editBox:GetNumLetters())
+ end
+ editBox:Insert(info)
+ self.button:Enable()
+end
+
+local function OnSizeChanged(self, width, height) -- ScrollFrame
+ self.obj.editBox:SetWidth(width)
+end
+
+local function OnTextChanged(self, userInput) -- EditBox
+ if userInput then
+ self = self.obj
+ self:Fire("OnTextChanged", self.editBox:GetText())
+ self.button:Enable()
+ end
+end
+
+local function OnTextSet(self) -- EditBox
+ self:HighlightText(0, 0)
+ self:SetCursorPosition(self:GetNumLetters())
+ self:SetCursorPosition(0)
+ self.obj.button:Disable()
+end
+
+local function OnVerticalScroll(self, offset) -- ScrollFrame
+ local editBox = self.obj.editBox
+ editBox:SetHitRectInsets(0, 0, offset, editBox:GetHeight() - offset - self:GetHeight())
+end
+
+local function OnShowFocus(frame)
+ frame.obj.editBox:SetFocus()
+ frame:SetScript("OnShow", nil)
+end
+
+local function OnEditFocusGained(frame)
+ AceGUI:SetFocus(frame.obj)
+ frame.obj:Fire("OnEditFocusGained")
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self.editBox:SetText("")
+ self:SetDisabled(false)
+ self:SetWidth(200)
+ self:DisableButton(false)
+ self:SetNumLines()
+ self.entered = nil
+ self:SetMaxLetters(0)
+ end,
+
+ ["OnRelease"] = function(self)
+ self:ClearFocus()
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ local editBox = self.editBox
+ if disabled then
+ editBox:ClearFocus()
+ editBox:EnableMouse(false)
+ editBox:SetTextColor(0.5, 0.5, 0.5)
+ self.label:SetTextColor(0.5, 0.5, 0.5)
+ self.scrollFrame:EnableMouse(false)
+ self.button:Disable()
+ else
+ editBox:EnableMouse(true)
+ editBox:SetTextColor(1, 1, 1)
+ self.label:SetTextColor(1, 0.82, 0)
+ self.scrollFrame:EnableMouse(true)
+ end
+ end,
+
+ ["SetLabel"] = function(self, text)
+ if text and text ~= "" then
+ self.label:SetText(text)
+ if self.labelHeight ~= 10 then
+ self.labelHeight = 10
+ self.label:Show()
+ end
+ elseif self.labelHeight ~= 0 then
+ self.labelHeight = 0
+ self.label:Hide()
+ end
+ Layout(self)
+ end,
+
+ ["SetNumLines"] = function(self, value)
+ if not value or value < 4 then
+ value = 4
+ end
+ self.numlines = value
+ Layout(self)
+ end,
+
+ ["SetText"] = function(self, text)
+ self.editBox:SetText(text)
+ end,
+
+ ["GetText"] = function(self)
+ return self.editBox:GetText()
+ end,
+
+ ["SetMaxLetters"] = function (self, num)
+ self.editBox:SetMaxLetters(num or 0)
+ end,
+
+ ["DisableButton"] = function(self, disabled)
+ self.disablebutton = disabled
+ if disabled then
+ self.button:Hide()
+ else
+ self.button:Show()
+ end
+ Layout(self)
+ end,
+
+ ["ClearFocus"] = function(self)
+ self.editBox:ClearFocus()
+ self.frame:SetScript("OnShow", nil)
+ end,
+
+ ["SetFocus"] = function(self)
+ self.editBox:SetFocus()
+ if not self.frame:IsShown() then
+ self.frame:SetScript("OnShow", OnShowFocus)
+ end
+ end,
+
+ ["HighlightText"] = function(self, from, to)
+ self.editBox:HighlightText(from, to)
+ end,
+
+ ["GetCursorPosition"] = function(self)
+ return self.editBox:GetCursorPosition()
+ end,
+
+ ["SetCursorPosition"] = function(self, ...)
+ return self.editBox:SetCursorPosition(...)
+ end,
+
+
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local backdrop = {
+ bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
+ edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], edgeSize = 16,
+ insets = { left = 4, right = 3, top = 4, bottom = 3 }
+}
+
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:Hide()
+
+ local widgetNum = AceGUI:GetNextWidgetNum(Type)
+
+ local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
+ label:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, -4)
+ label:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -4)
+ label:SetJustifyH("LEFT")
+ label:SetText(ACCEPT)
+ label:SetHeight(10)
+
+ local button = CreateFrame("Button", ("%s%dButton"):format(Type, widgetNum), frame, "UIPanelButtonTemplate2")
+ button:SetPoint("BOTTOMLEFT", 0, 4)
+ button:SetHeight(22)
+ button:SetWidth(label:GetStringWidth() + 24)
+ button:SetText(ACCEPT)
+ button:SetScript("OnClick", OnClick)
+ button:Disable()
+
+ local text = button:GetFontString()
+ text:ClearAllPoints()
+ text:SetPoint("TOPLEFT", button, "TOPLEFT", 5, -5)
+ text:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -5, 1)
+ text:SetJustifyV("MIDDLE")
+
+ local scrollBG = CreateFrame("Frame", nil, frame)
+ scrollBG:SetBackdrop(backdrop)
+ scrollBG:SetBackdropColor(0, 0, 0)
+ scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4)
+
+ local scrollFrame = CreateFrame("ScrollFrame", ("%s%dScrollFrame"):format(Type, widgetNum), frame, "UIPanelScrollFrameTemplate")
+
+ local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"]
+ scrollBar:ClearAllPoints()
+ scrollBar:SetPoint("TOP", label, "BOTTOM", 0, -19)
+ scrollBar:SetPoint("BOTTOM", button, "TOP", 0, 18)
+ scrollBar:SetPoint("RIGHT", frame, "RIGHT")
+
+ scrollBG:SetPoint("TOPRIGHT", scrollBar, "TOPLEFT", 0, 19)
+ scrollBG:SetPoint("BOTTOMLEFT", button, "TOPLEFT")
+
+ scrollFrame:SetPoint("TOPLEFT", scrollBG, "TOPLEFT", 5, -6)
+ scrollFrame:SetPoint("BOTTOMRIGHT", scrollBG, "BOTTOMRIGHT", -4, 4)
+ scrollFrame:SetScript("OnEnter", OnEnter)
+ scrollFrame:SetScript("OnLeave", OnLeave)
+ scrollFrame:SetScript("OnMouseUp", OnMouseUp)
+ scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag)
+ scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
+ scrollFrame:HookScript("OnVerticalScroll", OnVerticalScroll)
+
+ local editBox = CreateFrame("EditBox", ("%s%dEdit"):format(Type, widgetNum), scrollFrame)
+ editBox:SetAllPoints()
+ editBox:SetFontObject(ChatFontNormal)
+ editBox:SetMultiLine(true)
+ editBox:EnableMouse(true)
+ editBox:SetAutoFocus(false)
+ editBox:SetCountInvisibleLetters(false)
+ editBox:SetScript("OnCursorChanged", OnCursorChanged)
+ editBox:SetScript("OnEditFocusLost", OnEditFocusLost)
+ editBox:SetScript("OnEnter", OnEnter)
+ editBox:SetScript("OnEscapePressed", editBox.ClearFocus)
+ editBox:SetScript("OnLeave", OnLeave)
+ editBox:SetScript("OnMouseDown", OnReceiveDrag)
+ editBox:SetScript("OnReceiveDrag", OnReceiveDrag)
+ editBox:SetScript("OnTextChanged", OnTextChanged)
+ editBox:SetScript("OnTextSet", OnTextSet)
+ editBox:SetScript("OnEditFocusGained", OnEditFocusGained)
+
+
+ scrollFrame:SetScrollChild(editBox)
+
+ local widget = {
+ button = button,
+ editBox = editBox,
+ frame = frame,
+ label = label,
+ labelHeight = 10,
+ numlines = 4,
+ scrollBar = scrollBar,
+ scrollBG = scrollBG,
+ scrollFrame = scrollFrame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ button.obj, editBox.obj, scrollFrame.obj = widget, widget, widget
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua
new file mode 100644
index 0000000..d663259
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Ace3/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua
@@ -0,0 +1,283 @@
+--[[-----------------------------------------------------------------------------
+Slider Widget
+Graphical Slider, like, for Range values.
+-------------------------------------------------------------------------------]]
+local Type, Version = "Slider", 20
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local min, max, floor = math.min, math.max, math.floor
+local tonumber, pairs = tonumber, pairs
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: GameFontHighlightSmall
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function UpdateText(self)
+ local value = self.value or 0
+ if self.ispercent then
+ self.editbox:SetText(("%s%%"):format(floor(value * 1000 + 0.5) / 10))
+ else
+ self.editbox:SetText(floor(value * 100 + 0.5) / 100)
+ end
+end
+
+local function UpdateLabels(self)
+ local min, max = (self.min or 0), (self.max or 100)
+ if self.ispercent then
+ self.lowtext:SetFormattedText("%s%%", (min * 100))
+ self.hightext:SetFormattedText("%s%%", (max * 100))
+ else
+ self.lowtext:SetText(min)
+ self.hightext:SetText(max)
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function Frame_OnMouseDown(frame)
+ frame.obj.slider:EnableMouseWheel(true)
+ AceGUI:ClearFocus()
+end
+
+local function Slider_OnValueChanged(frame, newvalue)
+ local self = frame.obj
+ if not frame.setup then
+ if newvalue ~= self.value and not self.disabled then
+ self.value = newvalue
+ self:Fire("OnValueChanged", newvalue)
+ end
+ if self.value then
+ UpdateText(self)
+ end
+ end
+end
+
+local function Slider_OnMouseUp(frame)
+ local self = frame.obj
+ self:Fire("OnMouseUp", self.value)
+end
+
+local function Slider_OnMouseWheel(frame, v)
+ local self = frame.obj
+ if not self.disabled then
+ local value = self.value
+ if v > 0 then
+ value = min(value + (self.step or 1), self.max)
+ else
+ value = max(value - (self.step or 1), self.min)
+ end
+ self.slider:SetValue(value)
+ end
+end
+
+local function EditBox_OnEscapePressed(frame)
+ frame:ClearFocus()
+end
+
+local function EditBox_OnEnterPressed(frame)
+ local self = frame.obj
+ local value = frame:GetText()
+ if self.ispercent then
+ value = value:gsub('%%', '')
+ value = tonumber(value) / 100
+ else
+ value = tonumber(value)
+ end
+
+ if value then
+ PlaySound("igMainMenuOptionCheckBoxOn")
+ self.slider:SetValue(value)
+ self:Fire("OnMouseUp", value)
+ end
+end
+
+local function EditBox_OnEnter(frame)
+ frame:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
+end
+
+local function EditBox_OnLeave(frame)
+ frame:SetBackdropBorderColor(0.3, 0.3, 0.3, 0.8)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetWidth(200)
+ self:SetHeight(44)
+ self:SetDisabled(false)
+ self:SetIsPercent(nil)
+ self:SetSliderValues(0,100,1)
+ self:SetValue(0)
+ self.slider:EnableMouseWheel(false)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.slider:EnableMouse(false)
+ self.label:SetTextColor(.5, .5, .5)
+ self.hightext:SetTextColor(.5, .5, .5)
+ self.lowtext:SetTextColor(.5, .5, .5)
+ --self.valuetext:SetTextColor(.5, .5, .5)
+ self.editbox:SetTextColor(.5, .5, .5)
+ self.editbox:EnableMouse(false)
+ self.editbox:ClearFocus()
+ else
+ self.slider:EnableMouse(true)
+ self.label:SetTextColor(1, .82, 0)
+ self.hightext:SetTextColor(1, 1, 1)
+ self.lowtext:SetTextColor(1, 1, 1)
+ --self.valuetext:SetTextColor(1, 1, 1)
+ self.editbox:SetTextColor(1, 1, 1)
+ self.editbox:EnableMouse(true)
+ end
+ end,
+
+ ["SetValue"] = function(self, value)
+ self.slider.setup = true
+ self.slider:SetValue(value)
+ self.value = value
+ UpdateText(self)
+ self.slider.setup = nil
+ end,
+
+ ["GetValue"] = function(self)
+ return self.value
+ end,
+
+ ["SetLabel"] = function(self, text)
+ self.label:SetText(text)
+ end,
+
+ ["SetSliderValues"] = function(self, min, max, step)
+ if type(min) == 'function' then min = min() end -- ElvUI
+ if type(max) == 'function' then max = max() end -- ElvUI
+
+ local frame = self.slider
+ frame.setup = true
+ self.min = min
+ self.max = max
+ self.step = step
+ frame:SetMinMaxValues(min or 0,max or 100)
+ UpdateLabels(self)
+ frame:SetValueStep(step or 1)
+ if self.value then
+ frame:SetValue(self.value)
+ end
+ frame.setup = nil
+ end,
+
+ ["SetIsPercent"] = function(self, value)
+ self.ispercent = value
+ UpdateLabels(self)
+ UpdateText(self)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local SliderBackdrop = {
+ bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
+ edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
+ tile = true, tileSize = 8, edgeSize = 8,
+ insets = { left = 3, right = 3, top = 6, bottom = 6 }
+}
+
+local ManualBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ tile = true, edgeSize = 1, tileSize = 5,
+}
+
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+
+ frame:EnableMouse(true)
+ frame:SetScript("OnMouseDown", Frame_OnMouseDown)
+
+ local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ label:SetPoint("TOPLEFT")
+ label:SetPoint("TOPRIGHT")
+ label:SetJustifyH("CENTER")
+ label:SetHeight(15)
+
+ local slider = CreateFrame("Slider", nil, frame)
+ slider:SetOrientation("HORIZONTAL")
+ slider:SetHeight(15)
+ slider:SetHitRectInsets(0, 0, -10, 0)
+ slider:SetBackdrop(SliderBackdrop)
+ slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Horizontal")
+ slider:SetPoint("TOP", label, "BOTTOM")
+ slider:SetPoint("LEFT", 3, 0)
+ slider:SetPoint("RIGHT", -3, 0)
+ slider:SetValue(0)
+ slider:SetScript("OnValueChanged",Slider_OnValueChanged)
+ slider:SetScript("OnEnter", Control_OnEnter)
+ slider:SetScript("OnLeave", Control_OnLeave)
+ slider:SetScript("OnMouseUp", Slider_OnMouseUp)
+ slider:SetScript("OnMouseWheel", Slider_OnMouseWheel)
+
+ local lowtext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ lowtext:SetPoint("TOPLEFT", slider, "BOTTOMLEFT", 2, 3)
+
+ local hightext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ hightext:SetPoint("TOPRIGHT", slider, "BOTTOMRIGHT", -2, 3)
+
+ local editbox = CreateFrame("EditBox", nil, frame)
+ editbox:SetAutoFocus(false)
+ editbox:SetFontObject(GameFontHighlightSmall)
+ editbox:SetPoint("TOP", slider, "BOTTOM")
+ editbox:SetHeight(14)
+ editbox:SetWidth(70)
+ editbox:SetJustifyH("CENTER")
+ editbox:EnableMouse(true)
+ editbox:SetBackdrop(ManualBackdrop)
+ editbox:SetBackdropColor(0, 0, 0, 0.5)
+ editbox:SetBackdropBorderColor(0.3, 0.3, 0.30, 0.80)
+ editbox:SetScript("OnEnter", EditBox_OnEnter)
+ editbox:SetScript("OnLeave", EditBox_OnLeave)
+ editbox:SetScript("OnEnterPressed", EditBox_OnEnterPressed)
+ editbox:SetScript("OnEscapePressed", EditBox_OnEscapePressed)
+
+ local widget = {
+ label = label,
+ slider = slider,
+ lowtext = lowtext,
+ hightext = hightext,
+ editbox = editbox,
+ alignoffset = 25,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ slider.obj, editbox.obj = widget, widget
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type,Constructor,Version)
diff --git a/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/BackgroundWidget.lua b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/BackgroundWidget.lua
new file mode 100644
index 0000000..3bb45ed
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/BackgroundWidget.lua
@@ -0,0 +1,235 @@
+-- Widget is based on the AceGUIWidget-DropDown.lua supplied with AceGUI-3.0
+-- Widget created by Yssaril
+
+local AceGUI = LibStub("AceGUI-3.0")
+local Media = LibStub("LibSharedMedia-3.0")
+
+local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0")
+
+do
+ local widgetType = "LSM30_Background"
+ local widgetVersion = 12
+
+ local contentFrameCache = {}
+ local function ReturnSelf(self)
+ self:ClearAllPoints()
+ self:Hide()
+ self.check:Hide()
+ table.insert(contentFrameCache, self)
+ end
+
+ local function ContentOnClick(this, button)
+ local self = this.obj
+ self:Fire("OnValueChanged", this.text:GetText())
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function ContentOnEnter(this, button)
+ local self = this.obj
+ local text = this.text:GetText()
+ local background = self.list[text] ~= text and self.list[text] or Media:Fetch('background',text)
+ self.dropdown.bgTex:SetTexture(background)
+ end
+
+ local function GetContentLine()
+ local frame
+ if next(contentFrameCache) then
+ frame = table.remove(contentFrameCache)
+ else
+ frame = CreateFrame("Button", nil, UIParent)
+ --frame:SetWidth(200)
+ frame:SetHeight(18)
+ frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
+ frame:SetScript("OnClick", ContentOnClick)
+ frame:SetScript("OnEnter", ContentOnEnter)
+
+ local check = frame:CreateTexture("OVERLAY")
+ check:SetWidth(16)
+ check:SetHeight(16)
+ check:SetPoint("LEFT",frame,"LEFT",1,-1)
+ check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+ check:Hide()
+ frame.check = check
+
+ local text = frame:CreateFontString(nil,"OVERLAY","GameFontWhite")
+ local font, size = text:GetFont()
+ text:SetFont(font,size,"OUTLINE")
+
+ text:SetPoint("TOPLEFT", check, "TOPRIGHT", 1, 0)
+ text:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -2, 0)
+ text:SetJustifyH("LEFT")
+ text:SetText("Test Test Test Test Test Test Test")
+ frame.text = text
+
+ frame.ReturnSelf = ReturnSelf
+ end
+ frame:Show()
+ return frame
+ end
+
+ local function OnAcquire(self)
+ self:SetHeight(44)
+ self:SetWidth(200)
+ end
+
+ local function OnRelease(self)
+ self:SetText("")
+ self:SetLabel("")
+ self:SetDisabled(false)
+
+ self.value = nil
+ self.list = nil
+ self.open = nil
+ self.hasClose = nil
+
+ self.frame:ClearAllPoints()
+ self.frame:Hide()
+ end
+
+ local function SetValue(self, value) -- Set the value to an item in the List.
+ if self.list then
+ self:SetText(value or "")
+ end
+ self.value = value
+ end
+
+ local function GetValue(self)
+ return self.value
+ end
+
+ local function SetList(self, list) -- Set the list of values for the dropdown (key => value pairs)
+ self.list = list or Media:HashTable("background")
+ end
+
+
+ local function SetText(self, text) -- Set the text displayed in the box.
+ self.frame.text:SetText(text or "")
+ local background = self.list[text] ~= text and self.list[text] or Media:Fetch('background',text)
+
+ self.frame.displayButton:SetBackdrop({bgFile = background,
+ edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
+ edgeSize = 16,
+ insets = { left = 4, right = 4, top = 4, bottom = 4 }})
+ end
+
+ local function SetLabel(self, text) -- Set the text for the label.
+ self.frame.label:SetText(text or "")
+ end
+
+ local function AddItem(self, key, value) -- Add an item to the list.
+ self.list = self.list or {}
+ self.list[key] = value
+ end
+ local SetItemValue = AddItem -- Set the value of a item in the list. <>
+
+ local function SetMultiselect(self, flag) end -- Toggle multi-selecting. <>
+ local function GetMultiselect() return false end-- Query the multi-select flag. <>
+ local function SetItemDisabled(self, key) end-- Disable one item in the list. <>
+
+ local function SetDisabled(self, disabled) -- Disable the widget.
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ self.frame.displayButton:SetBackdropColor(.2,.2,.2,1)
+ else
+ self.frame:Enable()
+ self.frame.displayButton:SetBackdropColor(1,1,1,1)
+ end
+ end
+
+ local function textSort(a,b)
+ return string.upper(a) < string.upper(b)
+ end
+
+ local sortedlist = {}
+ local function ToggleDrop(this)
+ local self = this.obj
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ AceGUI:ClearFocus()
+ else
+ AceGUI:SetFocus(self)
+ self.dropdown = AGSMW:GetDropDownFrame()
+ local width = self.frame:GetWidth()
+ self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT")
+ self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0)
+ for k, v in pairs(self.list) do
+ sortedlist[#sortedlist+1] = k
+ end
+ table.sort(sortedlist, textSort)
+ for i, k in ipairs(sortedlist) do
+ local f = GetContentLine()
+ f.text:SetText(k)
+ --print(k)
+ if k == self.value then
+ f.check:Show()
+ end
+ f.obj = self
+ f.dropdown = self.dropdown
+ self.dropdown:AddFrame(f)
+ end
+ wipe(sortedlist)
+ end
+ end
+
+ local function ClearFocus(self)
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function OnHide(this)
+ local self = this.obj
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function Drop_OnEnter(this)
+ this.obj:Fire("OnEnter")
+ end
+
+ local function Drop_OnLeave(this)
+ this.obj:Fire("OnLeave")
+ end
+
+ local function Constructor()
+ local frame = AGSMW:GetBaseFrameWithWindow()
+ local self = {}
+
+ self.type = widgetType
+ self.frame = frame
+ frame.obj = self
+ frame.dropButton.obj = self
+ frame.dropButton:SetScript("OnEnter", Drop_OnEnter)
+ frame.dropButton:SetScript("OnLeave", Drop_OnLeave)
+ frame.dropButton:SetScript("OnClick",ToggleDrop)
+ frame:SetScript("OnHide", OnHide)
+
+ self.alignoffset = 31
+
+ self.OnRelease = OnRelease
+ self.OnAcquire = OnAcquire
+ self.ClearFocus = ClearFocus
+ self.SetText = SetText
+ self.SetValue = SetValue
+ self.GetValue = GetValue
+ self.SetList = SetList
+ self.SetLabel = SetLabel
+ self.SetDisabled = SetDisabled
+ self.AddItem = AddItem
+ self.SetMultiselect = SetMultiselect
+ self.GetMultiselect = GetMultiselect
+ self.SetItemValue = SetItemValue
+ self.SetItemDisabled = SetItemDisabled
+ self.ToggleDrop = ToggleDrop
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
+
+end
diff --git a/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/BorderWidget.lua b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/BorderWidget.lua
new file mode 100644
index 0000000..2211a4c
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/BorderWidget.lua
@@ -0,0 +1,230 @@
+-- Widget is based on the AceGUIWidget-DropDown.lua supplied with AceGUI-3.0
+-- Widget created by Yssaril
+
+local AceGUI = LibStub("AceGUI-3.0")
+local Media = LibStub("LibSharedMedia-3.0")
+
+local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0")
+
+do
+ local widgetType = "LSM30_Border"
+ local widgetVersion = 12
+
+ local contentFrameCache = {}
+ local function ReturnSelf(self)
+ self:ClearAllPoints()
+ self:Hide()
+ self.check:Hide()
+ table.insert(contentFrameCache, self)
+ end
+
+ local function ContentOnClick(this, button)
+ local self = this.obj
+ self:Fire("OnValueChanged", this.text:GetText())
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function ContentOnEnter(this, button)
+ local self = this.obj
+ local text = this.text:GetText()
+ local border = self.list[text] ~= text and self.list[text] or Media:Fetch('border',text)
+ this.dropdown:SetBackdrop({edgeFile = border,
+ bgFile=[[Interface\DialogFrame\UI-DialogBox-Background-Dark]],
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 4, right = 4, top = 4, bottom = 4 }})
+ end
+
+ local function GetContentLine()
+ local frame
+ if next(contentFrameCache) then
+ frame = table.remove(contentFrameCache)
+ else
+ frame = CreateFrame("Button", nil, UIParent)
+ --frame:SetWidth(200)
+ frame:SetHeight(18)
+ frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
+ frame:SetScript("OnClick", ContentOnClick)
+ frame:SetScript("OnEnter", ContentOnEnter)
+ local check = frame:CreateTexture("OVERLAY")
+ check:SetWidth(16)
+ check:SetHeight(16)
+ check:SetPoint("LEFT",frame,"LEFT",1,-1)
+ check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+ check:Hide()
+ frame.check = check
+ local text = frame:CreateFontString(nil,"OVERLAY","GameFontWhite")
+ text:SetPoint("TOPLEFT", check, "TOPRIGHT", 1, 0)
+ text:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -2, 0)
+ text:SetJustifyH("LEFT")
+ text:SetText("Test Test Test Test Test Test Test")
+ frame.text = text
+ frame.ReturnSelf = ReturnSelf
+ end
+ frame:Show()
+ return frame
+ end
+
+ local function OnAcquire(self)
+ self:SetHeight(44)
+ self:SetWidth(200)
+ end
+
+ local function OnRelease(self)
+ self:SetText("")
+ self:SetLabel("")
+ self:SetDisabled(false)
+
+ self.value = nil
+ self.list = nil
+ self.open = nil
+ self.hasClose = nil
+
+ self.frame:ClearAllPoints()
+ self.frame:Hide()
+ end
+
+ local function SetValue(self, value) -- Set the value to an item in the List.
+ if self.list then
+ self:SetText(value or "")
+ end
+ self.value = value
+ end
+
+ local function GetValue(self)
+ return self.value
+ end
+
+ local function SetList(self, list) -- Set the list of values for the dropdown (key => value pairs)
+ self.list = list or Media:HashTable("border")
+ end
+
+
+ local function SetText(self, text) -- Set the text displayed in the box.
+ self.frame.text:SetText(text or "")
+ local border = self.list[text] ~= text and self.list[text] or Media:Fetch('border',text)
+
+ self.frame.displayButton:SetBackdrop({edgeFile = border,
+ bgFile=[[Interface\DialogFrame\UI-DialogBox-Background-Dark]],
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 4, right = 4, top = 4, bottom = 4 }})
+ end
+
+ local function SetLabel(self, text) -- Set the text for the label.
+ self.frame.label:SetText(text or "")
+ end
+
+ local function AddItem(self, key, value) -- Add an item to the list.
+ self.list = self.list or {}
+ self.list[key] = value
+ end
+ local SetItemValue = AddItem -- Set the value of a item in the list. <>
+
+ local function SetMultiselect(self, flag) end -- Toggle multi-selecting. <>
+ local function GetMultiselect() return false end-- Query the multi-select flag. <>
+ local function SetItemDisabled(self, key) end-- Disable one item in the list. <>
+
+ local function SetDisabled(self, disabled) -- Disable the widget.
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ else
+ self.frame:Enable()
+ end
+ end
+
+ local function textSort(a,b)
+ return string.upper(a) < string.upper(b)
+ end
+
+ local sortedlist = {}
+ local function ToggleDrop(this)
+ local self = this.obj
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ AceGUI:ClearFocus()
+ else
+ AceGUI:SetFocus(self)
+ self.dropdown = AGSMW:GetDropDownFrame()
+ local width = self.frame:GetWidth()
+ self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT")
+ self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0)
+ for k, v in pairs(self.list) do
+ sortedlist[#sortedlist+1] = k
+ end
+ table.sort(sortedlist, textSort)
+ for i, k in ipairs(sortedlist) do
+ local f = GetContentLine()
+ f.text:SetText(k)
+ --print(k)
+ if k == self.value then
+ f.check:Show()
+ end
+ f.obj = self
+ f.dropdown = self.dropdown
+ self.dropdown:AddFrame(f)
+ end
+ wipe(sortedlist)
+ end
+ end
+
+ local function ClearFocus(self)
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function OnHide(this)
+ local self = this.obj
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function Drop_OnEnter(this)
+ this.obj:Fire("OnEnter")
+ end
+
+ local function Drop_OnLeave(this)
+ this.obj:Fire("OnLeave")
+ end
+
+ local function Constructor()
+ local frame = AGSMW:GetBaseFrameWithWindow()
+ local self = {}
+
+ self.type = widgetType
+ self.frame = frame
+ frame.obj = self
+ frame.dropButton.obj = self
+ frame.dropButton:SetScript("OnEnter", Drop_OnEnter)
+ frame.dropButton:SetScript("OnLeave", Drop_OnLeave)
+ frame.dropButton:SetScript("OnClick",ToggleDrop)
+ frame:SetScript("OnHide", OnHide)
+
+ self.alignoffset = 31
+
+ self.OnRelease = OnRelease
+ self.OnAcquire = OnAcquire
+ self.ClearFocus = ClearFocus
+ self.SetText = SetText
+ self.SetValue = SetValue
+ self.GetValue = GetValue
+ self.SetList = SetList
+ self.SetLabel = SetLabel
+ self.SetDisabled = SetDisabled
+ self.AddItem = AddItem
+ self.SetMultiselect = SetMultiselect
+ self.GetMultiselect = GetMultiselect
+ self.SetItemValue = SetItemValue
+ self.SetItemDisabled = SetItemDisabled
+ self.ToggleDrop = ToggleDrop
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
+
+end
diff --git a/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/FontWidget.lua b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/FontWidget.lua
new file mode 100644
index 0000000..723b028
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/FontWidget.lua
@@ -0,0 +1,216 @@
+-- Widget is based on the AceGUIWidget-DropDown.lua supplied with AceGUI-3.0
+-- Widget created by Yssaril
+
+local AceGUI = LibStub("AceGUI-3.0")
+local Media = LibStub("LibSharedMedia-3.0")
+
+local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0")
+
+do
+ local widgetType = "LSM30_Font"
+ local widgetVersion = 12
+
+ local contentFrameCache = {}
+ local function ReturnSelf(self)
+ self:ClearAllPoints()
+ self:Hide()
+ self.check:Hide()
+ table.insert(contentFrameCache, self)
+ end
+
+ local function ContentOnClick(this, button)
+ local self = this.obj
+ self:Fire("OnValueChanged", this.text:GetText())
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function GetContentLine()
+ local frame
+ if next(contentFrameCache) then
+ frame = table.remove(contentFrameCache)
+ else
+ frame = CreateFrame("Button", nil, UIParent)
+ --frame:SetWidth(200)
+ frame:SetHeight(18)
+ frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
+ frame:SetScript("OnClick", ContentOnClick)
+ local check = frame:CreateTexture("OVERLAY")
+ check:SetWidth(16)
+ check:SetHeight(16)
+ check:SetPoint("LEFT",frame,"LEFT",1,-1)
+ check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+ check:Hide()
+ frame.check = check
+ local text = frame:CreateFontString(nil,"OVERLAY","GameFontWhite")
+ text:SetPoint("TOPLEFT", check, "TOPRIGHT", 1, 0)
+ text:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -2, 0)
+ text:SetJustifyH("LEFT")
+ text:SetText("Test Test Test Test Test Test Test")
+ frame.text = text
+ frame.ReturnSelf = ReturnSelf
+ end
+ frame:Show()
+ return frame
+ end
+
+ local function OnAcquire(self)
+ self:SetHeight(44)
+ self:SetWidth(200)
+ end
+
+ local function OnRelease(self)
+ self:SetText("")
+ self:SetLabel("")
+ self:SetDisabled(false)
+
+ self.value = nil
+ self.list = nil
+ self.open = nil
+ self.hasClose = nil
+
+ self.frame:ClearAllPoints()
+ self.frame:Hide()
+ end
+
+ local function SetValue(self, value) -- Set the value to an item in the List.
+ if self.list then
+ self:SetText(value or "")
+ end
+ self.value = value
+ end
+
+ local function GetValue(self)
+ return self.value
+ end
+
+ local function SetList(self, list) -- Set the list of values for the dropdown (key => value pairs)
+ self.list = list or Media:HashTable("font")
+ end
+
+ local function SetText(self, text) -- Set the text displayed in the box.
+ self.frame.text:SetText(text or "")
+ local font = self.list[text] ~= text and self.list[text] or Media:Fetch('font',text)
+ local _, size, outline= self.frame.text:GetFont()
+ self.frame.text:SetFont(font,size,outline)
+ end
+
+ local function SetLabel(self, text) -- Set the text for the label.
+ self.frame.label:SetText(text or "")
+ end
+
+ local function AddItem(self, key, value) -- Add an item to the list.
+ self.list = self.list or {}
+ self.list[key] = value
+ end
+ local SetItemValue = AddItem -- Set the value of a item in the list. <>
+
+ local function SetMultiselect(self, flag) end -- Toggle multi-selecting. <>
+ local function GetMultiselect() return false end-- Query the multi-select flag. <>
+ local function SetItemDisabled(self, key) end-- Disable one item in the list. <>
+
+ local function SetDisabled(self, disabled) -- Disable the widget.
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ else
+ self.frame:Enable()
+ end
+ end
+
+ local function textSort(a,b)
+ return string.upper(a) < string.upper(b)
+ end
+
+ local sortedlist = {}
+ local function ToggleDrop(this)
+ local self = this.obj
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ AceGUI:ClearFocus()
+ else
+ AceGUI:SetFocus(self)
+ self.dropdown = AGSMW:GetDropDownFrame()
+ local width = self.frame:GetWidth()
+ self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT")
+ self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0)
+ for k, v in pairs(self.list) do
+ sortedlist[#sortedlist+1] = k
+ end
+ table.sort(sortedlist, textSort)
+ for i, k in ipairs(sortedlist) do
+ local f = GetContentLine()
+ local _, size, outline= f.text:GetFont()
+ local font = self.list[k] ~= k and self.list[k] or Media:Fetch('font',k)
+ f.text:SetFont(font,size,outline)
+ f.text:SetText(k)
+ if k == self.value then
+ f.check:Show()
+ end
+ f.obj = self
+ self.dropdown:AddFrame(f)
+ end
+ wipe(sortedlist)
+ end
+ end
+
+ local function ClearFocus(self)
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function OnHide(this)
+ local self = this.obj
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function Drop_OnEnter(this)
+ this.obj:Fire("OnEnter")
+ end
+
+ local function Drop_OnLeave(this)
+ this.obj:Fire("OnLeave")
+ end
+
+ local function Constructor()
+ local frame = AGSMW:GetBaseFrame()
+ local self = {}
+
+ self.type = widgetType
+ self.frame = frame
+ frame.obj = self
+ frame.dropButton.obj = self
+ frame.dropButton:SetScript("OnEnter", Drop_OnEnter)
+ frame.dropButton:SetScript("OnLeave", Drop_OnLeave)
+ frame.dropButton:SetScript("OnClick",ToggleDrop)
+ frame:SetScript("OnHide", OnHide)
+
+ self.alignoffset = 31
+
+ self.OnRelease = OnRelease
+ self.OnAcquire = OnAcquire
+ self.ClearFocus = ClearFocus
+ self.SetText = SetText
+ self.SetValue = SetValue
+ self.GetValue = GetValue
+ self.SetList = SetList
+ self.SetLabel = SetLabel
+ self.SetDisabled = SetDisabled
+ self.AddItem = AddItem
+ self.SetMultiselect = SetMultiselect
+ self.GetMultiselect = GetMultiselect
+ self.SetItemValue = SetItemValue
+ self.SetItemDisabled = SetItemDisabled
+ self.ToggleDrop = ToggleDrop
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
+
+end
diff --git a/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/SoundWidget.lua b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/SoundWidget.lua
new file mode 100644
index 0000000..10c8aa4
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/SoundWidget.lua
@@ -0,0 +1,264 @@
+-- Widget is based on the AceGUIWidget-DropDown.lua supplied with AceGUI-3.0
+-- Widget created by Yssaril
+
+local AceGUI = LibStub("AceGUI-3.0")
+local Media = LibStub("LibSharedMedia-3.0")
+
+local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0")
+
+do
+ local widgetType = "LSM30_Sound"
+ local widgetVersion = 12
+
+ local contentFrameCache = {}
+ local function ReturnSelf(self)
+ self:ClearAllPoints()
+ self:Hide()
+ self.check:Hide()
+ table.insert(contentFrameCache, self)
+ end
+
+ local function ContentOnClick(this, button)
+ local self = this.obj
+ self:Fire("OnValueChanged", this.text:GetText())
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function ContentSpeakerOnClick(this, button)
+ local self = this.frame.obj
+ local sound = this.frame.text:GetText()
+ PlaySoundFile(self.list[sound] ~= sound and self.list[sound] or Media:Fetch('sound',sound), "Master")
+ end
+
+ local function GetContentLine()
+ local frame
+ if next(contentFrameCache) then
+ frame = table.remove(contentFrameCache)
+ else
+ frame = CreateFrame("Button", nil, UIParent)
+ --frame:SetWidth(200)
+ frame:SetHeight(18)
+ frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
+ frame:SetScript("OnClick", ContentOnClick)
+ local check = frame:CreateTexture("OVERLAY")
+ check:SetWidth(16)
+ check:SetHeight(16)
+ check:SetPoint("LEFT",frame,"LEFT",1,-1)
+ check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+ check:Hide()
+ frame.check = check
+
+ local soundbutton = CreateFrame("Button", nil, frame)
+ soundbutton:SetWidth(16)
+ soundbutton:SetHeight(16)
+ soundbutton:SetPoint("RIGHT",frame,"RIGHT",-1,0)
+ soundbutton.frame = frame
+ soundbutton:SetScript("OnClick", ContentSpeakerOnClick)
+ frame.soundbutton = soundbutton
+
+ local speaker = soundbutton:CreateTexture(nil, "BACKGROUND")
+ speaker:SetTexture("Interface\\Common\\VoiceChat-Speaker")
+ speaker:SetAllPoints(soundbutton)
+ frame.speaker = speaker
+ local speakeron = soundbutton:CreateTexture(nil, "HIGHLIGHT")
+ speakeron:SetTexture("Interface\\Common\\VoiceChat-On")
+ speakeron:SetAllPoints(soundbutton)
+ frame.speakeron = speakeron
+
+ local text = frame:CreateFontString(nil,"OVERLAY","GameFontWhite")
+ text:SetPoint("TOPLEFT", check, "TOPRIGHT", 1, 0)
+ text:SetPoint("BOTTOMRIGHT", soundbutton, "BOTTOMLEFT", -2, 0)
+ text:SetJustifyH("LEFT")
+ text:SetText("Test Test Test Test Test Test Test")
+ frame.text = text
+ frame.ReturnSelf = ReturnSelf
+ end
+ frame:Show()
+ return frame
+ end
+
+ local function OnAcquire(self)
+ self:SetHeight(44)
+ self:SetWidth(200)
+ end
+
+ local function OnRelease(self)
+ self:SetText("")
+ self:SetLabel("")
+ self:SetDisabled(false)
+
+ self.value = nil
+ self.list = nil
+ self.open = nil
+ self.hasClose = nil
+
+ self.frame:ClearAllPoints()
+ self.frame:Hide()
+ end
+
+ local function SetValue(self, value) -- Set the value to an item in the List.
+ if self.list then
+ self:SetText(value or "")
+ end
+ self.value = value
+ end
+
+ local function GetValue(self)
+ return self.value
+ end
+
+ local function SetList(self, list) -- Set the list of values for the dropdown (key => value pairs)
+ self.list = list or Media:HashTable("sound")
+ end
+
+ local function SetText(self, text) -- Set the text displayed in the box.
+ self.frame.text:SetText(text or "")
+ end
+
+ local function SetLabel(self, text) -- Set the text for the label.
+ self.frame.label:SetText(text or "")
+ end
+
+ local function AddItem(self, key, value) -- Add an item to the list.
+ self.list = self.list or {}
+ self.list[key] = value
+ end
+ local SetItemValue = AddItem -- Set the value of a item in the list. <>
+
+ local function SetMultiselect(self, flag) end -- Toggle multi-selecting. <>
+ local function GetMultiselect() return false end-- Query the multi-select flag. <>
+ local function SetItemDisabled(self, key) end-- Disable one item in the list. <>
+
+ local function SetDisabled(self, disabled) -- Disable the widget.
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ self.speaker:SetDesaturated(true)
+ self.speakeron:SetDesaturated(true)
+ else
+ self.frame:Enable()
+ self.speaker:SetDesaturated(false)
+ self.speakeron:SetDesaturated(false)
+ end
+ end
+
+ local function textSort(a,b)
+ return string.upper(a) < string.upper(b)
+ end
+
+ local sortedlist = {}
+ local function ToggleDrop(this)
+ local self = this.obj
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ AceGUI:ClearFocus()
+ else
+ AceGUI:SetFocus(self)
+ self.dropdown = AGSMW:GetDropDownFrame()
+ local width = self.frame:GetWidth()
+ self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT")
+ self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0)
+ for k, v in pairs(self.list) do
+ sortedlist[#sortedlist+1] = k
+ end
+ table.sort(sortedlist, textSort)
+ for i, k in ipairs(sortedlist) do
+ local f = GetContentLine()
+ f.text:SetText(k)
+ if k == self.value then
+ f.check:Show()
+ end
+ f.obj = self
+ self.dropdown:AddFrame(f)
+ end
+ wipe(sortedlist)
+ end
+ end
+
+ local function ClearFocus(self)
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function OnHide(this)
+ local self = this.obj
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function Drop_OnEnter(this)
+ this.obj:Fire("OnEnter")
+ end
+
+ local function Drop_OnLeave(this)
+ this.obj:Fire("OnLeave")
+ end
+
+ local function WidgetPlaySound(this)
+ local self = this.obj
+ local sound = self.frame.text:GetText()
+ PlaySoundFile(self.list[sound] ~= sound and self.list[sound] or Media:Fetch('sound',sound), "Master")
+ end
+
+ local function Constructor()
+ local frame = AGSMW:GetBaseFrame()
+ local self = {}
+
+ self.type = widgetType
+ self.frame = frame
+ frame.obj = self
+ frame.dropButton.obj = self
+ frame.dropButton:SetScript("OnEnter", Drop_OnEnter)
+ frame.dropButton:SetScript("OnLeave", Drop_OnLeave)
+ frame.dropButton:SetScript("OnClick",ToggleDrop)
+ frame:SetScript("OnHide", OnHide)
+
+
+ local soundbutton = CreateFrame("Button", nil, frame)
+ soundbutton:SetWidth(16)
+ soundbutton:SetHeight(16)
+ soundbutton:SetPoint("LEFT",frame.DLeft,"LEFT",26,1)
+ soundbutton:SetScript("OnClick", WidgetPlaySound)
+ soundbutton.obj = self
+ self.soundbutton = soundbutton
+ frame.text:SetPoint("LEFT",soundbutton,"RIGHT",2,0)
+
+
+ local speaker = soundbutton:CreateTexture(nil, "BACKGROUND")
+ speaker:SetTexture("Interface\\Common\\VoiceChat-Speaker")
+ speaker:SetAllPoints(soundbutton)
+ self.speaker = speaker
+ local speakeron = soundbutton:CreateTexture(nil, "HIGHLIGHT")
+ speakeron:SetTexture("Interface\\Common\\VoiceChat-On")
+ speakeron:SetAllPoints(soundbutton)
+ self.speakeron = speakeron
+
+ self.alignoffset = 31
+
+ self.OnRelease = OnRelease
+ self.OnAcquire = OnAcquire
+ self.ClearFocus = ClearFocus
+ self.SetText = SetText
+ self.SetValue = SetValue
+ self.GetValue = GetValue
+ self.SetList = SetList
+ self.SetLabel = SetLabel
+ self.SetDisabled = SetDisabled
+ self.AddItem = AddItem
+ self.SetMultiselect = SetMultiselect
+ self.GetMultiselect = GetMultiselect
+ self.SetItemValue = SetItemValue
+ self.SetItemDisabled = SetItemDisabled
+ self.ToggleDrop = ToggleDrop
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
+
+end
diff --git a/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/StatusbarWidget.lua b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/StatusbarWidget.lua
new file mode 100644
index 0000000..824ce07
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/StatusbarWidget.lua
@@ -0,0 +1,233 @@
+-- Widget is based on the AceGUIWidget-DropDown.lua supplied with AceGUI-3.0
+-- Widget created by Yssaril
+
+local AceGUI = LibStub("AceGUI-3.0")
+local Media = LibStub("LibSharedMedia-3.0")
+
+local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0")
+
+do
+ local widgetType = "LSM30_Statusbar"
+ local widgetVersion = 12
+
+ local contentFrameCache = {}
+ local function ReturnSelf(self)
+ self:ClearAllPoints()
+ self:Hide()
+ self.check:Hide()
+ table.insert(contentFrameCache, self)
+ end
+
+ local function ContentOnClick(this, button)
+ local self = this.obj
+ self:Fire("OnValueChanged", this.text:GetText())
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function GetContentLine()
+ local frame
+ if next(contentFrameCache) then
+ frame = table.remove(contentFrameCache)
+ else
+ frame = CreateFrame("Button", nil, UIParent)
+ --frame:SetWidth(200)
+ frame:SetHeight(18)
+ frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
+ frame:SetScript("OnClick", ContentOnClick)
+ local check = frame:CreateTexture("OVERLAY")
+ check:SetWidth(16)
+ check:SetHeight(16)
+ check:SetPoint("LEFT",frame,"LEFT",1,-1)
+ check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+ check:Hide()
+ frame.check = check
+ local bar = frame:CreateTexture("ARTWORK")
+ bar:SetHeight(16)
+ bar:SetPoint("LEFT",check,"RIGHT",1,0)
+ bar:SetPoint("RIGHT",frame,"RIGHT",-1,0)
+ frame.bar = bar
+ local text = frame:CreateFontString(nil,"OVERLAY","GameFontWhite")
+
+ local font, size = text:GetFont()
+ text:SetFont(font,size,"OUTLINE")
+
+ text:SetPoint("TOPLEFT", check, "TOPRIGHT", 3, 0)
+ text:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -2, 0)
+ text:SetJustifyH("LEFT")
+ text:SetText("Test Test Test Test Test Test Test")
+ frame.text = text
+ frame.ReturnSelf = ReturnSelf
+ end
+ frame:Show()
+ return frame
+ end
+
+ local function OnAcquire(self)
+ self:SetHeight(44)
+ self:SetWidth(200)
+ end
+
+ local function OnRelease(self)
+ self:SetText("")
+ self:SetLabel("")
+ self:SetDisabled(false)
+
+ self.value = nil
+ self.list = nil
+ self.open = nil
+ self.hasClose = nil
+
+ self.frame:ClearAllPoints()
+ self.frame:Hide()
+ end
+
+ local function SetValue(self, value) -- Set the value to an item in the List.
+ if self.list then
+ self:SetText(value or "")
+ end
+ self.value = value
+ end
+
+ local function GetValue(self)
+ return self.value
+ end
+
+ local function SetList(self, list) -- Set the list of values for the dropdown (key => value pairs)
+ self.list = list or Media:HashTable("statusbar")
+ end
+
+
+ local function SetText(self, text) -- Set the text displayed in the box.
+ self.frame.text:SetText(text or "")
+ local statusbar = self.list[text] ~= text and self.list[text] or Media:Fetch('statusbar',text)
+ self.bar:SetTexture(statusbar)
+ end
+
+ local function SetLabel(self, text) -- Set the text for the label.
+ self.frame.label:SetText(text or "")
+ end
+
+ local function AddItem(self, key, value) -- Add an item to the list.
+ self.list = self.list or {}
+ self.list[key] = value
+ end
+ local SetItemValue = AddItem -- Set the value of a item in the list. <>
+
+ local function SetMultiselect(self, flag) end -- Toggle multi-selecting. <>
+ local function GetMultiselect() return false end-- Query the multi-select flag. <>
+ local function SetItemDisabled(self, key) end-- Disable one item in the list. <>
+
+ local function SetDisabled(self, disabled) -- Disable the widget.
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ else
+ self.frame:Enable()
+ end
+ end
+
+ local function textSort(a,b)
+ return string.upper(a) < string.upper(b)
+ end
+
+ local sortedlist = {}
+ local function ToggleDrop(this)
+ local self = this.obj
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ AceGUI:ClearFocus()
+ else
+ AceGUI:SetFocus(self)
+ self.dropdown = AGSMW:GetDropDownFrame()
+ local width = self.frame:GetWidth()
+ self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT")
+ self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0)
+ for k, v in pairs(self.list) do
+ sortedlist[#sortedlist+1] = k
+ end
+ table.sort(sortedlist, textSort)
+ for i, k in ipairs(sortedlist) do
+ local f = GetContentLine()
+ f.text:SetText(k)
+ --print(k)
+ if k == self.value then
+ f.check:Show()
+ end
+
+ local statusbar = self.list[k] ~= k and self.list[k] or Media:Fetch('statusbar',k)
+ f.bar:SetTexture(statusbar)
+ f.obj = self
+ f.dropdown = self.dropdown
+ self.dropdown:AddFrame(f)
+ end
+ wipe(sortedlist)
+ end
+ end
+
+ local function ClearFocus(self)
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function OnHide(this)
+ local self = this.obj
+ if self.dropdown then
+ self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
+ end
+ end
+
+ local function Drop_OnEnter(this)
+ this.obj:Fire("OnEnter")
+ end
+
+ local function Drop_OnLeave(this)
+ this.obj:Fire("OnLeave")
+ end
+
+ local function Constructor()
+ local frame = AGSMW:GetBaseFrame()
+ local self = {}
+
+ self.type = widgetType
+ self.frame = frame
+ frame.obj = self
+ frame.dropButton.obj = self
+ frame.dropButton:SetScript("OnEnter", Drop_OnEnter)
+ frame.dropButton:SetScript("OnLeave", Drop_OnLeave)
+ frame.dropButton:SetScript("OnClick",ToggleDrop)
+ frame:SetScript("OnHide", OnHide)
+
+ local bar = frame:CreateTexture(nil, "OVERLAY")
+ bar:SetPoint("TOPLEFT", frame,"TOPLEFT",6,-25)
+ bar:SetPoint("BOTTOMRIGHT", frame,"BOTTOMRIGHT", -21, 5)
+ bar:SetAlpha(0.5)
+ self.bar = bar
+
+ self.alignoffset = 31
+
+ self.OnRelease = OnRelease
+ self.OnAcquire = OnAcquire
+ self.ClearFocus = ClearFocus
+ self.SetText = SetText
+ self.SetValue = SetValue
+ self.GetValue = GetValue
+ self.SetList = SetList
+ self.SetLabel = SetLabel
+ self.SetDisabled = SetDisabled
+ self.AddItem = AddItem
+ self.SetMultiselect = SetMultiselect
+ self.GetMultiselect = GetMultiselect
+ self.SetItemValue = SetItemValue
+ self.SetItemDisabled = SetItemDisabled
+ self.ToggleDrop = ToggleDrop
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
+
+end
diff --git a/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/prototypes.lua b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/prototypes.lua
new file mode 100644
index 0000000..f77cfa0
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/prototypes.lua
@@ -0,0 +1,266 @@
+-- Widget created by Yssaril
+local DataVersion = 9003
+local AGSMW = LibStub:NewLibrary("AceGUISharedMediaWidgets-1.0", DataVersion)
+
+if not AGSMW then
+ return -- already loaded and no upgrade necessary
+end
+
+local AceGUI = LibStub("AceGUI-3.0")
+local Media = LibStub("LibSharedMedia-3.0")
+
+AGSMW = AGSMW or {}
+
+AceGUIWidgetLSMlists = {
+ ['font'] = Media:HashTable("font"),
+ ['sound'] = Media:HashTable("sound"),
+ ['statusbar'] = Media:HashTable("statusbar"),
+ ['border'] = Media:HashTable("border"),
+ ['background'] = Media:HashTable("background"),
+}
+
+do
+ local function disable(frame)
+ frame.label:SetTextColor(.5,.5,.5)
+ frame.text:SetTextColor(.5,.5,.5)
+ frame.dropButton:Disable()
+ if frame.displayButtonFont then
+ frame.displayButtonFont:SetTextColor(.5,.5,.5)
+ frame.displayButton:Disable()
+ end
+ end
+
+ local function enable(frame)
+ frame.label:SetTextColor(1,.82,0)
+ frame.text:SetTextColor(1,1,1)
+ frame.dropButton:Enable()
+ if frame.displayButtonFont then
+ frame.displayButtonFont:SetTextColor(1,1,1)
+ frame.displayButton:Enable()
+ end
+ end
+
+ local displayButtonBackdrop = {
+ edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 4, right = 4, top = 4, bottom = 4 },
+ }
+
+ -- create or retrieve BaseFrame
+ function AGSMW:GetBaseFrame()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:SetHeight(44)
+ frame:SetWidth(200)
+
+ local label = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
+ label:SetPoint("TOPLEFT",frame,"TOPLEFT",0,0)
+ label:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
+ label:SetJustifyH("LEFT")
+ label:SetHeight(18)
+ label:SetText("")
+ frame.label = label
+
+ local DLeft = frame:CreateTexture(nil, "ARTWORK")
+ DLeft:SetWidth(25)
+ DLeft:SetHeight(64)
+ DLeft:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", -17, -21)
+ DLeft:SetTexture([[Interface\Glues\CharacterCreate\CharacterCreate-LabelFrame]])
+ DLeft:SetTexCoord(0, 0.1953125, 0, 1)
+ frame.DLeft = DLeft
+
+ local DRight = frame:CreateTexture(nil, "ARTWORK")
+ DRight:SetWidth(25)
+ DRight:SetHeight(64)
+ DRight:SetPoint("TOP", DLeft, "TOP")
+ DRight:SetPoint("RIGHT", frame, "RIGHT", 17, 0)
+ DRight:SetTexture([[Interface\Glues\CharacterCreate\CharacterCreate-LabelFrame]])
+ DRight:SetTexCoord(0.8046875, 1, 0, 1)
+ frame.DRight = DRight
+
+ local DMiddle = frame:CreateTexture(nil, "ARTWORK")
+ DMiddle:SetHeight(64)
+ DMiddle:SetPoint("TOP", DLeft, "TOP")
+ DMiddle:SetPoint("LEFT", DLeft, "RIGHT")
+ DMiddle:SetPoint("RIGHT", DRight, "LEFT")
+ DMiddle:SetTexture([[Interface\Glues\CharacterCreate\CharacterCreate-LabelFrame]])
+ DMiddle:SetTexCoord(0.1953125, 0.8046875, 0, 1)
+ frame.DMiddle = DMiddle
+
+ local text = frame:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall")
+ text:SetPoint("RIGHT",DRight,"RIGHT",-43,1)
+ text:SetPoint("LEFT",DLeft,"LEFT",26,1)
+ text:SetJustifyH("RIGHT")
+ text:SetHeight(18)
+ text:SetText("")
+ frame.text = text
+
+ local dropButton = CreateFrame("Button", nil, frame)
+ dropButton:SetWidth(24)
+ dropButton:SetHeight(24)
+ dropButton:SetPoint("TOPRIGHT", DRight, "TOPRIGHT", -16, -18)
+ dropButton:SetNormalTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollDown-Up]])
+ dropButton:SetPushedTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollDown-Down]])
+ dropButton:SetDisabledTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollDown-Disabled]])
+ dropButton:SetHighlightTexture([[Interface\Buttons\UI-Common-MouseHilight]], "ADD")
+ frame.dropButton = dropButton
+
+ frame.Disable = disable
+ frame.Enable = enable
+ return frame
+ end
+
+ function AGSMW:GetBaseFrameWithWindow()
+ local frame = self:GetBaseFrame()
+
+ local displayButton = CreateFrame("Button", nil, frame)
+ displayButton:SetHeight(42)
+ displayButton:SetWidth(42)
+ displayButton:SetPoint("TOPLEFT", frame, "TOPLEFT", 1, -2)
+ displayButton:SetBackdrop(displayButtonBackdrop)
+ displayButton:SetBackdropBorderColor(.5, .5, .5)
+ frame.displayButton = displayButton
+
+ frame.label:SetPoint("TOPLEFT",displayButton,"TOPRIGHT",1,2)
+
+ frame.DLeft:SetPoint("BOTTOMLEFT", displayButton, "BOTTOMRIGHT", -17, -20)
+
+ return frame
+ end
+
+end
+
+do
+
+ local sliderBackdrop = {
+ ["bgFile"] = [[Interface\Buttons\UI-SliderBar-Background]],
+ ["edgeFile"] = [[Interface\Buttons\UI-SliderBar-Border]],
+ ["tile"] = true,
+ ["edgeSize"] = 8,
+ ["tileSize"] = 8,
+ ["insets"] = {
+ ["left"] = 3,
+ ["right"] = 3,
+ ["top"] = 3,
+ ["bottom"] = 3,
+ },
+ }
+ local frameBackdrop = {
+ bgFile=[[Interface\DialogFrame\UI-DialogBox-Background-Dark]],
+ edgeFile = [[Interface\DialogFrame\UI-DialogBox-Border]],
+ tile = true, tileSize = 32, edgeSize = 32,
+ insets = { left = 11, right = 12, top = 12, bottom = 9 },
+ }
+
+ local function OnMouseWheel(self, dir)
+ self.slider:SetValue(self.slider:GetValue()+(15*dir*-1))
+ end
+
+ local function AddFrame(self, frame)
+ frame:SetParent(self.contentframe)
+ frame:SetFrameStrata(self:GetFrameStrata())
+ frame:SetFrameLevel(self:GetFrameLevel() + 100)
+
+ if next(self.contentRepo) then
+ frame:SetPoint("TOPLEFT", self.contentRepo[#self.contentRepo], "BOTTOMLEFT", 0, 0)
+ frame:SetPoint("RIGHT", self.contentframe, "RIGHT", 0, 0)
+ self.contentframe:SetHeight(self.contentframe:GetHeight() + frame:GetHeight())
+ self.contentRepo[#self.contentRepo+1] = frame
+ else
+ self.contentframe:SetHeight(frame:GetHeight())
+ frame:SetPoint("TOPLEFT", self.contentframe, "TOPLEFT", 0, 0)
+ frame:SetPoint("RIGHT", self.contentframe, "RIGHT", 0, 0)
+ self.contentRepo[1] = frame
+ end
+
+ if self.contentframe:GetHeight() > UIParent:GetHeight()*2/5 - 20 then
+ self.scrollframe:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -28, 12)
+ self:SetHeight(UIParent:GetHeight()*2/5)
+ self.slider:Show()
+ self:SetScript("OnMouseWheel", OnMouseWheel)
+ self.slider:SetMinMaxValues(0, self.contentframe:GetHeight()-self.scrollframe:GetHeight())
+ else
+ self.scrollframe:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -14, 12)
+ self:SetHeight(self.contentframe:GetHeight()+25)
+ self.slider:Hide()
+ self:SetScript("OnMouseWheel", nil)
+ self.slider:SetMinMaxValues(0, 0)
+ end
+ self.contentframe:SetWidth(self.scrollframe:GetWidth())
+ end
+
+ local function ClearFrames(self)
+ for i, frame in ipairs(self.contentRepo) do
+ frame:ReturnSelf()
+ self.contentRepo[i] = nil
+ end
+ end
+
+ local function slider_OnValueChanged(self, value)
+ self.frame.scrollframe:SetVerticalScroll(value)
+ end
+
+ local DropDownCache = {}
+ function AGSMW:GetDropDownFrame()
+ local frame
+ if next(DropDownCache) then
+ frame = table.remove(DropDownCache)
+ else
+ frame = CreateFrame("Frame", nil, UIParent)
+ frame:SetClampedToScreen(true)
+ frame:SetWidth(188)
+ frame:SetBackdrop(frameBackdrop)
+ frame:SetFrameStrata("TOOLTIP")
+ frame:EnableMouseWheel(true)
+
+ local contentframe = CreateFrame("Frame", nil, frame)
+ contentframe:SetWidth(160)
+ contentframe:SetHeight(0)
+ frame.contentframe = contentframe
+
+ local scrollframe = CreateFrame("ScrollFrame", nil, frame)
+ scrollframe:SetWidth(160)
+ scrollframe:SetPoint("TOPLEFT", frame, "TOPLEFT", 14, -13)
+ scrollframe:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -14, 12)
+ scrollframe:SetScrollChild(contentframe)
+ frame.scrollframe = scrollframe
+
+ contentframe:SetPoint("TOPLEFT", scrollframe)
+ contentframe:SetPoint("TOPRIGHT", scrollframe)
+
+ local bgTex = frame:CreateTexture(nil, "ARTWORK")
+ bgTex:SetAllPoints(scrollframe)
+ frame.bgTex = bgTex
+
+ frame.AddFrame = AddFrame
+ frame.ClearFrames = ClearFrames
+ frame.contentRepo = {} -- store all our frames in here so we can get rid of them later
+
+ local slider = CreateFrame("Slider", nil, scrollframe)
+ slider:SetOrientation("VERTICAL")
+ slider:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -14, -10)
+ slider:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -14, 10)
+ slider:SetBackdrop(sliderBackdrop)
+ slider:SetThumbTexture([[Interface\Buttons\UI-SliderBar-Button-Vertical]])
+ slider:SetMinMaxValues(0, 1)
+ --slider:SetValueStep(1)
+ slider:SetWidth(12)
+ slider.frame = frame
+ slider:SetScript("OnValueChanged", slider_OnValueChanged)
+ frame.slider = slider
+ end
+ frame:SetHeight(UIParent:GetHeight()*2/5)
+ frame.slider:SetValue(0)
+ frame:Show()
+ return frame
+ end
+
+ function AGSMW:ReturnDropDownFrame(frame)
+ ClearFrames(frame)
+ frame:ClearAllPoints()
+ frame:Hide()
+ frame:SetBackdrop(frameBackdrop)
+ frame.bgTex:SetTexture(nil)
+ table.insert(DropDownCache, frame)
+ return nil
+ end
+end
diff --git a/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/widget.xml b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/widget.xml
new file mode 100644
index 0000000..15cd102
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/AceGUI-3.0-SharedMediaWidgets/widget.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Libraries/Load_Libraries.xml b/ElvUI_OptionsUI/Libraries/Load_Libraries.xml
new file mode 100644
index 0000000..5bcf854
--- /dev/null
+++ b/ElvUI_OptionsUI/Libraries/Load_Libraries.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Locales/Load_Locales.xml b/ElvUI_OptionsUI/Locales/Load_Locales.xml
new file mode 100644
index 0000000..68ff9ba
--- /dev/null
+++ b/ElvUI_OptionsUI/Locales/Load_Locales.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Locales/deDE.lua b/ElvUI_OptionsUI/Locales/deDE.lua
new file mode 100644
index 0000000..4b14a35
--- /dev/null
+++ b/ElvUI_OptionsUI/Locales/deDE.lua
@@ -0,0 +1,1394 @@
+-- German localization file for deDE.
+local L = ElvUI[1].Libs.ACL:NewLocale("ElvUI", "deDE")
+
+L["%s and then %s"] = "%s und dann %s"
+L["2D"] = "2D"
+L["3D"] = "3D"
+L["AFK Mode"] = "AFK Modus"
+L["ANCHOR_CURSOR"] = "Mausanker"
+L["ANCHOR_CURSOR_LEFT"] = "Mausanker links"
+L["ANCHOR_CURSOR_RIGHT"] = "Mausanker rechts"
+L["Abbreviation"] = true
+L["Above Chat"] = "Über dem Chat"
+L["Above"] = "Oben"
+L["Accept Invites"] = "Einladungen akzeptieren"
+L["Action Paging"] = "Seitenwechsel der Aktionsleisten"
+L["ActionBars"] = "Aktionsleisten"
+L["Actions"] = "Aktionen"
+L["Add Item or Search Syntax"] = "Füge Gegenstand oder Suchoperator hinzu"
+L["Add Name"] = "Name hinzufügen"
+L["Add Regular Filter"] = "Füge regulären Filter hinzu"
+L["Add Special Filter"] = "Füge speziellem Filter hinzu"
+L["Add Spell ID or Name"] = "Zauber ID oder Name hinzufügen"
+L["Add SpellID"] = "ZauberID hinzufügen"
+L["Add a Name to the list."] = true
+L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."] = "Zauber zum Filter hinzufügen. Benutze Zauber ID wenn du nicht möchtest, dass Zauber hinzugefügt werden die alle den selben Namen haben."
+L["Add a spell to the filter."] = "Zauber zum Filter hinzufügen"
+L["Add an item or search syntax to the ignored list. Items matching the search syntax will be ignored."] = "Füge ein Gegenstand oder ein Suchoperator zu der Ignorierliste hinzu. Gegenstände die auf den Suchoperator zutreffen werden ignoriert."
+L["Additional Power Text"] = "Zusätzlicher Kraft Text"
+L["Additional spacing between each individual group."] = "Zusätzlicher Abstand zwischen jeder Gruppe."
+L["Additive Blend"] = "Additive Überblendung"
+L["Adjust the height of your right chat panel."] = "Passe die Höhe des rechten Chatfensters an."
+L["Adjust the position of the threat bar to either the left or right datatext panels."] = "Bestimme die Position der Bedrohungsleiste in den rechten oder linken Infotextleisten."
+L["Adjust the size of the minimap."] = "Stelle die Größe der Minimap ein."
+L["Adjust the width of the bag frame."] = "Passe die Breite des Taschenfensters an."
+L["Adjust the width of the bank frame."] = "Passe die Breite des Bankfensters an."
+L["Adjust the width of your right chat panel."] = "Passe die Breite des rechten Chatfensters an."
+L["Alert Frames"] = "Alarmfenster"
+L["Alerts"] = "Alarme"
+L["Allow LBF to handle the skinning of this element."] = "Erlaubt LBF das Gestalten dieser Elememte."
+L["Allowed Combat Repeat"] = "Erlaubte Kampf Wiederholungen"
+L["Alpha Fading"] = "Alpha verblassen"
+L["Alpha Key"] = true
+L["Alpha channel is taken from the color option."] = "Alphakanal wird von der Farboptionen übernommen."
+L["Alpha"] = "Alpha"
+L["Always Display"] = "Immer anzeigen"
+L["Always Hide"] = "Immer verstecken"
+L["Always Show Realm"] = "Server immer anzeigen"
+L["Always Show Target Health"] = "Zeige immer Ziel Gesundheit"
+L["Ammo Pouch"] = true
+L["An X offset (in pixels) to be used when anchoring new frames."] = "X-Versatz (in Pixeln) der verwendet werden soll um neue Fenster zu ankern"
+L["An Y offset (in pixels) to be used when anchoring new frames."] = "Y-Versatz (in Pixeln) der verwendet werden soll um neue Fenster zu ankern"
+L["Anchor Point"] = "Ankerpunkt"
+L["Announce Interrupts"] = "Unterbrechungen ankündigen"
+L["Announce when you interrupt a spell to the specified chat channel."] = "Melde über den angegebenen Chatkanal einen unterbrochenen Zauber."
+L["Applies the font and font size settings throughout the entire user interface. Note: Some font size settings will be skipped due to them having a smaller font size by default."] = "Wendet die Schrift und Schriftgröße überall im Interface an. Hinweis: Einige Schriftarten werden übersprungen, weil sie eine kleinere Schriftgröße als Standard haben."
+L["Applies the primary texture to all statusbars."] = "Wendet die Primäre Textur auf alle Statusbars an."
+L["Apply Font To All"] = "Schriftart auf alles anwenden."
+L["Apply Texture To All"] = "Textur auf alles anwenden"
+L["Apply this filter if a buff has remaining time greater than this. Set to zero to disable."] = "Diesen Filter anwenden, wenn die Dauer von einem Stärkungszauber größer als dieses ist. Setze auf 0 um zu deaktivieren."
+L["Apply this filter if a buff has remaining time less than this. Set to zero to disable."] = "Diesen Filter anwenden, wenn die Dauer von einem Stärkungszauber kleiner als dieses ist. Setze auf 0 um zu deaktivieren."
+L["Apply this filter if a debuff has remaining time greater than this. Set to zero to disable."] = "Diesen Filter anwenden, wenn die Dauer von einem Schwächungszauber größer als dieses ist. Setze auf 0 um zu deaktivieren."
+L["Apply this filter if a debuff has remaining time less than this. Set to zero to disable."] = "Diesen Filter anwenden, wenn die Dauer von einem Schwächungszauber kleiner als dieses ist. Setze auf 0 um zu deaktivieren."
+L["Are you sure you want to reset ActionBars settings?"] = "Bist du dir sicher dass du die Actionsleisten Einstellungen zurücksetzen möchtest?"
+L["Are you sure you want to reset Auras settings?"] = "Bist du dir sicher dass du die Auren Einstellungen zurücksetzen möchtest?"
+L["Are you sure you want to reset Bags settings?"] = "Bist du dir sicher dass du die Taschen Einstellungen zurücksetzen möchtest?"
+L["Are you sure you want to reset Chat settings?"] = "Bist du dir sicher dass du die Chat Einstellungen zurücksetzen möchtest?"
+L["Are you sure you want to reset Cooldown settings?"] = "Bist du dir sicher dass du die Abklingzeiten Einstellungen zurücksetzen möchtest?"
+L["Are you sure you want to reset DataBars settings?"] = "Bist du dir sicher dass du die Informationsleisten Einstellungen zurücksetzen möchtest?"
+L["Are you sure you want to reset DataTexts settings?"] = "Bist du dir sicher dass du die Infotexte Einstellungen zurücksetzen möchtest?"
+L["Are you sure you want to reset General settings?"] = "Bist du dir sicher dass du die Allgemeinen Einstellungen zurücksetzen möchtest?"
+L["Are you sure you want to reset NamePlates settings?"] = "Bist du dir sicher dass du die Namensplaketten Einstellungen zurücksetzen möchtest?"
+L["Are you sure you want to reset Tooltip settings?"] = "Bist du dir sicher dass du die Tooltip Einstellungen zurücksetzen möchtest?"
+L["Are you sure you want to reset UnitFrames settings?"] = "Bist du dir sicher dass du die Einheitenfenster Einstellungen zurücksetzen möchtest?"
+L["Arena Frame"] = true
+L["Arena Registrar"] = true
+L["Arena"] = true
+L["Ascending or Descending order."] = "Aufsteigende oder Absteigende Reihenfolge"
+L["Ascending"] = "Aufsteigend"
+L["Assist Target"] = "Assistent Ziel"
+L["Assist"] = "Assistent"
+L["At what point should the text be displayed. Set to -1 to disable."] = "An welchen Punkt sollte der text angezeigt werden. Auf -1 setzen um es zu deaktivieren."
+L["Attach Text To"] = "Text anfügen an"
+L["Attach To"] = "Anfügen an"
+L["Attempt to create URL links inside the chat."] = "Eine Möglichkeit um Internet-Links im Chat anzuzeigen."
+L["Attempt to lock the left and right chat frame positions. Disabling this option will allow you to move the main chat frame anywhere you wish."] = "Fixiere das rechte und linke Chatfenster. Deaktiviere diese Option um das Hauptchatfenster nach Belieben zu verschieben."
+L["Attempt to support eyefinity/nvidia surround."] = "Versucht Eyefinity/NVIDIA Surround zu unterstützen"
+L["Aura Bars"] = "Auren Leisten"
+L["Aura Filters"] = "Auren Filter"
+L["Auto Greed/DE"] = "Auto-Gier/DE"
+L["Auto Hide"] = "Auto Verstecken"
+L["Auto Repair"] = "Auto-Reparatur"
+L["Auto-Hide"] = "Automatisch verstecken"
+L["Automatic"] = "Automatisch"
+L["Automatically accept invites from guild/friends."] = "Automatisch Einladungen von Gildenmitgliedern/Freunden akzeptieren"
+L["Automatically hide the objetive frame during boss or arena fights."] = "Versteckt automatisch die Questverfolgung während eines Boss oder Arena Kampfes."
+L["Automatically repair using the following method when visiting a merchant."] = "Repariere automatisch deine Ausrüstungsgegenstände, wenn du eine der folgenden Methoden auswählst."
+L["Automatically select greed or disenchant (when available) on green quality items. This will only work if you are the max level."] = "Automatisch Gier oder Entzauberung auf Gegenstände von grüner Qualität wählen (sofern verfügbar). Das funktioniert nur, wenn du die maximale Stufe erreicht hast."
+L["Automatically vendor gray items when visiting a vendor."] = "Automatischer Verkauf von grauen Gegenständen bei einem Händlerbesuch."
+L["Available Tags"] = "Verfügbare Tags"
+L["BG Map"] = "Schlachtfeldkarte"
+L["BG Score"] = "Schlachtfeldpunkte"
+L["BINDING_HEADER_RAID_TARGET"] = "Zielmarkierungen"
+L["Backdrop Color"] = "Hintergrundfarbe"
+L["Backdrop Faded Color"] = "Transparente Hintergrundfarbe"
+L["Backdrop Spacing"] = "Hintergrund Abstand"
+L["Backdrop color of transparent frames"] = "Hintergrundfarbe von transparenten Fenstern"
+L["Backdrop"] = "Hintergrund"
+L["Background Glow"] = "Hintergrund Leuchten"
+L["Bad Color"] = "Schlechte Farbe"
+L["Bad Scale"] = "Schlechte Skalierung"
+L["Bad Transition Color"] = "Schlechte Übergangsfarbe"
+L["Bad"] = "Schlecht"
+L["Bag 1"] = "Tasche 1"
+L["Bag 2"] = "Tasche 2"
+L["Bag 3"] = "Tasche 3"
+L["Bag 4"] = "Tasche 4"
+L["Bag Sorting"] = "Taschen Sortierung"
+L["Bag Spacing"] = "Taschen Abstand"
+L["Bag"] = "Tasche"
+L["Bag-Bar"] = "Taschenleiste"
+L["Bags Only"] = "Nur Taschen"
+L["Bags/Bank"] = "Taschen/Bank"
+L["Bank 1"] = true --No need to translate
+L["Bank 2"] = true
+L["Bank 3"] = true
+L["Bank 4"] = true
+L["Bank 5"] = true
+L["Bank 6"] = true
+L["Bank 7"] = true
+L["Bank Only"] = "Nur Bank"
+L["Bar Direction"] = "Ausrichtung Leiste"
+L["Bars will transition smoothly."] = "Sanfter Übergang der Leisten."
+L["Battleground Texts"] = "Schlachtfeld-Infotexte"
+L["Begin a new row or column after this many auras."] = "Beginne nach so vielen Stärkungszaubern eine neue Reihe oder Spalte."
+L["Below Chat"] = "Unter dem Chat"
+L["Below"] = "Unten"
+L["Blacklist Modifier"] = "Schwarze Liste Modifikator"
+L["Blacklist"] = "Schwarze Liste"
+L["Blend Mode"] = "Überblendungs-Modus"
+L["Blend"] = "Überblenden"
+L["BlizzUI Improvements"] = "Blizzard Verbesserungen"
+L["Blizzard Style"] = "Blizzard Stil"
+L["Blizzard"] = true --No need to translate
+L["Block Combat Click"] = "Blockiere Klicks im Kampf"
+L["Block Combat Hover"] = "Blockiere Hovereffekt im Kampf"
+L["Block Mouseover Glow"] = "Blocke Mouse-Over Leuchten"
+L["Block Target Glow"] = "Blocke Ziel Leuchten"
+L["Blocks all click events while in combat."] = "Blockiere alle Klickevents im Kampf."
+L["Blocks datatext tooltip from showing in combat."] = "Blockiere Infotextetooltips im Kampf."
+L["Border Color"] = "Rahmenfarbe"
+L["Border Glow"] = "Rahmen Leuchten"
+L["Border"] = "Rand"
+L["Borders"] = "Umrandungen"
+L["Both"] = "Beide"
+L["Bottom Left"] = "Unten links"
+L["Bottom Panel"] = "Untere Leiste"
+L["Bottom Right"] = "Unten rechts"
+L["Bottom to Top"] = "Von unten nach oben"
+L["Bottom"] = "Unten"
+L["BottomLeftMiniPanel"] = "Minimap Untenlinks (Innen)"
+L["BottomMiniPanel"] = "Minimap Unten (Innen)"
+L["BottomRightMiniPanel"] = "Minimap Untenrechts (Innen)"
+L["Buff Indicator"] = "Buff Indikator"
+L["Button Size (Bag)"] = "Tasten Größe (Tasche)"
+L["Button Size (Bank)"] = "Tasten Größe (Bank)"
+L["Button Size"] = "Größe der Tasten"
+L["Button Spacing"] = "Abstand der Tasten"
+L["Buttons Per Row"] = "Tasten pro Zeile"
+L["Buttons"] = "Tasten"
+L["By Type"] = "Nach Typ"
+L["Calendar Frame"] = "Kalender Fenster"
+L["Cast Bar"] = "Zauberleiste"
+L["Cast Color"] = "Zauberfarbe"
+L["Cast No Interrupt Color"] = "Nicht unterbrechbare Zauberfarbe"
+L["Cast Time Format"] = "Zauber Zeitformat"
+L["Castbar"] = "Zauberleiste"
+L["Casting"] = "Zaubernd"
+L["Center"] = "Zentrum"
+L["Change settings for the display of the location text that is on the minimap."] = "Ändere die Einstellungen für die Anzeige des Umgebungstextes an der Minimap."
+L["Change the alpha level of the frame."] = "Ändere den Alphakanal des Fensters."
+L["Channel Alerts"] = true
+L["Change the width and controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Channel Time Format"] = "Kanalisierung Zeitformat"
+L["Character Frame"] = "Charakterfenster"
+L["Chat Bubble Names"] = "Sprechblasen Name"
+L["Chat Bubbles Style"] = "Sprechblasen Stil"
+L["Chat Bubbles"] = "Sprechblasen"
+L["Chat EditBox Position"] = "Position der Texteingabeleiste"
+L["Chat Output"] = "Chat Ausgabe"
+L["Check these to only have the filter active in certain difficulties. If none are checked, it is active in all difficulties."] = "Wenn du dieses auswählst, wird der Filter nur in einigen Schwierigkeitsgraden aktiviert. Wenn nicht aktiviert ist er in allen aktiv."
+L["CheckBox Skin"] = "Auswahlkästchen Skin"
+L["Choose Export Format"] = "Wähle Export Format"
+L["Choose UIPARENT to prevent it from hiding with the unitframe."] = "Wähle UIPARENT um zu verhindern dass es mit dem Einheitenfenster versteckt wird."
+L["Choose What To Export"] = "Wähle aus, was exportiert werden soll"
+L["Choose when you want the tooltip to show in combat. If a modifer is chosen, then you need to hold that down to show the tooltip."] = "Wähle wann du den Tooltip im Kampf sehen möchtest. Wenn ein Modifikator genutzt wird, musst du ihn gedrückt halten um den Tooltip anzuzeigen."
+L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."] = "Wählt aus wann der Tooltip angezeigt wird. Wenn ein Modifikator ausgewählt ist, dann musst du ihn gedrückt halten um den Tooltip anzuzeigen."
+L["Class Backdrop"] = "Klassen Hintergrund"
+L["Class Castbars"] = "Klassen Zauberleisten"
+L["Class Color Mentions"] = "Erwähnung in Klassenfarbe"
+L["Class Color Override"] = "Klassenfarben überschreiben"
+L["Class Health"] = "Klassen Gesundheit"
+L["Class Power"] = "Klassen Kraft"
+L["Class Resources"] = "Klassenressourcen"
+L["Class Totems"] = "Klassen Totems"
+L["Clear Filter"] = "Filter leeren"
+L["Clear Search On Close"] = "Leere Suche beim Schließen"
+L["Click Through"] = "Klicke hindurch"
+L["Clickable Height"] = "Klickbare Höhe"
+L["Clickable Size"] = "Klickbare Größe"
+L["Clickable Width / Width"] = "Klickbare Breite / Breite"
+L["Coding:"] = "Programmierung:"
+L["Color Keybind Text when Out of Range, instead of the button."] = "Färbt den Tastaturbelegungstext wen nicht in Reichweite anstatt der Taste."
+L["Color Keybind Text"] = "Färbe Tastaturbelegungstext"
+L["Color Override"] = "Farbüberschreibung"
+L["Color Turtle Buffs"] = "Färbe Turtle Stärkungszauber"
+L["Color all buffs that reduce the unit's incoming damage."] = "Färbe alle Stärkungszauber die den einkommenden Schaden der Einheit verringern."
+L["Color aurabar debuffs by type."] = "Färbe Schwächungszauber nach Typ."
+L["Color by Value"] = "Färbe nach Wert"
+L["Color castbars by the class of player units."] = "Färbe die Zauberleiste entsprechend ihrer Klasse."
+L["Color castbars by the reaction type of non-player units."] = "Färbe die Zauberleiste entsprechend der Reaktion der Einheit."
+L["Color health by amount remaining."] = "Färbe die Gesundheitsleiste entsprechend der aktuell verbleibenden Lebenspunkte"
+L["Color health by classcolor or reaction."] = "Gesundheitsfarbe nach Klassenfarbe oder Reaktion."
+L["Color health by threat status."] = "Gesundheitsfarbe nach Bedrohungsstatus"
+L["Color of the actionbutton when not usable."] = "Farbe der Aktionsleisten wenn nicht nutzbar."
+L["Color of the actionbutton when out of power (Mana, Rage)."] = "Die Farbe der Aktionstasten, wenn keine Kraft, wie z.B. Mana, Wut, mehr vorhanden ist."
+L["Color of the actionbutton when out of range."] = "Die Farbe der Aktionstasten, wenn das Ziel außer Reichweite ist."
+L["Color of the actionbutton when usable."] = "Farbe der Aktionsleisten wenn nutzbar."
+L["Color power by classcolor or reaction."] = "Färbe die Kraftleiste entsprechend ihrer Klasse."
+L["Color power by threat status."] = "Färbt die Kraftleiste nach Bedrohungsstatus."
+L["Color some texts use."] = "Allgemeine Farbe der meisten Texte"
+L["Color the health backdrop by class or reaction."] = "Färbe den Gesundheitshintergrund nach Klasse oder Reaktion."
+L["Color the unit healthbar if there is a debuff that can be dispelled by you."] = "Aktiviere die Hervorhebung von Einheitenfenstern, wenn ein von dir bannbarer Schwächungszauber vorhanden ist."
+L["Color when the text is about to expire"] = "Färbe den Text in dieser Farbe, wenn er in Kürze abläuft."
+L["Color when the text is in the days format."] = "Färbe den Text in dieser Farbe, wenn er Tagen angezeigt wird."
+L["Color when the text is in the hours format."] = "Färbe den Text in dieser Farbe, wenn er in Stunden angezeigt wird."
+L["Color when the text is in the minutes format."] = "Färbe den Text in dieser Farbe, wenn er sich im Minutenformat angezeigt wird."
+L["Color when the text is in the seconds format."] = "Färbe den Text in dieser Farbe, wenn er in Sekunden angezeigt wird."
+L["Colored Icon"] = "Buntes Symbol"
+L["Coloring (Specific)"] = "Färben (Spezifisch)"
+L["Coloring"] = "Färben"
+L["Colorize Selected Text"] = true
+L["Colors the border according to the Quality of the Item."] = "Färbt den Rand entsprechend der Qualität von einem Gegenstand."
+L["Combat Icon"] = "Kampfsymbol"
+L["Combat Override Key"] = "Im Kampf Überschreibungstaste"
+L["CombatText Font"] = "Schriftart vom Kampftext"
+L["Combo Point"] = "Kombopunkt"
+L["Comparison Font Size"] = "Vergleich Schriftgröße"
+L["Condensed"] = "Gekürzt"
+L["Configure Auras"] = "Konfiguriere Auren"
+L["Control enemy nameplates toggling on or off when in combat."] = "Legt fest ob die Namensplaketten im Kampf für Gegner ein- oder ausgeblendet werden."
+L["Control friendly nameplates toggling on or off when in combat."] = "Legt fest ob die Namensplaketten im Kampf für freundliche Einheiten ein- oder ausgeblendet werden."
+L["Controls how big of an area on the screen will accept clicks to target unit."] = "Legt die Größe des Bereichs auf dem Bildschirm fest, welche die klicks durch die feindlichen Einheiten erlaubt."
+L["Controls the amount of decimals used in values displayed on elements like NamePlates and UnitFrames."] = "Kontrolliert die Anzahl der Dezimalstellen in den Werten auf den Namensplaketten und Einheitenfenstern."
+L["Controls the speed at which smoothed bars will be updated."] = "Kontrolliert die Geschwindigkeit wie die Sanften Leistenübergange updaten."
+L["Controls how many seconds of inactivity has to pass before chat is faded."] = "Kontrolliert die Sekunden die vergehen müssen bevor der chat ausblendet."
+L["Cooldown Orientation"] = true
+L["Cooldown Text"] = "Abklingzeittext"
+L["Cooldowns"] = "Abklingzeiten"
+L["Copy From"] = "Kopieren von"
+L["Copy Settings From"] = "Kopiere Einstellungen von"
+L["Copy settings from another unit."] = "Kopiere Einstellungen von einer anderen Einheit."
+L["Core |cff1784d1E|r|cffe5e3e3lvUI|r options."] = "|cff1784d1E|r|cffe5e3e3lvUI|r Einstellungen"
+L["Count Font Size"] = "Anzahl Schriftgröße"
+L["Count xOffset"] = "Den Versatz auf der X-Achse zählen"
+L["Count yOffset"] = "Den Versatz auf der Y-Achse zählen"
+L["Create Custom Text"] = "Erstelle benutzerdefinierten Text"
+L["Create Filter"] = "Filter erstellen"
+L["Create a filter, once created a filter can be set inside the buffs/debuffs section of each unit."] = "Erstelle einen Filter. Ist dieser Filter einmal erstellt, kann er bei jeder Einheit im Bereich Stärkungszauber/Schwächungszauber ausgewählt werden."
+L["Credits"] = "Danksagung"
+L["Crop Icons"] = "Symbole zuschneiden"
+L["Currency Format"] = "Währungsformat"
+L["Current - Max | Percent"] = "Aktuell - Max | Prozent"
+L["Current - Max"] = "Aktuell - Maximal"
+L["Current - Percent (Remaining)"] = "Aktuell - Prozent (Verleibend)"
+L["Current - Percent"] = "Aktuell - Prozent"
+L["Current - Remaining"] = "Aktuell - Verbleibend"
+L["Current / Max"] = "Aktuell / Maximal"
+L["Current Level"] = "Aktuelles Level"
+L["Current"] = "Aktuell"
+L["Curse Effect"] = true
+L["Cursor Anchor Offset X"] = "Zeigeranker X-Versatz"
+L["Cursor Anchor Offset Y"] = "Zeigeranker Y-Versatz"
+L["Cursor Anchor Type"] = "Mausanker Typ"
+L["Cursor Anchor"] = "Zeigeranker"
+L["Custom Backdrop"] = "Benutzerdefinierte Hintergrund"
+L["Custom Color"] = "Benutzerdefinierte Farbe"
+L["Custom Dead Backdrop"] = "Benutzerdefinierte Hintergrundfarbe vom Tod"
+L["Custom Faction Colors"] = "Benutzerdefinierte Fraktionsfarben"
+L["Custom Texts"] = "Benutzerdefinierte Texte"
+L["Custom Texture"] = "Benutzerdefinierte Textur"
+L["Custom Timestamp Color"] = "Benutzerdefinierte Zeitstempel Farbe"
+L["Cutaway Bars"] = "Animierte Leisten"
+L["Darken Inactive"] = "Inaktives verdunkeln"
+L["DataBars"] = "Informationsleisten"
+L["DataTexts"] = "Infotexte"
+L["Datatext Panel (Left)"] = "Infotextleiste (Links)"
+L["Datatext Panel (Right)"] = "Infotextleiste (Rechts)"
+L["Date Format"] = "Datums-Format"
+L["Days"] = "Tage"
+L["Debuff Highlighting"] = "Hervorhebung von Schwächungszaubern"
+L["Debug Tools"] = "Debug Tools"
+L["Decimal Length"] = "Dezimalstellen"
+L["Decimal Threshold"] = "Dezimaler Schwellenwert"
+L["Decode Text"] = "Entschlüsselter Text"
+L["Default Color"] = "Standardfarbe"
+L["Default Font"] = "Allgemeine Schriftart"
+L["Default Settings"] = "Standard Einstellungen"
+L["Deficit"] = "Unterschied"
+L["Defines how the group is sorted."] = "Lege fest, wie die Gruppe sortiert wird."
+L["Defines the sort order of the selected sort method."] = "Legt die Sortierreihenfolge der ausgewählten Sortiermethode fest."
+L["Delete Filter"] = "Filter löschen"
+L["Delete a created filter, you cannot delete pre-existing filters, only custom ones."] = "Entferne einen erstellten Filter. Es können nur benutzerdefinierte Filter entfernt werden."
+L["Desaturate Cooldowns"] = "Auf Cooldown entsättigt"
+L["Desaturate Junk Items"] = "Verblasste Müll Symbole"
+L["Desaturated Icon"] = "Entsättigtes Symbol"
+L["Descending"] = "Absteigend"
+L["Detach From Frame"] = "Vom Fenster lösen"
+L["Detached Width"] = "Freistehendes Breite"
+L["Direction the bag sorting will use to allocate the items."] = "Die Richtung, in welche die Gegenstände in den Taschen sortiert werden."
+L["Direction the bar moves on gains/losses"] = "Richtung in die der Balken wächst/sinkt"
+L["Direction the health bar moves when gaining/losing health."] = "Richtung in die sich die Lebensleiste aufbaut, wenn man Leben gewinnt oder verliert."
+L["Disable Bag Sort"] = "Deaktiviere Taschensortierung"
+L["Disable Bank Sort"] = "Deaktiviere Banksortierung"
+L["Disable Debuff Highlight"] = "Deaktiviere Schwächungszauber-Hervorhebung"
+L["Disabled Blizzard Frames"] = "Deaktivierte Blizzard Fenster"
+L["Disabled Blizzard"] = "Blizzard deaktivieren"
+L["Disables the focus and target of focus unitframes."] = "Deaktiviert das Fokus und Fokus-Ziel Einheitenfenster."
+L["Disables the player and pet unitframes."] = "Deaktiviert das Spieler und Begleiter Einheitenfenster."
+L["Disables the target and target of target unitframes."] = "Deaktiviert das Ziel und Ziel des Ziels Einheitenfenster."
+L["Disconnected"] = "Nicht Verbunden"
+L["Disease Effect"] = true
+L["Display Frames"] = "Zeige Fenster"
+L["Display Item Level"] = "Itemlevel anzeigen"
+L["Display Player"] = "Zeige Spieler"
+L["Display Target"] = "Zeige Ziel"
+L["Display Text"] = "Zeige Text"
+L["Display a healer icon over known healers inside battlegrounds or arenas."] = "Zeige auf Schlachtfeldern oder in Arenen ein Heilersymbol über Heilern an."
+L["Display a panel across the bottom of the screen. This is for cosmetic only."] = "Zeige eine Leiste am unterem Bildschirmrand. Das ist rein kosmetisch."
+L["Display a panel across the top of the screen. This is for cosmetic only."] = "Zeige eine Leiste am oberen Bildschirmrand. Das ist rein kosmetisch."
+L["Display a spark texture at the end of the castbar statusbar to help show the differance between castbar and backdrop."] = "Zeigt eine funkelnde Textur am Ende des Zauberbalken um den Unterschied zwischen Zauberbalken und Hintergrund zu verdeutlichen."
+L["Display an exclamation mark on items that starts a quest."] = true
+L["Display battleground messages in the middle of the screen."] = "Zeigt Schlachtfeld Nachrichten in der Mitte des Bildschirms."
+L["Display bind names on action buttons."] = "Zeige Tastaturbelegungen auf der Aktionsleiste an."
+L["Display cooldown text on anything with the cooldown spiral."] = "Zeige die Abklingzeit auf allen Tasten mit Hilfe einer animierten Spirale."
+L["Display data panels below the chat, used for datatexts."] = "Zeige die Infoleisten unter dem Chat, benutzt für Infotexte."
+L["Display emotion icons in chat."] = "Zeige Emoticons im Chat."
+L["Display guild ranks if a unit is guilded."] = "Zeige Gildenränge von Spielern die in einer Gilde sind."
+L["Display how many of a certain item you have in your possession."] = "Zeige wie viele sich von dem ausgewählten Gegenstand in deinem Besitz befinden."
+L["Display macro names on action buttons."] = "Zeige Makronamen auf der Aktionsleiste an."
+L["Display minimap panels below the minimap, used for datatexts."] = "Zeige Minimap Leisten unter der Minimap, benutzt für Infotexte."
+L["Display player titles."] = "Zeige Spielertitel."
+L["Display reminder bar on the minimap."] = "Buff-Reminder an der Minimap anzeigen"
+L["Display the castbar icon inside the castbar."] = "Zeigt das Zauberleisten Symbol in der Zauberleiste."
+L["Display the castbar inside the information panel, the icon will be displayed outside the main unitframe."] = "Zeige die Zauberleiste im Information Panel, das Symbol wird ausserhalb des Einheitenfenster angezeigt."
+L["Display the hyperlink tooltip while hovering over a hyperlink."] = "Zeigt den Hyperlink Tooltip beim Überfahren eines Hyperlinks."
+L["Display the junk icon on all grey items that can be vendored."] = "Zeigt das Müll Symbol auf allen grauen Gegenständen an die verkauft werden können."
+L["Display the name of the unit on the chat bubble."] = true
+L["Display the npc ID when mousing over a npc tooltip."] = "Zeigt die NPC ID an, wenn du mit der Maus über einen NPC ziehst."
+L["Display the spell or item ID when mousing over a spell or item tooltip."] = "Zeige die ID des Zaubers oder des Gegenstands an, wenn du mit der Maus über einen Zauber oder Fegenstand ziehst."
+L["Display the target of your current cast. Useful for mouseover casts."] = "Zeige das Ziel deines derzeitigen Zaubers, für Mouseover Zauber nützlich"
+L["Display tick marks on the castbar for channelled spells. This will adjust automatically for spells like Drain Soul and add additional ticks based on haste."] = "Anzeige der Zauberbalkenticks für kanalisierte Zauber. Dies ändert sich automatisch für Zauber wie Seelendieb, wenn zusätzliche Ticks durch einen hohen Tempowert entstehen."
+L["Displayed server time."] = true
+L["Displays a detailed report of every item sold when enabled."] = "Zeigt einen detaillierten Report von jedem verkauften Gegenstand wenn aktiviert."
+L["Displays item level on equippable items."] = "Zeigt das Itemlevel für ausrüstbare Gegenstände an."
+L["Display Types"] = true
+L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."] = "Keine Auren anzeigen die länger als diese Dauer (in Sekunden) sind"
+L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."] = "Zeige keine Auren die kürzer als die Dauer (in Sekunden) sind. Auf 0 stellen um zu deaktivieren."
+L["Donations:"] = "Spenden:"
+L["Down"] = "Hinunter"
+L["Dropdown CheckBox Skin"] = true
+L["Dungeon & Raid Filter"] = "Instanz & Schlachtzug Filter"
+L["Duration Enable"] = "Dauer aktiviert"
+L["Duration Font Size"] = "Dauer Schriftgröße"
+L["Duration Reverse"] = "Dauer umkehren"
+L["Duration Text"] = "Dauer Text"
+L["Duration"] = "Dauer"
+L["Editbox History Size"] = true
+L["ELVUI_CREDITS"] = "Ich möchte mich hier bei folgenden Personen bedanken, die durch ihre tatkräftige Unterstützung beim Testen und Coden, sowie durch Spenden, sehr geholfen haben. Bitte beachten: Für Spenden poste ich nur die Namen, die mich im Forum via PN angeschrieben haben. Sollte dein Name fehlen und du möchtest deinen Namen hinzugefügt haben, schreib mir bitte eine PN im Forum."
+L["ENEMY_NPC"] = "Gegnerischer NPC"
+L["ENEMY_PLAYER"] = "Gegnerischer Spieler"
+L["Elite Icon"] = "Elite Symbol"
+L["Emotion Icons"] = "Emoticons"
+L["Enable Custom Color"] = "Benutzerdefinierte Farbe aktivieren"
+L["Enable the use of separate size options for the right chat panel."] = "Benutze getrennte Größenoptionen für das rechte Chatfenster."
+L["Enable/Disable the Bag-Bar."] = "Aktiviere/Deaktiviere die Taschenleiste."
+L["Enable/Disable the all-in-one bag."] = "Einschalten/Ausschalten der zusammengefassten Tasche."
+L["Enable/Disable the loot frame."] = "Aktiviere/Deaktiviere das Beutefenster."
+L["Enable/Disable the loot roll frame."] = "Aktiviere/Deaktiviere das Beutewürfelfenster."
+L["Enable/Disable the minimap. |cffFF0000Warning: This will prevent you from seeing the consolidated buffs bar, and prevent you from seeing the minimap datatexts.|r"] = true
+L["Enable/Disable the scaling of targetted nameplates."] = true
+L["Enables the ElvUI Raid Control panel."] = "Aktiviert das ElvUI Raid Control Panel."
+L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."] = "Aktivieren dieses Punktes erlaubt Raidweites sortieren, allerdings wirst du nicht zwischen Gruppen unterscheiden können"
+L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."] = "Aktivieren dieses Punktes kehrt die Gruppierungsrichtung um wenn der Raid nicht voll ist, die Startrichtung wird ebenfalls umgekehrt"
+L["Enabling this will check your health amount."] = "Wenn aktiviert wird dein Lebenswert überprüft."
+L["Enabling this will check your power amount."] = "Wenn aktiviert wird dein Kraftwert überprüft."
+L["Enchanting"] = "Verzauberkunst"
+L["Enemy Aura Type"] = "Feindlicher Aurentyp"
+L["Enemy Combat Toggle"] = "Im Kampf für Gegner umschalten"
+L["Enemy NPC Frames"] = true
+L["Enemy Player Frames"] = true
+L["Enemy"] = "Gegner"
+L["Engineering"] = "Ingenieurskunst"
+L["Enhanced PVP Messages"] = "Erweiterte PvP Nachrichten"
+L["Equipped Item Color"] = true
+L["Equipped Item"] = true
+L["Error decoding data. Import string may be corrupted!"] = "Fehler beim entschlüsseln der Daten. Die importierende Zeichenfolge scheint beschädigt zu sein!"
+L["Error exporting profile!"] = "Fehler beim Exportieren des Profils!"
+L["Exclude Name"] = "Ausgeschlossener Name"
+L["Excluded Names"] = "Ausgeschlossene Namen"
+L["Excluded names will not be class colored."] = "Ausgeschlossene Namen werden nicht in Klassenfarbe erscheinen."
+L["Expiring"] = "Auslaufend"
+L["Export Profile"] = "Exportiere Profil"
+L["Exported"] = "Exportiert"
+L["FRIENDLY_NPC"] = "Freundlicher NPC"
+L["FRIENDLY_PLAYER"] = "Freundlicher Spieler"
+L["Fade Chat Toggles"] = true
+L["Fade Out Delay"] = "Ausblendungsverzögerung"
+L["Fade Out"] = "Ausblenden"
+L["Fade Tabs No Backdrop"] = "Verblasst Tabs ohne Hintergrund"
+L["Fade Threshold"] = "Zeit bis zum verblassen"
+L["Fade Undocked Tabs"] = "Verblasst nicht angedockte Tabs"
+L["Fade the chat text when there is no activity."] = "Lässt den Chat Text verblassen, wenn keine Aktivität besteht."
+L["Fader"] = "Verblassen"
+L["Fades the buttons that toggle chat windows when that window has been toggled off."] = true
+L["Fades the text on chat tabs that are docked in a panel where the backdrop is disabled."] = "Verblasst den Text für die Chat Tabs, die nicht angedockt sind und deren Hintergrund deaktiviert ist."
+L["Fades the text on chat tabs that are not docked at the left or right chat panel."] = "Verblasst den Text für die Chat Tabs, die nicht am linken oder rechten Chat angedockt sind."
+L["Fill"] = "Füllen"
+L["Filled"] = "Gefüllt"
+L["Filter Priority"] = "Filter Priorität"
+L["Filter Search"] = "Filter Suche"
+L["Filter Type"] = "Filter Typ"
+L["Filter already exists!"] = "Filter existiert bereits!"
+L["Filters Page"] = "Filter Seite"
+L["Filters are not allowed to have commas in their name. Stripping commas from filter name."] = "Filtern ist es nicht erlaubt Kommas im Namen zu haben. Entferne Kommas vom Filter Namen."
+L["Flash"] = "Blinken"
+L["Fluid Position Buffs on Debuffs"] = "Flüssige Position Stärkungszauber auf Schwächungszauber"
+L["Fluid Position Debuffs on Buffs"] = "Flüssige Position Schwächungszauber auf Stärkungszauber"
+L["Flyout Direction"] = "Ausklapprichtung"
+L["Flyout Spacing"] = true
+L["Focus"] = "Fokus"
+L["FocusTarget"] = "Fokus Ziel"
+L["Font Outline"] = "Kontur der Schriftart"
+L["Font"] = "Schriftart"
+L["Fonts"] = "Schrift"
+L["Force Off"] = "Gezwungen aus"
+L["Force On"] = "Gezwungen an"
+L["Force Reaction Color"] = "Erzwinge Reaktionsfarbe"
+L["Force the frames to show, they will act as if they are the player frame."] = "Zwinge die Fenster sichtbar zu werden. Diese Fenster werden sich wie das Spielerfenster verhalten."
+L["Forces Debuff Highlight to be disabled for these frames"] = "Erzwinge die deaktivierung der Schwächungszauber-Hervorhebung für diese Fenster"
+L["Forces Mouseover Glow to be disabled for these frames"] = "Erzwingt Mouseover Leuchten deaktivierung auf diesen Fenstern"
+L["Forces Target Glow to be disabled for these frames"] = "Erzwingt Ziel Leuchten deaktivierung auf diesen Fenstern"
+L["Forces reaction color instead of class color on units controlled by players."] = "Erzwinge Reaktionsfarbe anstatt Klassenfarbe auf übernommene Einheiten."
+L["Format"] = "Formatierung"
+L["Frame Glow"] = "Fenster Leuchten"
+L["Frame Level"] = "Fenster Ebene"
+L["Frame Orientation"] = "Fenster Ausrichtung"
+L["Frame Strata"] = "Fenster Schicht"
+L["Frequent Updates"] = "Häufigkeit der Aktualisierung"
+L["Friendly Aura Type"] = "Freundlicher Aurentyp"
+L["Friendly Combat Toggle"] = "Im Kampf für freundliche umschalten"
+L["Friendly NPC Frames"] = true
+L["Friendly Player Frames"] = true
+L["Friendly"] = "Freundlich"
+L["Full Overlay"] = "Volles Überblenden"
+L["Full"] = "Voll"
+L["GM Chat"] = true --No need to translate
+L["GPS Arrow"] = "GPS Pfeil"
+L["Gems"] = "Edelsteine"
+L["General Options"] = "Allgemeine Optionen"
+L["Global (Account Settings)"] = "Globale (Account Einstellungen)"
+L["Global Fade Transparency"] = "Globales Transparenz verblassen"
+L["Global"] = true --No need to translate
+L["Glow"] = "Glanz"
+L["Gold Format"] = "Gold-Format"
+L["Good Color"] = "Gute Farbe"
+L["Good Scale"] = "Gute Skalierung"
+L["Good Transition Color"] = "Gute Übergangsfarbe"
+L["Good"] = "Gut"
+L["Gossip Frame"] = "Begrüßungsfenster"
+L["Group By"] = "Gruppiert durch"
+L["Group Spacing"] = "Gruppen Abstand"
+L["Grouping & Sorting"] = "Gruppierung und Sortierung"
+L["Groups Per Row/Column"] = "Gruppen per Reihe/Spalte"
+L["Growth Direction"] = "Wachstumsrichtung"
+L["Growth X-Direction"] = "Wachstum X-Richtung"
+L["Growth Y-Direction"] = "Wachstum Y-Richtung"
+L["Growth direction from the first unitframe."] = "Wachstumsrichtung von dem ersten Einheitenfenster."
+L["Guide:"] = true
+L["Guild Ranks"] = "Gildenränge"
+L["Guild Registrar"] = "Gildenregister"
+L["HH:MM Threshold"] = "HH:MM Schwellenwert"
+L["HH:MM"] = "HH:MM"
+L["Header Font Size"] = "Kopfzeile Schriftgröße"
+L["Heal Prediction"] = "Eingehende Heilung"
+L["Healer Icon"] = "Heilersymbol"
+L["Health Backdrop Multiplier"] = "Gesundheitshintergrund Multiplikator"
+L["Health Backdrop"] = "Gesundheitshintergrund"
+L["Health Bar"] = "Lebensleiste"
+L["Health Border"] = "Gesundheitsumrandung"
+L["Health By Value"] = "Gesundheit nach dem Wert"
+L["Health Color"] = "Gesundheitsfarbe"
+L["Health Length"] = "Gesundheitslänge"
+L["Health Threshold"] = "Gesundheit Schwellwert"
+L["Health"] = "Leben"
+L["Height Multiplier"] = "Höhenmultiplikator"
+L["Height of the objective tracker. Increase size to be able to see more objectives."] = "Höhe des Questfensters. Größe verändern um mehr Ziele zu sehen."
+L["Height"] = "Höhe"
+L["Help Frame"] = "Hilfefenster"
+L["Herbalism"] = "Kräuterkunde"
+L["Here you can add items or search terms that you want to be excluded from sorting. To remove an item just click on its name in the list."] = "Hier kannst du Gegenstände oder Suchbedingungen vom Suchen ausschließen. Um ein Gegenstand zu entfernen, klicke einfach auf den Namen in der Liste."
+L["Hide At Max Level"] = "Auf max. Level vestecken"
+L["Hide Both"] = "Verstecke Beide"
+L["Hide Error Text"] = "Fehlertext verstecken"
+L["Hide Frame"] = "Verstecke Fenster"
+L["Hide In Combat"] = "Im Kampf ausblenden"
+L["Hide In Vehicle"] = "Im Fahrzeug verstecken"
+L["Hide Spell Name"] = "Verstecke Zaubername"
+L["Hide Time"] = "Verstecke Zeit"
+L["Hide specific sections in the datatext tooltip."] = "Verstecke spezifische Abschnitte im Infotext Tooltip."
+L["Hide tooltip while in combat."] = "Verstecke den Tooltip während des Kampfes."
+L["Hides the red error text at the top of the screen while in combat."] = "Den roten Fehlertext im oberen Teil des Bildschirms im Kampf verstecken"
+L["History Size"] = true
+L["History"] = true
+L["Horizontal Spacing"] = "Horizontaler Abstand"
+L["Horizontal"] = "Horizontal"
+L["Hours"] = "Stunden"
+L["Hover Highlight"] = "Mouseover Highlight"
+L["Hover"] = "Mouseover"
+L["How long the cutaway health will take to fade out."] = "Wie lange das animierte Leben braucht um auszublenden."
+L["How long the cutaway power will take to fade out."] = "Wie lange die animierte Kraft braucht um auszublenden."
+L["How many seconds the castbar should stay visible after the cast failed or was interrupted."] = "Wieviele Sekunden die Zauberleiste sichtbar bleibt, nachdem ein Zauber abgebrochen oder unterbrochen wurde."
+L["How much time before the cutaway health starts to fade."] = "Wieviel Zeit es benötigt bevor das animierte Leben ausblendet."
+L["How much time before the cutaway power starts to fade."] = "Wieviel Zeit es benötigt bevor die anmierte Kraft ausblendet."
+L["Hyperlink Hover"] = "Hyperlink Hover"
+L["Icon Frame"] = true
+L["Icon Inside Castbar"] = "Symbol innerhalb Zauberleiste"
+L["Icon Only"] = "Nur Symbole"
+L["Icon Position"] = "Symbol Position"
+L["Icon Size"] = "Symbol Größe"
+L["Icon"] = "Symbol"
+L["Icon: BOTTOM"] = "Symbol: UNTEN"
+L["Icon: BOTTOMLEFT"] = "Symbol: UNTENLINKS"
+L["Icon: BOTTOMRIGHT"] = "Symbol: UNTENRECHTS"
+L["Icon: LEFT"] = "Symbol: LINKS"
+L["Icon: RIGHT"] = "Symbol: RECHTS"
+L["Icon: TOP"] = "Symbol: OBEN"
+L["Icon: TOPLEFT"] = "Symbol: OBENLINKS"
+L["Icon: TOPRIGHT"] = "Symbol: OBENRECHTS"
+L["Icons and Text (Short)"] = "Symbole und Text (Kurz)"
+L["Icons and Text"] = "Symbole und Text"
+L["If enabled then it checks if auras are missing instead of being present on the unit."] = "Wenn aktiviert, wird überprüft ob Auren fehlen anstatt vorhanden zu sein auf der Einheit."
+L["If enabled then it will require all auras to activate the filter. Otherwise it will only require any one of the auras to activate it."] = "Wenn aktiviert, benötigt es alle Auren um den Filter zu aktivieren. Andererseits benötigt es nur eine von den Auren um den Filter zu aktivieren."
+L["If enabled then it will require all cooldowns to activate the filter. Otherwise it will only require any one of the cooldowns to activate it."] = "Wenn aktiviert, benötigt es alle Cooldowns um den Filter zu aktivieren. Ansonsten benötigt es einen Cooldown um zu aktiveren."
+L["If enabled then the filter will activate if the unit is casting anything."] = true
+L["If enabled then the filter will activate if the unit is channeling anything."] = true
+L["If enabled then the filter will activate if the unit is not casting anything."] = true
+L["If enabled then the filter will activate if the unit is not channeling anything."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or higher than this value."] = "Wenn eingeschaltet, wird der Filter nur aktiviert wenn das Level der Einheit gleich oder höher diesem Level ist."
+L["If enabled then the filter will only activate if the level of the unit is equal to or lower than this value."] = "Wenn eingeschaltet, wird der Filter nur aktiviert wenn das Level der Einheit gleich oder niedriger diesem Level ist."
+L["If enabled then the filter will only activate if the level of the unit matches this value."] = "Wenn aktiviert, wird der Filter nur aktiviert wenn das Level der Einheit diesem Wert entspricht."
+L["If enabled then the filter will only activate if the level of the unit matches your own."] = "Wenn eingeschaltet, wird der Filter nur aktiviert wenn das Level er Einheit deinem Level entspricht."
+L["If enabled then the filter will only activate if the unit is casting interruptible spells."] = "Wenn eingeschaltet, wird der Filter nur aktiviert wenn die Einheit einen unterbrechbaren Zauber wirkt."
+L["If enabled then the filter will only activate if the unit is casting not interruptible spells."] = "Wenn eingeschaltet, wird der Filter nur aktiviert wenn die Einheit einen nicht unterbrechbaren Zauber wirkt."
+L["If enabled then the filter will only activate if the unit is not casting or channeling one of the selected spells."] = "Wenn eingeschaltet, wird der Filter nur aktiviert wenn die Einheit nicht am Zaubern oder Kanalisieren vom ausgwähltem Zauber ist."
+L["If enabled then the filter will only activate when you are in combat."] = "Wenn eingeschaltet, wird der Filter nur aktiviert, wenn du im Kampf bist."
+L["If enabled then the filter will only activate when you are not targeting the unit."] = "Wenn eingeschaltet, wird der Filter nur aktiviert, wenn du die Einheit nicht im Ziel hast."
+L["If enabled then the filter will only activate when you are out of combat."] = "Wenn eingeschaltet, wird der Filter nur aktiviert, wenn du nicht im Kampf bist."
+L["If enabled then the filter will only activate when you are targeting the unit."] = "Wenn eingeschaltet, wird der Filter nur aktiviert, wenn du die Einheit im Ziel hast."
+L["If enabled then the filter will only activate when you have a target."] = true
+L["If not set to 0 then override the size of the aura icon to this."] = "Wenn dieser Wert nicht auf 0 gesetzt wird, dann überschreibt dieser die größe des Aurensymbols."
+L["If the aura is listed with a number then you need to use that to remove it from the list."] = "Wenn die Aura mit einer Nummer aufgeführt ist, dann musst du sie benutzten um sie aus der Liste zu entfernen."
+L["If this list is empty, and if 'Interruptible' is checked, then the filter will activate on any type of cast that can be interrupted."] = "Wenn die Liste leer ist, und 'Unterbrechbar' ist ausgewählt, wird der Filter aktiviert bei jedem Zauber der unterbrechbar ist."
+L["If this threshold is used then the health of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = "Wenn dieser Schwellenwert genutzt wird, muss die Gesundheit höher sein als dieser Wert um den Filter zu aktivieren. Setze auf 0 um zu deaktiveren."
+L["If this threshold is used then the health of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = "Wenn dieser Schwellenwert genutzt wird, muss die Gesundheit niedriger sein als dieser Wert um den Filter zu aktivieren. Setze auf 0 um zu deaktiveren."
+L["If this threshold is used then the power of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = "Wenn dieser Schwellenwert genutzt wird, muss die Kraft höher sein als dieser Wert um den Filter zu aktivieren. Setze auf 0 um zu deaktiveren."
+L["If this threshold is used then the power of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = "Wenn dieser Schwellenwert genutzt wird, muss die Kraft niedriger sein als dieser Wert um den Filter zu aktivieren. Setzte auf 0 um zu deaktiveren."
+L["If you have a lot of 3D Portraits active then it will likely have a big impact on your FPS. Disable some portraits if you experience FPS issues."] = "Wenn du viele 3D Portraits aktiviert hast, wird es voraussichtlich enorm auf deine FPS auswirken. Deaktiviere bitte einige 3D Portraits sollte das der Fall sein."
+L["If you have any plugins supporting this feature installed you can find them in the selection dropdown to the right."] = "Wenn du ein Plugin installiert hast, was diese Einstellungen unterstützt, findest du sie im Dropdown rechts."
+L["If you unlock actionbars then trying to move a spell might instantly cast it if you cast spells on key press instead of key release."] = "Wenn du die Aktionsleisten entsperrst und versuchst einen Zauber zu verschieben, wird voraussichtlich der Zauber ausgelöst beim drücken anstatt beim loslassen der Taste."
+L["Ignore UI Scale Popup"] = "Ignoriere UI Skalierungs-Popup"
+L["Ignore mouse events."] = "Ignoriere Maus Events."
+L["Ignored Items and Search Syntax (Global)"] = "Ignorierte Gegenstände oder Suchoperatoren (Global)"
+L["Ignored Items and Search Syntax (Profile)"] = "Ignorierte Gegenstände oder Suchoperatoren (Profil)"
+L["Import Profile"] = "Importiere Profil"
+L["Importing"] = "Importiere"
+L["Inactivity Timer"] = "Inaktivitäts-Timer"
+L["Index"] = "Index"
+L["Indicate whether buffs you cast yourself should be separated before or after."] = "Wenn du einen Stärkungszauber auf dich selber wirkst, zeige diesen zuerst in der Leiste."
+L["InfoPanel Border"] = "InfoPanel Rand"
+L["Information Panel"] = true --No need to translate. Probably
+L["Inherit Global Fade"] = "Globales verblassen vererben"
+L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."] = "Vererbt das globale Verblassen, mouseover, anvisieren, Focus setzen, Gesundheit verlieren, Kampf betreten wird die Transparenz entfernen. Andernfalls wird das Transparenzlevel, in den allgemeinen Einstellungen der Aktionsleisten, globales verblassen Alpha verwendet."
+L["Inset"] = "Einsatz"
+L["Inside Information Panel"] = "Im Information Panel"
+L["Install"] = "Installation"
+L["Instance Difficulty"] = "Instanz Schwierigkeitsgrad"
+L["Instance Type"] = "Instanz Typ"
+L["Interruptable"] = "Unterbrechbar"
+L["Interruptible"] = "Unterbrechbar"
+L["Invert Colors"] = "Farben invertieren"
+L["Invert Grouping Order"] = "Gruppierungsreihenfolge umkehren"
+L["Invert foreground and background colors."] = "Invertiert Vordergrund- und Hintergrundfarbe."
+L["Is Casting Anything"] = "Zaubert irgendetwas"
+L["Is Channeling Anything"] = "Kanalisiert irgendetwas"
+L["Is Targeted"] = "Ist anvisiert"
+L["Item Count Font"] = "Gegenstandszähler Schriftart"
+L["Item Count"] = "Gegenstandsanzahl"
+L["Item Level Threshold"] = "Itemlevel Schwellenwert"
+L["Item Level"] = "Itemlevel"
+L["JustifyH"] = "RechtfertigenH"
+L["Key Down"] = "Aktion bei Tastendruck"
+L["Keybind Mode"] = "Tastaturbelegung"
+L["Keybind Text Position"] = "Tastaturbelegungstext Position"
+L["Keybind Text X-Offset"] = "Tastaturbelegungstext X-Versatz"
+L["Keybind Text Y-Offset"] = "Tastaturbelegungstext Y-Versatz"
+L["Keybind Text"] = "Tastaturbelegungstext"
+L["Keyword Alert"] = "Stichwort Alarm"
+L["Keywords"] = "Stichwort"
+L["LBF Support"] = true
+L["LEVEL_BOSS"] = "Setze das Level auf -1 für Boss Einheiten oder auf 0 um zu deaktivieren"
+L["LFD Frame"] = true
+L["LFG Queue"] = "LFG Warteschlange"
+L["LFR Frame"] = true
+L["Latency"] = "Latenz"
+L["Leatherworking"] = "Lederverarbeitung"
+L["Left Only"] = "Nur Links"
+L["Left to Right"] = "Links nach Rechts"
+L["Left"] = "Links"
+L["Limit the number of rows or columns."] = "Beschränkung für die Anzahl an Leisten oder Spalten."
+L["List of words to color in chat if found in a message. If you wish to add multiple words you must seperate the word with a comma. To search for your current name you can use %MYNAME%.\n\nExample:\n%MYNAME%, ElvUI, RBGs, Tank"] = "Liste der Wörter die farblich im Chat erscheinen, wenn sie in einer Nachricht gefunden werden. Wenn du möchtest, kannst du mehrere Wörter hinzufügen. Diese müssen durch ein Komma getrennt werden. Um deinen momentanen Namen zu suchen, benutze %MYNAME%.\n\nBeispiel:\n%MYNAME%, ElvUI, RBGs, Tank"
+L["Location Text"] = "Umgebungstext"
+L["Lock Positions"] = "Positionen fixieren"
+L["Log Taints"] = "Log Fehler"
+L["Log the main chat frames history. So when you reloadui or log in and out you see the history from your last session."] = "Sichert den Chatverlauf der Hauptchatfenster. Wenn du dein UI neulädst oder einloggst, siehst du den Chatverlauf der letzten Sitzung."
+L["Login Message"] = "Login Nachricht"
+L["Loot Frames"] = "Beutefenster"
+L["Loot Roll"] = "Würfelfenster"
+L["Losing Threat"] = "Bedroungsverlust"
+L["Low Health Threshold"] = "Wenig Leben Schwellenwert"
+L["Low Threat"] = "Geringe Bedrohung"
+L["Low Threshold"] = "Niedrige CD-Schwelle"
+L["Lower numbers mean a higher priority. Filters are processed in order from 1 to 100."] = "Niedrigere Nummern bedeuten eine höhere Priorität. Filter werden von 1 bis 100 verarbeitet."
+L["MM:SS Threshold"] = "MM:SS Schwellenwert"
+L["MM:SS"] = "MM:SS"
+L["Macro Text"] = "Makrotext"
+L["Magic Effect"] = true
+L["Main Tanks / Main Assist"] = "Haupt Tank / Haupt Assistent"
+L["Main backdrop color of the UI."] = "Allgemeine Hintergrundfarbe der Benutzeroberfläche."
+L["Main border color of the UI."] = "Standard-Rahmenfarbe der Benutzeroberfläche"
+L["Main statusbar texture."] = "Haupt-Statusleisten Textur"
+L["Make textures transparent."] = "Mache Texturen transparent."
+L["Make the unitframe glow yellow when it is below this percent of health, it will glow red when the health value is half of this value."] = "Färbe das Einheitenfensterleuchten gelb, wenn es unter diesen Prozentwert des Lebens sinkt. Es wird Rot angezeigt, wenn es die Hälfte des Wertes erreicht."
+L["Make the world map smaller."] = "Macht die Weltkarte kleiner."
+L["Map Opacity When Moving"] = "Deckkraft der Karte während der Bewegung"
+L["Maps"] = "Karten"
+L["Match Frame Width"] = "Passende Fensterbreite"
+L["Match Player Level"] = "Entspreche Spieler Level"
+L["Max Alpha"] = true --No need to translate
+L["Max Bars"] = "Leisten Anzahl"
+L["Max Lines"] = true
+L["Max Overflow"] = "Maximaler Overflow"
+L["Max Wraps"] = "Maximale Leisten"
+L["Max amount of overflow allowed to extend past the end of the health bar."] = "Maximale Menge des erlaubten Overflows um das Ende der Gesundheitsleiste zu erweitern."
+L["Maximum Duration"] = "Maximale Dauer"
+L["Maximum Level"] = "Maximale Level"
+L["Maximum Time Left"] = "Maximale Zeit verbleibend"
+L["Media"] = "Medien"
+L["Method to sort by."] = "Methode nach dem sortiert werden soll."
+L["Middle Click - Set Focus"] = "Mittelklick - Setze Fokus"
+L["Middle clicking the unit frame will cause your focus to match the unit."] = "Mittelklicken des Einheitenfensters passt deinen Fokus an die Einheit an."
+L["Middle"] = "Mitte"
+L["Min Alpha"] = true --No need to translate
+L["Minimap Mouseover"] = "Minimap Mouseover"
+L["Minimap Panels"] = "Minimap Leisten"
+L["Minimum Duration"] = "Minimale Dauer"
+L["Minimum Level"] = "Minimale Level"
+L["Minimum Time Left"] = "Minimale Zeit verbleibend"
+L["Mining"] = "Bergbau"
+L["Minutes"] = "Minuten"
+L["Mirror Timers"] = "Spiegel Zeitgeber"
+L["Misc Frames"] = "Verschiedene Fenster"
+L["Missing"] = "Fehlend"
+L["Modulating Blend"] = "Modulierende Überblendung"
+L["Module Control"] = "Modulkontrolle"
+L["Module Copy"] = "Module kopieren"
+L["Module Reset"] = "Module zurücksetzen"
+L["Money Format"] = "Geldformat"
+L["Mouse Over"] = "Mouseover"
+L["Mouseover Glow"] = "Mouseover Leuchten"
+L["Mouseover Highlight"] = "Mouseover Hervorhebung"
+L["Mouseover"] = "Mouseover"
+L["Multi-Monitor Support"] = "Multi-Monitor Unterstützung"
+L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."] = "Multipliziere die Höhe und die Breite des Hintergrundes. Das ist nützlich, wenn du mehr als eine Leiste hinter einem Hintergrund haben möchtest."
+L["NPC IDs"] = "NSC IDs"
+L["Name Color"] = "Namen Farbe"
+L["Name Colored Glow"] = "Klassenfarben Leuchten"
+L["Name Font"] = "Schriftart von Spielernamen"
+L["Name Only"] = "Nur Name"
+L["Name"] = true
+L["NamePlate Style Filters"] = "Namensplaketten Stil Filter"
+L["NamePlates"] = "Namensplaketten"
+L["Nameplate"] = "Namensplakette"
+L["Neutral"] = "Neutral"
+L["Never Hide"] = "Niemals verstecken"
+L["No Alert In Combat"] = "Kein Alarm im Kampf"
+L["No Duration"] = true
+L["No Sorting"] = "Nicht Sortieren"
+L["Non-Interruptable"] = "Nicht-Unterbrechbar"
+L["Non-Target Alpha"] = "Nicht-Anvisiert Alpha"
+L["Not Casting Anything"] = "Zaubert nicht irgendetwas"
+L["Not Channeling Anything"] = "Kanalisiert nicht irgendetwas"
+L["Not Spell"] = "Kein Zauber"
+L["Not Targeted"] = "Nicht anvisiert"
+L["Not Usable"] = "Nicht nutzbar"
+L["Not valid spell id"] = "Keine gültige Zauber ID"
+L["Num Rows"] = "Anzahl der Reihen"
+L["Number of Groups"] = "Anzahl der Gruppen"
+L["Number of messages you scroll for each step."] = "Anzahl der Nachrichten die mit jeden Schritt gescrollt werden."
+L["Number of repeat characters while in combat before the chat editbox is automatically closed. Set to 0 to disable."] = "Anzahl der wiederholten Zeichen im Kampf, bevor das Chateingabefeld automatisch schließt. Auf 0 setzen zum deaktivieren."
+L["Number of time in seconds to scroll down to the bottom of the chat window if you are not scrolled down completely."] = "Anzahl der Sekunden um im Chatfenster nach unten zu scrollen, wenn du nicht komplett nach unten gescrollt bist."
+L["Objective Frame Height"] = "Questfenster Höhe"
+L["Off Cooldown"] = "Benutzbar"
+L["Offset of the powerbar to the healthbar, set to 0 to disable."] = "Versatz der Powerleiste zu der Lebensleiste. Setze es auf 0 um den Versatz zu deaktivieren."
+L["Offset position for text."] = "Versatz Positionen für Texte."
+L["Offset"] = "Versatz"
+L["On Cooldown"] = "Auf Abklingzeit"
+L["Only Match SpellID"] = "Nur SpellID entsprechen"
+L["Only show when the unit is not in range."] = "Nur zeigen wenn die Einheit nicht in Reichweite ist."
+L["Only show when you are mousing over a frame."] = "Nur zeigen wenn du mit der Maus über dem Fenster bist."
+L["Other Filter"] = "Anderer Filter"
+L["Other's First"] = "Andere zuerst"
+L["Others"] = "Andere"
+L["Out of Power"] = "Keine Kraft"
+L["Out of Range"] = "Außer Reichweite"
+L["Over Health Threshold"] = "Über den Gesundheit Schwellenwert"
+L["Over Power Threshold"] = "Über dem Kraft Schwellenwert"
+L["Overlay Alpha"] = "Überblendungs Aplha"
+L["Overlay"] = "Überblenden"
+L["Overnuking"] = true
+L["Override any custom visibility setting in certain situations, EX: Only show groups 1 and 2 inside a 10 man instance."] = "Überschreibe alle benutzerdefinierten Einstellungen für die Sichtbarkeit in bestimmten Situationen. Beispiel: Zeige nur Gruppe 1 und 2 in einer 10er-Instanz."
+L["Override the default class color setting."] = "Überschreibe die Standard Klassenfarben Einstellungen"
+L["Owners Name"] = "Name des Besitzers"
+L["PVP Trinket"] = "PVP Schmuck"
+L["Panel Backdrop"] = "Fensterhintergrund"
+L["Panel Height"] = "Fensterhöhe"
+L["Panel Texture (Left)"] = "Fenstertextur (Links)"
+L["Panel Texture (Right)"] = "Fenstertextur (Rechts)"
+L["Panel Transparency"] = "Leisten Transparenz"
+L["Panel Width (Bags)"] = "Leistenbreite (Taschen)"
+L["Panel Width (Bank)"] = "Leistenbreite (Bank)"
+L["Panel Width"] = "Leistenbreite"
+L["Panels"] = "Leisten"
+L["Parent"] = true --No need to translate
+L["Party / Raid"] = "Gruppe / Schlachtzug"
+L["Party Only"] = "Nur in der Gruppe"
+L["Party Pets"] = "Gruppenbegleiter"
+L["Party Targets"] = "Gruppenziele"
+L["Per Row"] = "Pro Reihe"
+L["Percent"] = "Prozent"
+L["Personal"] = "Persönlich"
+L["Pet Name"] = "Name des Pets"
+L["Pet"] = "Begleiter"
+L["PetTarget"] = "Begleiter Ziel"
+L["Petition Frame"] = "Abstimmungsfenster"
+L["Pick Up Action Key"] = true
+L["Player Frame Aura Bars"] = "Spielerfenster Aurenleiste"
+L["Player Health"] = "Spieler Gesundheit"
+L["Player Out of Combat"] = "Spieler nicht im Kampf"
+L["Player Target"] = "Spieler Ziel"
+L["Player Titles"] = "Spielertitel"
+L["Player in Combat"] = "Spieler im Kampf"
+L["Player"] = "Spieler"
+L["Plugin"] = true --No need to translate
+L["Poison Effect"] = true
+L["Portrait"] = "Portrait"
+L["Position Buffs on Debuffs"] = "Positioniere Stärkungszauber zu Schwächungszauber"
+L["Position Debuffs on Buffs"] = "Positioniere Schwächungszauber zu Stärkungszauber"
+L["Position of the Chat EditBox, if datatexts are disabled this will be forced to be above chat."] = "Position der Texteingabeleiste. Sind die Infotexte deaktiviert, dann wird diese über dem Chat angebracht."
+L["Position"] = "Position"
+L["Power Threshold"] = "Kraft Schwellenwert"
+L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."] = "Der Krafttext wird bei NPC-Zielen automatisch verborgen, zusätzlich wird der Namenstext relativ zu dem Energie/Mana-Ankerpunkt umpositioniert."
+L["Power"] = "Kraft"
+L["Powers"] = "Kräfte"
+L["Prevent the same messages from displaying in chat more than once within this set amount of seconds, set to zero to disable."] = "Verhindert, dass die gleiche Nachricht im Chat mehr als einmal, innerhalb dieser festgelegten Anzahl von Sekunden, angezeigt wird. Auf Null setzen um diese Option zu deaktivieren."
+L["Primary Texture"] = "Primäre Textur"
+L["Priority"] = "Priorität"
+L["Private (Character Settings)"] = "Private (Charakter Einstellungen)"
+L["Profession Bags"] = "Berufstaschen"
+L["Profile Name"] = "Profil Name"
+L["Profile Specific"] = "Profilspezifisch"
+L["Profile imported successfully!"] = "Profil erfolgreich importiert!"
+L["Profile"] = "Profil"
+L["Progress Bar"] = "Fortschrittsbalken"
+L["Puts coordinates on the world map."] = "Platziert Koordinaten auf der Weltkarte."
+L["PvP Frames"] = "Pvp Fenster"
+L["PvP Icon"] = "PvP Symbol"
+L["PvP Queue"] = "PvP Warteschlange"
+L["PvP Text"] = true
+L["Quest Frames"] = "Quest Fenster"
+L["Quest Starter"] = "Quest beginnen"
+L["Quiver"] = true
+L["RAID_CONTROL"] = "Schlachtzugssteuerung"
+L["RL / ML Icons"] = "Schlachtzugsleister / Plündermeister Symbole"
+L["Raid Difficulty"] = "Schlachtzug Schwierigkeitsgrad"
+L["Raid Frame"] = "Schlachtzugsfenster"
+L["Raid Icon"] = "Schlachtzugssymbol"
+L["Raid Only"] = "Nur im Schlachtzug"
+L["Raid Pet"] = "Schlachtzugsbegleiter"
+L["Raid-40"] = "40er Schlachtzug"
+L["Raid-Wide Sorting"] = "Raidweite Sortierung"
+L["RaidDebuff Indicator"] = "RaidDebuff Indikator"
+L["Range"] = "Reichweite"
+L["Rapidly update the health, uses more memory and cpu. Only recommended for healing."] = "Schnelle Aktualisierung der Lebensleiste. Benutzt mehr Speicher und Prozessorleistung. Nur für Heiler zu empfehlen."
+L["Reaction Castbars"] = "Reaktion Zauberleiste"
+L["Reaction Colors"] = "Reaktionsfarbe"
+L["Reaction Type"] = "Reaktion Typ"
+L["Reactions"] = "Reaktionen"
+L["Ready Check Icon"] = "Bereitschaftssymbol"
+L["Realm Time"] = true
+L["Remaining / Max"] = "Verbleibend / Max"
+L["Remaining Time"] = "Verbleibende Zeit anzeigen"
+L["Remaining"] = "Verbleibend"
+L["Reminder"] = true
+L["Remove Backdrop"] = "Hintergrund entfernen"
+L["Remove Name"] = "Name entfernen"
+L["Remove Spell ID or Name"] = "Entferne Zauber ID oder Name"
+L["Remove Spell"] = "Entferne Zauber"
+L["Remove SpellID"] = "Entferne Zauber ID"
+L["Remove a Name from the list."] = true
+L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."] = "Entferne Zauber vom Filter. Benutze die Zauber ID, wenn du die ID siehst als Teil vom Zaubernamen im Filter."
+L["Remove a spell from the filter."] = "Entfernt einen Zauber aus dem Filter."
+L["Replace Blizzard Fonts"] = "Blizzard Schriftarten überschreiben"
+L["Replaces the default Blizzard fonts on various panels and frames with the fonts chosen in the Media section of the ElvUI Options. NOTE: Any font that inherits from the fonts ElvUI usually replaces will be affected as well if you disable this. Enabled by default."] = "Ersetzt die Standard Blizzard Schriftarten in verschiedenen Fenstern und Leisten mit den im Medienbereich des ElvUI Options gewählten Schriftenarten. HINWEIS: Jede Schrift die ElvUI standardmäßig ersetzt ist ebenfalls betroffen wenn du dieses deaktivierst. Standardmäßig aktiviert."
+L["Reposition Window"] = "Fenster zurücksetzen"
+L["Require All"] = "Benötigt alle"
+L["Require Target"] = true
+L["Require holding the Alt key down to move cursor or cycle through messages in the editbox."] = "Erfordert dass die Alt-Taste gedrückt wird, um mit den Mauszeiger durch die Nachrichten zu scrollen."
+L["Reset Anchors"] = "Ankerpunkte zurücksetzen"
+L["Reset Aura Filters"] = "Setze Aurafilter zurück"
+L["Reset Editbox History"] = true
+L["Reset Filter"] = "Filter zurücksetzen"
+L["Reset History"] = true
+L["Reset Priority"] = "Setze die Priorität zurück"
+L["Reset Zoom"] = "Zoom zurücksetzen"
+L["Reset all frames to their original positions."] = "Setze alle Einheiten an ihre ursprüngliche Position zurück."
+L["Reset filter priority to the default state."] = "Setze die Filter Priorität auf Standard zurück."
+L["Reset the size and position of this frame."] = "Setzt die Größe und Position vom Fenster zurück."
+L["Rest Icon"] = "Ausgeruht-Symbol"
+L["Restore Bar"] = "Leiste zurücksetzen"
+L["Restore Defaults"] = "Standard wiederherstellen"
+L["Restore the actionbars default settings"] = "Wiederherstellung der vordefinierten Aktionsleisteneinstellung"
+L["Resurrect Icon"] = "Wiederbelebungssymbol"
+L["Return filter to its default state."] = "Setzt den Filter auf Standard zurück."
+L["Reverse Bag Slots"] = "Umgekehrte Taschenslots"
+L["Reverse Cooldown"] = true
+L["Reverse Style"] = "Stil umkehren"
+L["Reverse Toggle will enable Cooldown Text on this module when the global setting is disabled and disable them when the global setting is enabled."] = "Umgekehrte Anzeige aktiviert den Cooldown Text auf diesem Modul wenn die globale Einstellung deaktiviert ist und deaktiviert es wenn die globale Einstellung aktiviert ist."
+L["Reverse Toggle"] = "Umgekehrte Anzeige"
+L["Right Only"] = "Nur Rechts"
+L["Right Panel Height"] = "Rechte Fensterhöhe"
+L["Right Panel Width"] = "Rechte Fensterbreite"
+L["Right to Left"] = "Rechts nach Links"
+L["Right"] = "Rechts"
+L["RightClick Self-Cast"] = "Rechtsklick Selbstzauber"
+L["Role Icon"] = "Rollensymbol"
+L["Run the installation process."] = "Startet den Installationsprozess."
+L["Sanctuary"] = true
+L["Scale of the nameplate that is targetted."] = "Skalierung der Namensplaketten ausgewählter Einheiten."
+L["Scale"] = "Skalierung"
+L["Scroll Interval"] = "Scroll Intervall"
+L["Scroll Messages"] = "Scroll Nachrichten"
+L["Search Syntax"] = "Suchsyntax"
+L["Search for a spell name inside of a filter."] = "Suche nach einem Zaubernamen im Filter."
+L["Secondary Texture"] = "Sekundäre Textur"
+L["Seconds remaining on the aura duration before the bar starts moving. Set to 0 to disable."] = "Verbleibende Sekunden auf der Aura bis sie sich bewegt. Auf 0 setzen zum deaktivieren."
+L["Seconds"] = "Sekunden"
+L["Selected Text Color"] = true
+L["Selector Color"] = true
+L["Selector Style"] = true
+L["Securely Tanking"] = "Sicher am Tanken"
+L["Select Filter"] = "Filter auswählen"
+L["Select Spell"] = "Zauber auswählen"
+L["Select a profile to copy from/to."] = "Wähle ein Profil um zu kopieren von/zu."
+L["Select a unit to copy settings from."] = "Wähle eine Einheit um Einstellungen zu kopieren."
+L["Select the display method of the portrait."] = "Wähle das Anzeigemethode für das Portrait."
+L["Sell Interval"] = "Verkaufsintervall"
+L["Send ADDON_ACTION_BLOCKED errors to the Lua Error frame. These errors are less important in most cases and will not effect your game performance. Also a lot of these errors cannot be fixed. Please only report these errors if you notice a Defect in gameplay."] = "Sende ADDON_ACTION_BLOCKED Fehler zum Lua-Fehlerfenster. Diese Fehler sind weniger wichtig und werden deine Spielleistung nicht beeinflussen. Viele dieser Fehler können nicht beseitigt werden. Bitte melde diese Fehler nur, wenn es einen Defekt im Spiel verursacht."
+L["Sends your current profile to your target."] = "Sende dein momentanes Profil an dein Ziel."
+L["Sends your filter settings to your target."] = "Sende deine Filter Einstellungen an dein Ziel."
+L["Separate Panel Sizes"] = "Getrennte Chatfenster Größenoptionen"
+L["Seperate"] = "Seperat"
+L["Set Settings to Default"] = "Setzte die Einstellungen auf Standard"
+L["Set the alpha level of portrait when frame is overlayed."] = "Setzt dass Alpha Level wenn die Portraits überblendet sind."
+L["Set the filter type. Blacklist will hide any auras in the list and show all others. Whitelist will show any auras in the filter and hide all others."] = "Wähle den Filtertyp. Blacklist versteckt alle Auren in der Liste und zeigt den Rest an. Whitelist zeigt alle Auren in der Liste an und versteckt den Rest."
+L["Set the font outline."] = "Setzt die Schrift auf Outline."
+L["Set the font size for everything in UI. Note: This doesn't effect somethings that have their own seperate options (UnitFrame Font, Datatext Font, ect..)"] = "Setze die Größe für die Schriftart der gesamten Benutzeroberfläche fest. Notiz: Dies hat keinen Einfluss auf Optionen, die ihre eigenen Einstellungen haben (Einheitenfenster Schrift, Infotext Schrift, ect..)"
+L["Set the font size for unitframes."] = "Wähle die Schriftart für die Einheitenfenster."
+L["Set the order that the group will sort."] = "Wähle die Richtung in welche die Gruppe sortiert werden soll."
+L["Set the orientation of the UnitFrame."] = "Setzt die Ausrichtung des Einheitenfensters."
+L["Set the priority order of the spell, please note that prioritys are only used for the raid debuff module, not the standard buff/debuff module. If you want to disable set to zero."] = "Wähle die Priorität des Zaubers. Bitte beachte, dass sich die Priorität nur auf das Schlachtzugsschwächungszauber-Modul auswirkt und nicht auf das Standard-Stärkungs/Schwächungszauber-Modul. Möchtest du es deaktivieren, dann setze es auf 0."
+L["Set the size of the individual auras."] = "Lege die Größe der individuellen Stärkungszauber fest."
+L["Set the size of your bag buttons."] = "Setze die Größe der Taschen Taste."
+L["Set the type of auras to show when a unit is a foe."] = "Wähle den Aurentyp, der angezeigt werden soll, wenn das Ziel feindlich ist."
+L["Set the type of auras to show when a unit is friendly."] = "Wähle den Aurentyp, der angezeigt werden soll, wenn das Ziel freundlich ist."
+L["Set to either stack nameplates vertically or allow them to overlap."] = "Namensplaketten übereinander stapeln oder überlappen."
+L["Sets the font instance's horizontal text alignment style."] = "Wähle die Schriftart Instanz horizontal zur Ausrichtung des Textes Stils."
+L["Share Current Profile"] = "Teile das momentane Profil"
+L["Share Filters"] = "Teile Filter"
+L["Short (Whole Numbers)"] = "Kurz (ganze Zahlen)"
+L["Short Channels"] = "Kurze Kanäle"
+L["Shortcut to 'Filters' section of the config."] = "Verknüpfung zur 'Filter' Sektion in den Einstellungen."
+L["Shortcut to global filters."] = "Verknüpfung zu Globalen Filter"
+L["Shortcuts"] = "Verknüpfungen"
+L["Shorten the channel names in chat."] = "Kürze Kanalnamen im Chat."
+L["Should tooltip be anchored to mouse cursor"] = "Soll das Tooltip an den Mauszeiger geankert werden"
+L["Show Aura From Other Players"] = "Zeige Auren von anderen Spielern"
+L["Show Auras"] = "Zeige Auren"
+L["Show Bind on Equip/Use Text"] = "Zeigt gebunden beim Aufheben/Anlegen Text"
+L["Show Both"] = "Zeige Beide"
+L["Show Coins"] = "Währungssymbole anzeigen"
+L["Show Dispellable Debuffs"] = "Zeige stehlbare Schwächungszauber"
+L["Show Empty Buttons"] = "Zeige leere Tasten"
+L["Show For DPS"] = "Zeige für Schadensklassen"
+L["Show For Healers"] = "Zeige für Heiler"
+L["Show For Tanks"] = "Zeige für Tanks"
+L["Show Icon"] = "Zeige Symbol"
+L["Show Junk Icon"] = "Zeige Müll Symbol"
+L["Show Quality Color"] = "Zeige Qualitätsfarbe"
+L["Show Quest Icon"] = true
+L["Show When Not Active"] = "Zeige, wenn nicht aktiv"
+L["Show an incoming heal prediction bar on the unitframe. Also display a slightly different colored bar for incoming overheals."] = "Zeige eingehende Heilung im Einheitenfenster. Zeigt eine etwas anders farbige Leiste für eingehende Überheilung."
+L["Show the castbar icon desaturated if a spell is not interruptible."] = "Zeigt das Zauberleistensymbol entsättigt an, wenn ein Zauber nicht unterbrechbar ist."
+L["Show/Hide Test Frame"] = "Zeige/Verstecke Test Fenster"
+L["Side Arrows"] = "Seitliche Pfeile"
+L["Size Override"] = "Größe überschreiben"
+L["Size and Positions"] = "Größe und Positionen"
+L["Size of the indicator icon."] = "Größe des Anzeigesymbole."
+L["Size"] = "Größe"
+L["Skin Backdrop (No Borders)"] = "Skin für den Hintergrund (kein Rahmen)"
+L["Skin Backdrop"] = "Skin für den Hintergrund"
+L["Skin the blizzard chat bubbles."] = "Skin die Blizzard Chat Sprechblasen."
+L["Skins"] = "Skins"
+L["Small Panels"] = "Schmale Leisten"
+L["Smaller World Map"] = "Kleinere Weltkarte"
+L["Smart Aura Position"] = "Intelligente Aurenposition"
+L["Smart Raid Filter"] = "Intelligenter Raid-Filter"
+L["Smart"] = "Elegant"
+L["Smooth Bars"] = "Sanfte Leistenübergänge"
+L["Smooth"] = "Sanft"
+L["Smoothing Amount"] = "Sanfter Animationswert"
+L["Socket Frame"] = "Sockel Fenster"
+L["Sort By"] = "Sortieren nach"
+L["Sort Direction"] = "Sortierrichtung"
+L["Sort Inverted"] = "Umgekehrtes sortieren"
+L["Sort Method"] = "Sortiermethode"
+L["Soul Bag"] = true
+L["Spaced"] = "Abgetrennt"
+L["Spacing"] = "Abstand"
+L["Spam Interval"] = "Spam Intervall"
+L["Spark"] = "Funken"
+L["Spell/Item IDs"] = "Zauber/Gegenstand IDs"
+L["Split"] = "Aufteilen"
+L["Stable"] = "Stall"
+L["Stack Counter"] = "Stapel Zähler"
+L["Stack Text Position"] = "Aufladungstext Position"
+L["Stack Text X-Offset"] = "Aufladungstext X-Versatz"
+L["Stack Text Y-Offset"] = "Aufladungstext Y-Versatz"
+L["Stack Threshold"] = "Stapel Schwellenwert"
+L["Start Near Center"] = "Starte nahe der Mitte"
+L["StatusBar Texture"] = "Statusleistentextur"
+L["Statusbar Fill Orientation"] = "Füllrichtung der Statusleiste"
+L["Statusbar"] = true
+L["Sticky Chat"] = "Kanal merken"
+L["Strata and Level"] = "Schicht und Ebene"
+L["Style Filter"] = "Stil Filter"
+L["Style"] = "Stil"
+L["Tab Font Outline"] = "Tab Schriftkontur"
+L["Tab Font Size"] = "Tab Schriftgröße"
+L["Tab Font"] = "Tab Schriftart"
+L["Tab Panel Transparency"] = "Tableisten Transparenz"
+L["Tab Panel"] = "Tableiste anzeigen"
+L["Tab Selector"] = true
+L["Tabard Frame"] = "Wappenrockfenster"
+L["Table"] = "Tabelle"
+L["Tank Target"] = "Tank Ziel"
+L["Tank"] = "Schutz"
+L["Tapped"] = "Angeschlagen"
+L["Target Indicator Color"] = "Ziel Indikator Farbe"
+L["Target Info"] = "Ziel Info"
+L["Target On Mouse-Down"] = "Ziel bei Maus-Runter"
+L["Target Scale"] = "Ziel Skalierung"
+L["Target units on mouse down rather than mouse up. \n\n|cffFF0000Warning: If you are using the addon 'Clique' you may have to adjust your clique settings when changing this."] = "Nimmt die Einheit ins Ziel bei Maus-Runter anstatt bei Maus-Hoch. |cffFF0000Warnung: Wenn du das Addon 'Clique' benutzt musst du das auch in den Clique Einstellungen ändern wenn du das hier benutzt."
+L["Target/Low Health Indicator"] = "Ziel-/Geringer Leben Indikator"
+L["TargetTarget"] = "Ziel des Ziels"
+L["TargetTargetTarget"] = "Ziel des Ziels des Ziels"
+L["Targeted Glow"] = "Anvisiert Leuchten"
+L["Targeting"] = "Zielauswahl"
+L["Testing:"] = "Tester:"
+L["Text Fade"] = "Text Verblassen"
+L["Text Color"] = "Text Farbe"
+L["Text Font Size"] = "Text Schriftgröße"
+L["Text Format"] = "Textformat"
+L["Text Position"] = "Textposition"
+L["Text Threshold"] = "Text Schwelle"
+L["Text Toggle On NPC"] = "Textumschalter auf NPCs"
+L["Text xOffset"] = "Text X-Versatz"
+L["Text yOffset"] = "Text Y-Versatz"
+L["Text"] = "Text"
+L["Texture"] = "Textur"
+L["Textured Icon"] = "Texturiertes Symbol"
+L["Textures"] = "Texturen"
+L["The Portrait will overlay the Healthbar. This will be automatically happen if the Frame Orientation is set to Middle."] = "Das Portrait wird die Lebensleiste überdecken. Dieses wird automatisch passieren wenn die Fensterausrichtung auf Mittel gesetzt ist."
+L["The Thin Border Theme option will change the overall apperance of your UI. Using Thin Border Theme is a slight performance increase over the traditional layout."] = "Das Dünne Rahmen Theme ändert das gesamte Erscheinungsbild deines UI. Das Benutzten des Dünnen Rahmen Theme ist ein kleiner performance Schub gegenüber dem traditionellen Layout."
+L["The amount of buttons to display per row."] = "Anzahl der Aktionstasten in einer Reihe."
+L["The amount of buttons to display."] = "Anzahl der angezeigten Aktionstasten."
+L["The button you must hold down in order to drag an ability to another action button."] = "Die Taste, die du gedrückt halten musst, um eine Fähigkeit zu einer anderen Aktionstaste zu ziehen."
+L["The debuff needs to reach this amount of stacks before it is shown. Set to 0 to always show the debuff."] = "Der Schwächungszauber muss erst den angegebenen Wert erreichen um angezeigt zu werden. 0 zeigt den Schwächungszauber immer an."
+L["The direction that the bag frames be (Horizontal or Vertical)."] = "Die Ausrichtung der Leiste (Horizontal oder Vertikal)."
+L["The direction that the bag frames will grow from the anchor."] = "Die Richtung in welche das Fenster vom Ankerpunkt aus wächst (Horizontal oder Vertikal)."
+L["The direction the auras will grow and then the direction they will grow after they reach the wrap after limit."] = "Die Richtung, die Aura wird wachsen wird und dann die Richtung dei Sie wachsen wird, nachdem sie die Grenze nach Wrap erreichen."
+L["The display format of the currency icons that get displayed below the main bag. (You have to be watching a currency for this to display)"] = "Das Anzeigeformat für die Währungssymbole, welche unter der Haupttasche angezeigt werden. (Du musst eine Währung beobachten, damit diese angezeigt wird)"
+L["The display format of the money text that is shown at the top of the main bag."] = "Das Anzeigeformat für Gold oben an der Haupttasche."
+L["The display format of the money text that is shown in the gold datatext and its tooltip."] = "Das Anzeigeformat für Gold in den Haupt-Infoleisten und Tooltips."
+L["The first button anchors itself to this point on the bar."] = "Der erste Aktionstaste dockt an diesen Punkt in der Leiste an."
+L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."] = "Das folgende Makro muss wahr sein um die Gruppe anzuzeigen. Dies gilt zusätzlich zu jeglichem Filter der möglicherweise bereits eingestellt ist."
+L["The font that appears on the text above players heads. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "Die Schrift, die über den Köpfen der Spieler auftaucht. |cffFF0000WARNUNG: Das benötigt einen Neustart des Spiels oder einen Relog um in Effekt zu treten.|r"
+L["The font that combat text will use. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "Die Schriftart des Kampftextes. |cffFF0000WARNUNG: Nach der änderung dieser Option muss das Spiel neu gestartet werden.|r"
+L["The font that the core of the UI will use."] = "Die Schriftart, die hauptsächlich vom UI verwendet wird."
+L["The font that the unitframes will use."] = "Die Schriftart, welche die Einheitenfenster benutzen sollen."
+L["The frame is not shown unless you mouse over the frame."] = "Das Fenster ist nicht sichtbar, außer man bewegt die Maus darüber."
+L["The initial group will start near the center and grow out."] = "Die anfängliche Gruppe wird nahe der Mitte starten und dann wachsen"
+L["The minimum item level required for it to be shown."] = "Das minimale Itemlevel um angezeigt zu werden."
+L["The name you have selected is already in use by another element."] = "Den Namen den du ausgewählt hast, wird bereits von einem anderem Element benutzt."
+L["The object you want to attach to."] = "Das Objekt, das du anhängen willst"
+L["The size of the action buttons."] = "Die Größe der Aktionstasten."
+L["The size of the individual buttons on the bag frame."] = "Die Größe der einzelnen Tasten auf dem Taschenfenster."
+L["The size of the individual buttons on the bank frame."] = "Die Größe der einzelnen Tasten auf dem Bankfenster."
+L["The spacing between buttons."] = "Der Abstand zwischen den Tasten."
+L["The spacing between the backdrop and the buttons."] = "Der Abstand zwischen dem Hintergrund und den Tasten."
+L["The texture that will be used mainly for statusbars."] = "Diese Textur wird vorallem für Statusbars verwendet."
+L["The unit prefixes you want to use when values are shortened in ElvUI. This is mostly used on UnitFrames."] = "Der Einheitenpräfix den du benutzen möchtest wenn die Werte von ElvUI verkürzt sind. Wird meist auf den Einheitenfenstern benutzt."
+L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."] = "Diese Filter benutzen keine Liste von Zaubern wie die regulären Filter. Sie benutzen anstatt die WoW API um festzustellen ob eine Aura erlaubt oder geblockt wird."
+L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."] = "Diese Filter nutzen eine Liste von Zaubern um festzustellen ob eine Aura erlaubt oder geblockt wird. Der Inhalt dieses Filter kann in der 'Filter' Sektion der Konfiguration bearbeitet werden."
+L["Thin Border Theme"] = "Dünner Rahmen Theme"
+L["Thin Borders"] = "Dünne Rahmen"
+L["This dictates the size of the icon when it is not attached to the castbar."] = "Dieses zwingt die Größe des Symbols wenn es nicht an der Zauberleiste angehängt ist."
+L["This feature will allow you to transfer settings to other characters."] = "Dieses Feature erlaubt es dir Einstellungen an andere Charaktere zu schicken."
+L["This is for Customized Icons in your Interface/Icons folder."] = "Dieses ist für Benutzerdefinierte Symbole in deinem Interface/Icon Ordner."
+L["This opens the UnitFrames Color settings. These settings affect all unitframes."] = "Dieses öffnet die Farbeinstellung für die Einheitenfenster. Diese Einstellungen wirken sich auf alle Einheitenfenster aus."
+L["This option allows the overlay to span the whole health, including the background."] = "Diese Option erlaubt erlaubt dass volle überblenden der Gesundheit, inklusive des Hintergrund."
+L["This section will allow you to copy settings to a select module from or to a different profile."] = "Diese Sektion erlaubt dir die Einstellungen von einem ausgewählten Module zu oder von einen anderen Profil zu kopieren."
+L["This section will help reset specfic settings back to default."] = "Diese Sektion wird dir dabei helfen spezifische Einstellungen zurückzusetzen."
+L["This selects the Chat Frame to use as the output of ElvUI messages."] = "Dieses wählt das Chatfenster aus wo die ElvUI Nachrichten erscheinen sollen."
+L["This setting controls the size of text in item comparison tooltips."] = "Diese Einstellung kontrolliert die Größe der Schrift vom Text im Item Vergleichs-Tooltip."
+L["This setting will be updated upon changing stances."] = "Diese Einstellungen werden bei Gestaltwandel aktualisiert"
+L["This texture will get used on objects like chat windows and dropdown menus."] = "Diese Textur wird für Objekte wie Chatfenster und Dropdown-Menüs benutzt."
+L["This will override the global cooldown settings."] = "Dieses überschreibt die globale Abklingzeiteinstellung."
+L["This will prevent the UI Scale Popup from being shown when changing the game window size."] = "Dieses verhindert dass das UI Skalierungs-Popup erscheint, wenn man die Spiel Fenstergröße ändert."
+L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."] = "Dieses wird den Inhalt des Filters auf Standard zurücksetzen. Jeder Zauber den du zum Filter hinzugefügt hast wird gelöscht."
+L["Threat Display Mode"] = "Bedrohungs Anzeige Modus"
+L["Threat Health"] = "Bedrohungs-Gesundheit"
+L["Threat Power"] = "Bedrohungs-Kraft"
+L["Threat"] = "Bedrohung"
+L["Threshold (in minutes) before text is shown in the HH:MM format. Set to -1 to never change to this format."] = "Schwellenwert (in Minuten) bevor der Text in MM:SS Format angezeigt wird. Setze auf -1 um niemals das Format zu ändern."
+L["Threshold (in seconds) before text is shown in the MM:SS format. Set to -1 to never change to this format."] = "Schwellenwert (in Sekunden) bevor der Text in MM:SS Format angezeigt wird. Setze auf -1 um niemals das Format zu ändern."
+L["Threshold before text goes into decimal form. Set to -1 to disable decimals."] = "Schwellenwert bevor der Text in die Dezimalform wechselt. Auf -1 setzen, um Dezimalstellen zu deaktivieren."
+L["Threshold before text turns red and is in decimal form. Set to -1 for it to never turn red"] = "CD-Schwelle bevor der Text rot wird. Setze diesen Wert auf -1, wenn er nie rot werden soll"
+L["Threshold before the icon will fade out and back in. Set to -1 to disable."] = "Schwelle bevor das Symbol ausblendend und wieder einblendet. Setze auf -1 um zu deaktivieren."
+L["Ticks"] = "Ticks"
+L["Time Format"] = "Zeit-Format"
+L["Time Indicator Colors"] = "Zeit Indikator Farben"
+L["Time Remaining Reverse"] = "Zeit verbleibend umkehren"
+L["Time Remaining"] = "Zeit verbleibend"
+L["Time To Hold"] = "Anzeigezeit"
+L["Time xOffset"] = "Zeit X-Versatz"
+L["Time yOffset"] = "Zeit Y-Versatz"
+L["Time"] = "Zeit"
+L["Timestamp Color"] = "Zeitstempel Farbe"
+L["Toggle Anchors"] = "Ankerpunkte umschalten"
+L["Toggle Off While In Combat"] = "Im Kampf ausblenden"
+L["Toggle On While In Combat"] = "Im Kampf einblenden"
+L["Toggle Tutorials"] = "Tutorial starten"
+L["Toggle showing of the left and right chat panels."] = "Aktiviere den Hintergrund des linken und rechten Chatfensters"
+L["Toggle the chat tab panel backdrop."] = "Aktiviere den Hintergrund der oberen Tableisten der Chatfenster"
+L["Toggles the display of the actionbars backdrop."] = "Aktiviere den Hintergrund der Aktionsleisten."
+L["Tooltip Font Settings"] = "Tooltip Schrifteinstellung"
+L["Top Arrow"] = "Oberer Pfeil"
+L["Top Left"] = "Oben links"
+L["Top Panel"] = "Obere Leiste"
+L["Top Right"] = "Oben rechts"
+L["Top to Bottom"] = "Von oben nach unten"
+L["Top"] = "Oben"
+L["TopLeftMiniPanel"] = "Minimap Obenlinks (Innen)"
+L["TopMiniPanel"] = "Minimap Oben (Innen)"
+L["TopRightMiniPanel"] = "Minimap Obenrechts (Innen)"
+L["Totem"] = true
+L["Trainer Frame"] = "Lehrerfenster"
+L["Transparency level when not in combat, no target exists, full health, not casting, and no focus target exists."] = "Transparenz Level wenn nicht im Kampf, kein Ziel ausgewählt, volle Gesundheit, nicht am Zaubern und kein Fokus existiert."
+L["Transparent Backdrops"] = true
+L["Transparent Buttons"] = true
+L["Transparent"] = "Transparent"
+L["Triggers"] = "Auslöser"
+L["Turtle Color"] = "Turtle Farbe"
+L["Tutorial Frame"] = "Tutorial Fenster"
+L["URL Links"] = "URL Links"
+L["Under Health Threshold"] = "Unter Gesundheit Schwellenwert"
+L["Under Power Threshold"] = "Unter dem Kraft Schwellenwert"
+L["Uniform Threshold"] = "Einheitlicher Schwellenwert"
+L["Unique Units"] = true
+L["Unit Prefix Style"] = "Einheit Präfix Stil"
+L["Unit Target"] = "Einheit Ziel"
+L["Unit Type"] = "Einheiten Typ"
+L["UnitFrames"] = "Einheitenfenster"
+L["Unlock various elements of the UI to be repositioned."] = "Schalte verschiedene Elemente der Benutzeroberfläche frei um sie neu zu positionieren."
+L["Up"] = "Hinauf"
+L["Usable"] = "Nutzbar"
+L["Use Alt Key"] = "Benutze Alt-Taste"
+L["Use Class Color"] = "Benutze Klassenfarbe"
+L["Use Custom Level"] = "Benutze benutzerdefinierte Ebene"
+L["Use Custom Strata"] = "Benutze benutzerdefinierte Schicht"
+L["Use Dead Backdrop"] = "Benutze Hintergrundfarbe vom Tod"
+L["Use Default"] = "Benutze Standard"
+L["Use Indicator Color"] = "Benutze Indikator Farbe"
+L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."] = "Benutze Shift+Linksklick um zwischen freundlichem oder freindlichen Status umzuschalten. Normaler Status erlaubt den Filter alle Einheiten zu überprüfen. Freundlicher Status überprüft nur freundliche Einheiten. Feindliche überprüft nur feindliche Einheiten."
+L["Use Target Scale"] = "Benutze Ziel Skalierung"
+L["Use Threat Color"] = "Benutze Bedrohungsfarbe"
+L["Use class color for the names of players when they are mentioned."] = "Benutze Klassenfarben von Spielernamen, wenn sie erwähnt werden."
+L["Use coin icons instead of colored text."] = "Benutze Währungssymbole anstatt von farbigem Text."
+L["Use drag and drop to rearrange filter priority or right click to remove a filter."] = "Benutze Drag und Drop um die Filter Priorität zu arrangieren oder rechts klick um einen Filter zu entfernen."
+L["Use the Name Color of the unit for the Name Glow."] = "Benutze Klassenfarbe für das Einheiten Namensleuchten."
+L["Use the custom backdrop color instead of a multiple of the main color."] = "Benutze eine eigene Hintergrundfarbe, anstelle der Hauptfarbe."
+L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."] = "Benutze den Profilspezifischen 'Buff Indikator (Profil)' anstatt des globalen Filter 'Buff Indikator'."
+L["Use thin borders on certain unitframe elements."] = "Benutze dünne Rahmen auf bestimmten Einheitenfenster Elementen."
+L["Use this backdrop color for units that are dead or ghosts."] = "Benutze diese Hintergrundfarbe für Einheiten die Tod oder als Geist sind."
+L["Used as RaidDebuff Indicator"] = "Verwendet als RaidDebuff Indikator"
+L["Value Color"] = "Farbwert"
+L["Value must be a number"] = "Der Wert muss eine Zahl sein"
+L["Vehicle Seat Indicator Size"] = "Fahrzeugfenster Skalierung"
+L["Vehicle"] = "Fahrzeug"
+L["Vendor Gray Detailed Report"] = "Graue Gegenstände detaillierter Report"
+L["Vendor Grays"] = "Graue Gegenstände verkaufen"
+L["Version"] = "Version"
+L["Vertical Fill Direction"] = "Vertikale Füllausrichtung"
+L["Vertical Spacing"] = "Vertikaler Abstand"
+L["Vertical"] = "Vertikal"
+L["Visibility State"] = "Sichbarkeitszustand"
+L["Visibility"] = "Sichtbarkeit"
+L["Watch Frame"] = true
+L["What point to anchor to the frame you set to attach to."] = "Welchen Punkt für das verankern der Fenster möchtest du wählen."
+L["What to attach the buff anchor frame to."] = "Wo die Stärkungszauber angehängt werden sollen."
+L["What to attach the debuff anchor frame to."] = "Wo die Schwächungszauber angehängt werden sollen."
+L["When enabled active buff icons will light up instead of becoming darker, while inactive buff icons will become darker instead of being lit up."] = "Wenn diese Option aktiviert wird, leuchten die Symbole für aktive Stärkungszauber auf und inaktive Stärkungszauber werden dunkler. Ansonsten leuchten die Symbole für inaktive Stärkungszauber auf und aktive Stärkungszauber werden dunkler."
+L["When enabled it will only show spells that were added to the filter using a spell ID and not a name."] = "Wenn aktiviert werden nur Zauber angezeigt die dem Filter hinzugefügt wurden die der SpellID entsprechen und nicht dem Namen."
+L["When in a raid group display if anyone in your raid is targeting the current tooltip unit."] = "Zeige ob jemand aus deiner Gruppe/Schlachtzug die Tooltip-Einheit ins Ziel genommen hat."
+L["When inside a battleground display personal scoreboard information on the main datatext bars."] = "Zeige innerhalb eines Schlachtfeldes persönliche Statistiken in den Haupt-Infoleisten."
+L["When opening the Chat Editbox to type a message having this option set means it will retain the last channel you spoke in. If this option is turned off opening the Chat Editbox should always default to the SAY channel."] = "Beim Öffnen der Texteingabeleiste wird dem Kanal beigetreten, in den zu letzt geschrieben wurde. Wenn diese Option deaktiviert ist, wird standardmäßig der SAGEN-Kanal beim öffnen der Texteingabeleiste aufgerufen."
+L["When true, the header includes the player when not in a raid."] = "Wenn aktiv und sich der Spieler nicht in einem Raid befindet, dann wird das angezeigt."
+L["When you go AFK display the AFK screen."] = "AFK Bildschirm anzeigen wenn du AFK bist."
+L["Whitelist"] = "Weiße Liste"
+L["Width Multiplier"] = "Breitenmultiplikator"
+L["Width"] = "Breite"
+L["Will attempt to sell another item in set interval after previous one was sold."] = "Versucht einen anderen Gegenstand in einem bestimmten Intervall zu verkaufen, nachdem der vorherige verkauft wurde."
+L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."] = "Zeigt Stärkungszauber auf der Position der Schwächungszauber, wenn kein Schwächungszauber aktiv ist und vice versa."
+L["Word Wrap"] = "Zeilenumbruch"
+L["World Map Coordinates"] = "Weltkarten Koordinaten"
+L["World State Frame"] = true
+L["Wrap After"] = "Neue Reihe/Spalte beginnen"
+L["X-Offset"] = "X-Versatz"
+L["Y-Offset"] = "Y-Versatz"
+L["You do not need to use 'Is Casting Anything' or 'Is Channeling Anything' for these spells to trigger."] = "Du brauchst nicht 'Ist irgendetwas am Zaubern' oder 'Ist irgendetwas am Kanalisieren' für die Zauber auswählen um Auszulösen."
+L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."] = "Du kannst keinen Filter entfernen, der nicht von dir selbst hinzugefügt wurde. Setzte den Zauber einfach auf deaktiviert."
+L["You must be targeting a player."] = "Du musst einen Spieler anvisiert haben."
+L["You need to hold this modifier down in order to blacklist an aura by right-clicking the icon. Set to None to disable the blacklist functionality."] = "Du musst den Modifikator gedrückt halten um mit rechtsklick auf ein Symbol es zur Schwarzen Liste hinzuzufügen. Setzte auf Kein um die Funktion zu deaktivieren."
+L["Your Auras First"] = "Deine Auren zuerst"
+L["xOffset"] = "X-Versatz"
+L["yOffset"] = "Y-Versatz"
+
+L["ACTIONBARS_DESC"] = "Konfiguriere die Einstellungen für die Aktionsleisten."
+L["AURAS_DESC"] = "Konfiguriere die Symbole für die Stärkungs- und Schwächungszauber nahe der Minimap."
+L["BAGS_DESC"] = "Konfiguriere die Einstellungen für die Taschen."
+L["CHAT_DESC"] = "Anpassen der Chateinstellungen für ElvUI."
+L["COOLDOWN_DESC"] = "Passe Cooldown Einstellungen an."
+L["DATABAR_DESC"] = "Einstellung der Informationsleisten."
+L["DATATEXT_DESC"] = "Bearbeite die Anzeige der Infotexte."
+L["ELVUI_DESC"] = "ElvUI ist ein komplettes Benutzerinterface für World of Warcraft."
+L["NAMEPLATE_DESC"] = "Konfiguriere die Einstellungen für die Namensplaketten."
+L["PANEL_DESC"] = "Stellt die Größe der linken und rechten Leisten ein, dies hat auch Einfluss auf den Chat und die Taschen."
+L["SKINS_DESC"] = "Passe die Einstellungen für externe Addon Skins/Optionen an."
+L["TOGGLESKIN_DESC"] = "Aktiviere/Deaktiviere diesen Skin."
+L["TOOLTIP_DESC"] = "Konfiguriere die Einstellungen für Tooltips."
+L["UNITFRAME_DESC"] = "Konfiguriere die Einstellungen für die Einheitenfenster."
+L["SEARCH_SYNTAX_DESC"] = [=[Mit der Ergänzung von LibItemSearch, kannst du jetzt erweitert nach Gegenständen suchen. Nachfolgend findest du eine Dokumentation des Suchsyntax. Die volle Erklärung findest du hier: https://github.com/Jaliborc/LibItemSearch-1.2/wiki/Search-Syntax.
+
+Spezifische Suche:
+ • q:[quality] oder quality:[quality]. Beispielsweise q:episch findet alle epischen Gegenstände.
+ • l:[level], lvl:[level] oder level:[level]. Zum Beispiel: l:30 findet alle Gegenstände mit Level 30.
+ • t:[suche], type:[suche] oder slot:[suche]. Beispielsweise t:waffe findet alle Waffen.
+ • n:[name] oder name:[name]. Beispielsweise wenn du n:muffins eintippst, findest du alle Gegenstände die "muffins" im Namen haben.
+ • s:[set] oder set:[set]. Zum Beispiel: s:feuer findet alle Gegenstände eines Ausrüstungssets mit Feuer im Namen.
+ • r:[level], reg:[level], rl:[level], regl:[level] or reqlvl:[level]. For example, reqlvl:30 will find all items that require level 30.
+ • tt:[suche], tip:[suche] oder tooltip:[suche]. Beispielsweise tt:gebunden findet alle Gegenstände die am Account, beim Aufheben oder beim Ausrüsten gebunden sind.
+
+
+Suchoperatoren:
+ • ! : Negiert eine Suche. Zum Beispiel !q:episch findet alle Gegenstände die NICHT episch sind.
+ • | : Kombiniert zwei Suchen. q:episch | t:waffe findet alle Gegenstände die episch ODER Waffen sind.
+ • & : Teilt zwei Suchen. Beispielsweise q:episch & t:waffen findet alle Gegenstände die episch UND Waffen sind.
+ • >, <, <=, => : Führt eine numerische Suche durch. Zum Beispiel: lvl: >30 findet alle Gegenstände mit Level 30 oder HÖHER.
+
+
+Die folgenden Suchbegriffe können auch benutzt werden:
+ • soulbound, bound, bop : Beim Aufheben gebundene Gegenstände.
+ • bou : Beim Benutzen gebundene Gegenstände.
+ • boe : Beim Ausrüsten gebundene Gegenstände.
+ • boa : An den Account gebundene Gegenstände.
+ • quest : Gebundene Quest Gegenstände.]=]
+L["TEXT_FORMAT_DESC"] = [=[Wähle eine Zeichenfolge um das Textformat zu ändern.
+
+Beispiele:
+[namecolor][name] [difficultycolor][smartlevel] [shortclassification]
+[healthcolor][health:current-max]
+[powercolor][power:current]
+
+Leben / Kraft Formate:
+"current" - Aktueller Wert
+"percent" - Prozentualer Wert
+"current-max" - Aktueller Wert gefolgt von dem maximalen Wert. Es wird nur der Maximale Wert anzeigt, wenn der aktuelle Wert auch das Maximum ist
+"current-percent" - Aktueller Wert gefolgt von dem prozentualen Wert. Es wird nur der maximale Wert angezeigt, wenn der aktuelle Wert auch das Maximum ist
+"current-max-percent" - Aktueller Wert, Maximaler Wert, gefolgt von dem prozentualen Wert. Es wird nur der maximale Wert angezeigt, wenn der aktuelle Wert auch das Maximum ist
+"deficit" - Zeigt das Defizit. Es wird nichts angezeigt, wenn kein Defizit vorhanden ist
+
+Namensformate:
+"name:veryshort" - Name restricted to 5 characters
+"name:short" - Name auf 10 Zeichen beschränkt
+"name:medium" - Name auf 15 Zeichen beschränkt
+"name:long" - Name auf 20 Zeichen beschränkt
+"name:short:translit" - Name restricted to 10 characters with transliteration
+
+Zum Deaktvieren lasse das Feld leer. Brauchst du mehr Informationen besuche https://www.tukui.org/forum/viewtopic.php?t=6]=]
+L["NAMEPLATE_FRAMELEVEL_DESC"] = [=[Wenn du dieses auf 1 setzt werden alle Namensplaketten die vom Stilfilter ausgelöst werden über jeder anderen Namensplakette liegen.
+
+Wenn du dieses auf 2 setzt in einem anderen Stilfilter, werden alle Namensplakette die vom Filter ausgelöst wurden, über den Namensplaketten liegen die auf 1 gesetzt sind, usw.
+
+HINWEIS: Diese Einstellung behebt NICHT die Probleme mit klicken oder mouseover von überlappenden Namensplaketten. Dieses Problem liegt dran, dass wir nicht im Stande sind das
+Frame Level von klickbaren Namensplakette zu manipulieren.]=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to page differently.
+ Example: '[combat] 2;']=] ] = [=[Dieses funktioniert wie ein Makro, du kannst verschiedene Situationen haben um die Aktionsleiste zu wechseln.
+ Beispiel: '[combat] 2;']=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to show/hide differently.
+ Example: '[combat] show;hide']=] ] = [=[Dieses funktioniert wie ein Makro, du kannst verschiedene Situationen haben um die Aktionsleiste ein-/auszublenden.
+ Beispiel: '[combat] show;hide']=]
+
+L[ [=[Specify a filename located inside the World of Warcraft directory. Textures folder that you wish to have set as a panel background.
+
+Please Note:
+-The image size recommended is 256x128
+-You must do a complete game restart after adding a file to the folder.
+-The file type must be tga format.
+
+Example: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Or for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here.]=] ] = [=[Gib einen Dateinamen im World of Warcraft Verzeichnis an. Textures Ordner, den du als Fensterhintergrund eingestellt haben willst.
+
+Bitte beachten:
+-Als Bildgröße 256x128 wird empfohlen.
+-Du musst das Spiel komplett neu starten, nachdem du die Datei hinzugefügt hast.
+-Der Dateityp muss im Format tga sein.
+
+Zum Beispiel: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Für die meisten Anwender ist es allerdigns einfacher, eine tga-Datei in ihren WoW-Ordner abzulegen. Anschließend kann man den Namen der Datei hier eingeben.]=]
+
+-- Global Strings
+L["ACHIEVEMENTS"] = "Erfolge"
+L["ALT_KEY_TEXT"] = "ALT"
+L["ARENA"] = "Arena"
+L["AUCTIONS"] = "Auktionen"
+L["BAGSLOT"] = "Tasche"
+L["BARBERSHOP"] = "Barbier"
+L["BATTLEGROUND"] = "Schlachtfeld"
+L["BATTLEFIELDS"] = "Schlachtfelder"
+L["BLOCK"] = "Blocken"
+L["BOSS"] = "Boss"
+L["BUFFOPTIONS_LABEL"] = "Stärkungs-/Schwächungszauber"
+L["CLASS"] = "Klasse"
+L["CHANNEL"] = "Channel"
+L["COLOR"] = "Farbe"
+L["COLORS"] = "Farben"
+L["COMBAT"] = "Kampf"
+L["COMBAT_TEXT_RUNE_BLOOD"] = "Blutrune"
+L["COMBAT_TEXT_RUNE_DEATH"] = "Todesrune"
+L["COMBAT_TEXT_RUNE_FROST"] = "Frostrune"
+L["COMBAT_TEXT_RUNE_UNHOLY"] = "Unheilige Rune"
+L["COMBO_POINTS"] = "Combo |4punkt:punkte;"
+L["CTRL_KEY"] = "CTRL"
+L["CUSTOM"] = "Benutzer"
+L["DAMAGER"] = "Schaden"
+L["DEFAULT"] = "Standard"
+L["DELETE"] = "Löschen"
+L["DISABLE"] = "Deaktivieren"
+L["DRESSUP_FRAME"] = "Anprobe"
+L["DUNGEON_DIFFICULTY"] = "Schwierigkeitsgrad"
+L["DUNGEONS"] = "Dungeons"
+L["EMOTE"] = "Emote"
+L["ENEMY"] = "Feindlich"
+L["ENERGY"] = "Energie"
+L["FACTION_STANDING_LABEL1"] = "Hasserfüllt"
+L["FACTION_STANDING_LABEL2"] = "Feindselig"
+L["FACTION_STANDING_LABEL3"] = "Unfreundlich"
+L["FACTION_STANDING_LABEL4"] = "Neutral"
+L["FACTION_STANDING_LABEL5"] = "Freundlich"
+L["FACTION_STANDING_LABEL6"] = "Wohlwollend"
+L["FACTION_STANDING_LABEL7"] = "Respektvoll"
+L["FACTION_STANDING_LABEL8"] = "Ehrfürchtig"
+L["FILTERS"] = "Filter"
+L["FLIGHT_MAP"] = "Flugkarte"
+L["FOCUS"] = "Fokus"
+L["FONT_SIZE"] = "Schriftgröße"
+L["FRIEND"] = "Freund"
+L["FRIENDS"] = "Freunde"
+L["GROUP"] = "Group"
+L["GUILD"] = "Gilde"
+L["GUILD_BANK"] = "Gildenbank"
+L["HAPPINESS"] = "Zufriedenheit"
+L["HEALER"] = "Heilung"
+L["HEALTH"] = "Gesundheit"
+L["HIDE"] = "Ausblenden"
+L["INSCRIPTION"] = "Inschriftenkunde"
+L["INSPECT"] = "Betrachten"
+L["INTERFACE_OPTIONS"] = "Interface-Optionen"
+L["INTERRUPTED"] = "Unterbrochen"
+L["ITEM_BIND_QUEST"] = "Questgegenstand"
+L["ITEMS"] = "Gegenstände"
+L["KEY_BINDINGS"] = "Tastaturbelegung"
+L["LANGUAGE"] = "Sprache"
+L["LEAVE_VEHICLE"] = "Fahrzeug verlassen"
+L["LEVEL"] = "Stufe"
+L["LOCK_ACTIONBAR_TEXT"] = "Leisten fixieren"
+L["LOOT"] = "Beute"
+L["MACROS"] = "Makros"
+L["MAIL_LABEL"] = "Post"
+L["MANA"] = "Mana"
+L["MAP_FADE_TEXT"] = "Kartentransparenz beim Bewegen"
+L["MERCHANT"] = "Händler"
+L["MINIMAP_LABEL"] = "Minikarte"
+L["MISCELLANEOUS"] = "Verschiedenes"
+L["NAME"] = "Name"
+L["NONE"] = "Nichts"
+L["OFFICER"] = "Offizier"
+L["OPACITY"] = "Transparenz"
+L["OPTION_TOOLTIP_ACTION_BUTTON_USE_KEY_DOWN"] = "Vordefinierte Tastaturbelegungen für Aktionen reagieren bei gedrückter statt bei losgelassener Taste."
+L["OPTION_TOOLTIP_TIMESTAMPS"] = "Bitte wählt das Format des Zeitstempels für Chatnachrichten aus."
+L["PARTY"] = "Gruppe"
+L["PET"] = "Begleiter"
+L["PLAYER"] = "Spieler"
+L["PLAYER_DIFFICULTY1"] = "Normal"
+L["PLAYER_DIFFICULTY2"] = "Heroisch"
+L["RAGE"] = "Wut"
+L["RAID"] = "Schlachtzug"
+L["RAID_TARGET_1"] = "Stern"
+L["RAID_TARGET_2"] = "Kreis"
+L["RAID_TARGET_3"] = "Diamant"
+L["RAID_TARGET_4"] = "Dreieck"
+L["RAID_TARGET_5"] = "Mond"
+L["RAID_TARGET_6"] = "Quadrat"
+L["RAID_TARGET_7"] = "Kreuz"
+L["RAID_TARGET_8"] = "Totenschädel"
+L["REPUTATION"] = "Ruf"
+L["ROLE"] = "Rolle"
+L["RUNIC_POWER"] = "Runenmacht"
+L["SAY"] = "Sagen"
+L["SHIFT_KEY"] = "SHIFT"
+L["SHORT"] = "Kurz"
+L["SHOW"] = "Anzeigen"
+L["SPEED"] = "Geschwindigkeit"
+L["SPELLBOOK"] = "Zauberbuch"
+L["TALENTS"] = "Talente"
+L["TANK"] = "Schutz"
+L["TARGET"] = "Ziel"
+L["TIMEMANAGER_TITLE"] = "Uhr"
+L["TIMESTAMPS_LABEL"] = "Chatzeitstempel"
+L["TRADE"] = "Handeln"
+L["TRADESKILLS"] = "Berufsfertigkeit"
+L["TUTORIAL_TITLE47"] = "Totemleiste"
+L["UI_SCALE"] = "UI-Skalierung"
+L["UNIT_NAMEPLATES_TYPES"] = "Bewegungstyp für Namensplaketten"
+L["UNIT_NAMEPLATES_TYPE_1"] = "Namensschilder überlappen"
+L["UNIT_NAMEPLATES_TYPE_2"] = "Namensschilder stapeln"
+L["WHISPER"] = "Flüstern"
+L["WORLD_MAP"] = "Weltkarte"
+L["XPBAR_LABEL"] = "EP-Balken"
+L["YELL"] = "Schreien"
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Locales/enUS.lua b/ElvUI_OptionsUI/Locales/enUS.lua
new file mode 100644
index 0000000..af178e9
--- /dev/null
+++ b/ElvUI_OptionsUI/Locales/enUS.lua
@@ -0,0 +1,1393 @@
+-- English localization file for enUS and enGB.
+local L = ElvUI[1].Libs.ACL:NewLocale("ElvUI", "enUS", true, true)
+
+L["%s and then %s"] = true
+L["2D"] = true
+L["3D"] = true
+L["AFK Mode"] = true
+L["ANCHOR_CURSOR"] = true
+L["ANCHOR_CURSOR_LEFT"] = true
+L["ANCHOR_CURSOR_RIGHT"] = true
+L["Abbreviation"] = true
+L["Above Chat"] = true
+L["Above"] = true
+L["Accept Invites"] = true
+L["Action Paging"] = true
+L["ActionBars"] = true
+L["Actions"] = true
+L["Add Item or Search Syntax"] = true
+L["Add Name"] = true
+L["Add Regular Filter"] = true
+L["Add Special Filter"] = true
+L["Add Spell ID or Name"] = true
+L["Add SpellID"] = true
+L["Add a Name to the list."] = true
+L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."] = true
+L["Add a spell to the filter."] = true
+L["Add an item or search syntax to the ignored list. Items matching the search syntax will be ignored."] = true
+L["Additional Power Text"] = true
+L["Additional spacing between each individual group."] = true
+L["Additive Blend"] = true
+L["Adjust the height of your right chat panel."] = true
+L["Adjust the position of the threat bar to either the left or right datatext panels."] = true
+L["Adjust the size of the minimap."] = true
+L["Adjust the width of the bag frame."] = true
+L["Adjust the width of the bank frame."] = true
+L["Adjust the width of your right chat panel."] = true
+L["Alert Frames"] = true
+L["Alerts"] = true
+L["Allow a small gradient between each threshold"] = true
+L["Allow LBF to handle the skinning of this element."] = true
+L["Allowed Combat Repeat"] = true
+L["Alpha Fading"] = true
+L["Alpha Key"] = true
+L["Alpha channel is taken from the color option."] = true
+L["Alpha"] = true
+L["Always Display"] = true
+L["Always Hide"] = true
+L["Always Show Realm"] = true
+L["Always Show Target Health"] = true
+L["Ammo Pouch"] = true
+L["An X offset (in pixels) to be used when anchoring new frames."] = true
+L["An Y offset (in pixels) to be used when anchoring new frames."] = true
+L["Anchor Point"] = true
+L["Announce Interrupts"] = true
+L["Announce when you interrupt a spell to the specified chat channel."] = true
+L["Applies the font and font size settings throughout the entire user interface. Note: Some font size settings will be skipped due to them having a smaller font size by default."] = true
+L["Applies the primary texture to all statusbars."] = true
+L["Apply Font To All"] = true
+L["Apply Texture To All"] = true
+L["Apply this filter if a buff has remaining time greater than this. Set to zero to disable."] = true
+L["Apply this filter if a buff has remaining time less than this. Set to zero to disable."] = true
+L["Apply this filter if a debuff has remaining time greater than this. Set to zero to disable."] = true
+L["Apply this filter if a debuff has remaining time less than this. Set to zero to disable."] = true
+L["Are you sure you want to reset ActionBars settings?"] = true
+L["Are you sure you want to reset Auras settings?"] = true
+L["Are you sure you want to reset Bags settings?"] = true
+L["Are you sure you want to reset Chat settings?"] = true
+L["Are you sure you want to reset Cooldown settings?"] = true
+L["Are you sure you want to reset DataBars settings?"] = true
+L["Are you sure you want to reset DataTexts settings?"] = true
+L["Are you sure you want to reset General settings?"] = true
+L["Are you sure you want to reset NamePlates settings?"] = true
+L["Are you sure you want to reset Tooltip settings?"] = true
+L["Are you sure you want to reset UnitFrames settings?"] = true
+L["Arena Frame"] = true
+L["Arena Registrar"] = true
+L["Arena"] = true
+L["Ascending or Descending order."] = true
+L["Ascending"] = true
+L["Assist Target"] = true
+L["Assist"] = true
+L["At what point should the text be displayed. Set to -1 to disable."] = true
+L["Attach Text To"] = true
+L["Attach To"] = true
+L["Attempt to create URL links inside the chat."] = true
+L["Attempt to lock the left and right chat frame positions. Disabling this option will allow you to move the main chat frame anywhere you wish."] = true
+L["Attempt to support eyefinity/nvidia surround."] = true
+L["Aura Bars"] = true
+L["Aura Filters"] = true
+L["Auto Greed/DE"] = true
+L["Auto Hide"] = true
+L["Auto Repair"] = true
+L["Auto-Hide"] = true
+L["Automatic"] = true
+L["Automatically accept invites from guild/friends."] = true
+L["Automatically hide the objetive frame during boss or arena fights."] = true
+L["Automatically repair using the following method when visiting a merchant."] = true
+L["Automatically select greed or disenchant (when available) on green quality items. This will only work if you are the max level."] = true
+L["Automatically vendor gray items when visiting a vendor."] = true
+L["Available Tags"] = true
+L["BG Map"] = true
+L["BG Score"] = true
+L["BINDING_HEADER_RAID_TARGET"] = "Target Markers"
+L["Backdrop Color"] = true
+L["Backdrop Faded Color"] = true
+L["Backdrop Spacing"] = true
+L["Backdrop color of transparent frames"] = true
+L["Backdrop"] = true
+L["Background Glow"] = true
+L["Bad Color"] = true
+L["Bad Scale"] = true
+L["Bad Transition Color"] = true
+L["Bad"] = true
+L["Bag 1"] = true
+L["Bag 2"] = true
+L["Bag 3"] = true
+L["Bag 4"] = true
+L["Bag Sorting"] = true
+L["Bag Spacing"] = true
+L["Bag"] = true
+L["Bag-Bar"] = true
+L["Bags Only"] = true
+L["Bags/Bank"] = true
+L["Bank 1"] = true
+L["Bank 2"] = true
+L["Bank 3"] = true
+L["Bank 4"] = true
+L["Bank 5"] = true
+L["Bank 6"] = true
+L["Bank 7"] = true
+L["Bank Only"] = true
+L["Bar Direction"] = true
+L["Bars will transition smoothly."] = true
+L["Battleground Texts"] = true
+L["Begin a new row or column after this many auras."] = true
+L["Below Chat"] = true
+L["Below"] = true
+L["Blacklist Modifier"] = true
+L["Blacklist"] = true
+L["Blend Mode"] = true
+L["Blend"] = true
+L["BlizzUI Improvements"] = true
+L["Blizzard Style"] = true
+L["Blizzard"] = true
+L["Block Combat Click"] = true
+L["Block Combat Hover"] = true
+L["Block Mouseover Glow"] = true
+L["Block Target Glow"] = true
+L["Blocks all click events while in combat."] = true
+L["Blocks datatext tooltip from showing in combat."] = true
+L["Border Color"] = true
+L["Border Glow"] = true
+L["Border"] = true
+L["Borders"] = true
+L["Both"] = true
+L["Bottom Left"] = true
+L["Bottom Panel"] = true
+L["Bottom Right"] = true
+L["Bottom to Top"] = true
+L["Bottom"] = true
+L["BottomLeftMiniPanel"] = "Minimap BottomLeft (Inside)"
+L["BottomMiniPanel"] = "Minimap Bottom (Inside)"
+L["BottomRightMiniPanel"] = "Minimap BottomRight (Inside)"
+L["Buff Indicator"] = true
+L["Button Size (Bag)"] = true
+L["Button Size (Bank)"] = true
+L["Button Size"] = true
+L["Button Spacing"] = true
+L["Buttons Per Row"] = true
+L["Buttons"] = true
+L["By Type"] = true
+L["Calendar Frame"] = true
+L["Cast Bar"] = true
+L["Cast Color"] = true
+L["Cast No Interrupt Color"] = true
+L["Cast Time Format"] = true
+L["Castbar"] = true
+L["Casting"] = true
+L["Center"] = true
+L["Change settings for the display of the location text that is on the minimap."] = true
+L["Change the alpha level of the frame."] = true
+L["Change the width and controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Channel Alerts"] = true
+L["Channel Time Format"] = true
+L["Character Frame"] = true
+L["Chat Bubble Names"] = true
+L["Chat Bubbles Style"] = true
+L["Chat Bubbles"] = true
+L["Chat EditBox Position"] = true
+L["Chat Output"] = true
+L["Check these to only have the filter active in certain difficulties. If none are checked, it is active in all difficulties."] = true
+L["CheckBox Skin"] = true
+L["Choose Export Format"] = true
+L["Choose UIPARENT to prevent it from hiding with the unitframe."] = true
+L["Choose What To Export"] = true
+L["Choose when you want the tooltip to show in combat. If a modifer is chosen, then you need to hold that down to show the tooltip."] = true
+L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."] = true
+L["Class Backdrop"] = true
+L["Class Castbars"] = true
+L["Class Color Mentions"] = true
+L["Class Color Override"] = true
+L["Class Health"] = true
+L["Class Power"] = true
+L["Class Resources"] = true
+L["Class Totems"] = true
+L["Clear Filter"] = true
+L["Clear Search On Close"] = true
+L["Click Through"] = true
+L["Clickable Height"] = true
+L["Clickable Size"] = true
+L["Clickable Width / Width"] = true
+L["Coding:"] = true
+L["Color Keybind Text when Out of Range, instead of the button."] = true
+L["Color Keybind Text"] = true
+L["Color Override"] = true
+L["Color Turtle Buffs"] = true
+L["Color all buffs that reduce the unit's incoming damage."] = true
+L["Color aurabar debuffs by type."] = true
+L["Color by Value"] = true
+L["Color castbars by the class of player units."] = true
+L["Color castbars by the reaction type of non-player units."] = true
+L["Color health by amount remaining."] = true
+L["Color health by specific thresholds."] = true
+L["Color health by classcolor or reaction."] = true
+L["Color health by threat status."] = true
+L["Color of the actionbutton when not usable."] = true
+L["Color of the actionbutton when out of power (Mana, Rage)."] = true
+L["Color of the actionbutton when out of range."] = true
+L["Color of the actionbutton when usable."] = true
+L["Color power by classcolor or reaction."] = true
+L["Color power by threat status."] = true
+L["Color some texts use."] = true
+L["Color the health backdrop by class or reaction."] = true
+L["Color the unit healthbar if there is a debuff that can be dispelled by you."] = true
+L["Color when the text is about to expire"] = true
+L["Color when the text is in the days format."] = true
+L["Color when the text is in the hours format."] = true
+L["Color when the text is in the minutes format."] = true
+L["Color when the text is in the seconds format."] = true
+L["Colored Icon"] = true
+L["Coloring (Specific)"] = true
+L["Coloring"] = true
+L["Colorize Selected Text"] = true
+L["Colors the border according to the Quality of the Item."] = true
+L["Combat Icon"] = true
+L["Combat Override Key"] = true
+L["CombatText Font"] = true
+L["Combo Point"] = true
+L["Comparison Font Size"] = true
+L["Condensed"] = true
+L["Configure Auras"] = true
+L["Control enemy nameplates toggling on or off when in combat."] = true
+L["Control friendly nameplates toggling on or off when in combat."] = true
+L["Controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Controls the amount of decimals used in values displayed on elements like NamePlates and UnitFrames."] = true
+L["Controls the speed at which smoothed bars will be updated."] = true
+L["Controls how many seconds of inactivity has to pass before chat is faded."] = true
+L["Cooldown Orientation"] = true
+L["Cooldown Text"] = true
+L["Cooldowns"] = true
+L["Copy From"] = true
+L["Copy Settings From"] = true
+L["Copy settings from another unit."] = true
+L["Core |cff1784d1E|r|cffe5e3e3lvUI|r options."] = true
+L["Count Font Size"] = true
+L["Count xOffset"] = true
+L["Count yOffset"] = true
+L["Create Custom Text"] = true
+L["Create Filter"] = true
+L["Create a filter, once created a filter can be set inside the buffs/debuffs section of each unit."] = true
+L["Credits"] = true
+L["Crop Icons"] = true
+L["Currency Format"] = true
+L["Current - Max | Percent"] = true
+L["Current - Max"] = true
+L["Current - Percent (Remaining)"] = true
+L["Current - Percent"] = true
+L["Current - Remaining"] = true
+L["Current / Max"] = true
+L["Current Level"] = true
+L["Current"] = true
+L["Curse Effect"] = true
+L["Cursor Anchor Offset X"] = true
+L["Cursor Anchor Offset Y"] = true
+L["Cursor Anchor Type"] = true
+L["Cursor Anchor"] = true
+L["Custom Backdrop"] = true
+L["Custom Color"] = true
+L["Custom Dead Backdrop"] = true
+L["Custom Faction Colors"] = true
+L["Custom Texts"] = true
+L["Custom Texture"] = true
+L["Custom Timestamp Color"] = true
+L["Cutaway Bars"] = true
+L["Darken Inactive"] = true
+L["DataBars"] = true
+L["DataTexts"] = true
+L["Datatext Panel (Left)"] = true
+L["Datatext Panel (Right)"] = true
+L["Date Format"] = true
+L["Days"] = true
+L["Debuff Highlighting"] = true
+L["Debug Tools"] = true
+L["Decimal Length"] = true
+L["Decimal Threshold"] = true
+L["Decode Text"] = true
+L["Default Color"] = true
+L["Default Font"] = true
+L["Default Settings"] = true
+L["Deficit"] = true
+L["Defines how the group is sorted."] = true
+L["Defines the sort order of the selected sort method."] = true
+L["Delete Filter"] = true
+L["Delete a created filter, you cannot delete pre-existing filters, only custom ones."] = true
+L["Desaturate Cooldowns"] = true
+L["Desaturate Junk Items"] = true
+L["Desaturated Icon"] = true
+L["Descending"] = true
+L["Detach From Frame"] = true
+L["Detached Width"] = true
+L["Direction the bag sorting will use to allocate the items."] = true
+L["Direction the bar moves on gains/losses"] = true
+L["Direction the health bar moves when gaining/losing health."] = true
+L["Disable Bag Sort"] = true
+L["Disable Bank Sort"] = true
+L["Disable Debuff Highlight"] = true
+L["Disabled Blizzard Frames"] = true
+L["Disabled Blizzard"] = true
+L["Disables the focus and target of focus unitframes."] = true
+L["Disables the player and pet unitframes."] = true
+L["Disables the target and target of target unitframes."] = true
+L["Disconnected"] = true
+L["Disease Effect"] = true
+L["Display Frames"] = true
+L["Display Item Level"] = true
+L["Display Player"] = true
+L["Display Target"] = true
+L["Display Text"] = true
+L["Display a healer icon over known healers inside battlegrounds or arenas."] = true
+L["Display a panel across the bottom of the screen. This is for cosmetic only."] = true
+L["Display a panel across the top of the screen. This is for cosmetic only."] = true
+L["Display a spark texture at the end of the castbar statusbar to help show the differance between castbar and backdrop."] = true
+L["Display an exclamation mark on items that starts a quest."] = true
+L["Display battleground messages in the middle of the screen."] = true
+L["Display bind names on action buttons."] = true
+L["Display cooldown text on anything with the cooldown spiral."] = true
+L["Display data panels below the chat, used for datatexts."] = true
+L["Display emotion icons in chat."] = true
+L["Display guild ranks if a unit is guilded."] = true
+L["Display how many of a certain item you have in your possession."] = true
+L["Display macro names on action buttons."] = true
+L["Display minimap panels below the minimap, used for datatexts."] = true
+L["Display player titles."] = true
+L["Display reminder bar on the minimap."] = true
+L["Display the castbar icon inside the castbar."] = true
+L["Display the castbar inside the information panel, the icon will be displayed outside the main unitframe."] = true
+L["Display the hyperlink tooltip while hovering over a hyperlink."] = true
+L["Display the junk icon on all grey items that can be vendored."] = true
+L["Display the name of the unit on the chat bubble."] = true
+L["Display the npc ID when mousing over a npc tooltip."] = true
+L["Display the spell or item ID when mousing over a spell or item tooltip."] = true
+L["Display the target of your current cast. Useful for mouseover casts."] = true
+L["Display tick marks on the castbar for channelled spells. This will adjust automatically for spells like Drain Soul and add additional ticks based on haste."] = true
+L["Display Types"] = true
+L["Displayed server time."] = true
+L["Displays a detailed report of every item sold when enabled."] = true
+L["Displays item level on equippable items."] = true
+L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."] = true
+L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."] = true
+L["Donations:"] = true
+L["Down"] = true
+L["Dropdown CheckBox Skin"] = true
+L["Dungeon & Raid Filter"] = true
+L["Duration Enable"] = true
+L["Duration Font Size"] = true
+L["Duration Reverse"] = true
+L["Duration Text"] = true
+L["Duration"] = true
+L["Editbox History Size"] = true
+L["ELVUI_CREDITS"] = "I would like to give out a special shout out to the following people for helping me maintain this addon with testing, coding, and people who also have helped me through donations. Please note for donations; I'm only posting the names of people who messaged me on the forums, if your name is missing and you wish to have your name added please message me."
+L["ENEMY_NPC"] = "Enemy NPC"
+L["ENEMY_PLAYER"] = "Enemy Player"
+L["Elite Icon"] = true
+L["Emotion Icons"] = true
+L["Enable Custom Color"] = true
+L["Enable the use of separate size options for the right chat panel."] = true
+L["Enable/Disable the Bag-Bar."] = true
+L["Enable/Disable the all-in-one bag."] = true
+L["Enable/Disable the loot frame."] = true
+L["Enable/Disable the loot roll frame."] = true
+L["Enable/Disable the minimap. |cffFF0000Warning: This will prevent you from seeing the consolidated buffs bar, and prevent you from seeing the minimap datatexts.|r"] = true
+L["Enable/Disable the scaling of targetted nameplates."] = true
+L["Enables the ElvUI Raid Control panel."] = true
+L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."] = true
+L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."] = true
+L["Enabling this will check your health amount."] = true
+L["Enabling this will check your power amount."] = true
+L["Enchanting"] = true
+L["Enemy Aura Type"] = true
+L["Enemy Combat Toggle"] = true
+L["Enemy NPC Frames"] = true
+L["Enemy Player Frames"] = true
+L["Enemy"] = true
+L["Engineering"] = true
+L["Enhanced PVP Messages"] = true
+L["Equipped Item Color"] = true
+L["Equipped Item"] = true
+L["Error decoding data. Import string may be corrupted!"] = true
+L["Error exporting profile!"] = true
+L["Exclude Name"] = true
+L["Excluded Names"] = true
+L["Excluded names will not be class colored."] = true
+L["Expiring"] = true
+L["Export Profile"] = true
+L["Exported"] = true
+L["FRIENDLY_NPC"] = "Friendly NPC"
+L["FRIENDLY_PLAYER"] = "Friendly Player"
+L["Fade Chat Toggles"] = true
+L["Fade Out Delay"] = true
+L["Fade Out"] = true
+L["Fade Tabs No Backdrop"] = true
+L["Fade the chat text when there is no activity."] = true
+L["Fade Threshold"] = true
+L["Fade Undocked Tabs"] = true
+L["Fade the chat text when there is no activity."] = true
+L["Fader"] = true
+L["Fades the buttons that toggle chat windows when that window has been toggled off."] = true
+L["Fades the text on chat tabs that are docked in a panel where the backdrop is disabled."] = true
+L["Fades the text on chat tabs that are not docked at the left or right chat panel."] = true
+L["Fill"] = true
+L["Filled"] = true
+L["Filter Priority"] = true
+L["Filter Search"] = true
+L["Filter Type"] = true
+L["Filter already exists!"] = true
+L["Filters Page"] = true
+L["Filters are not allowed to have commas in their name. Stripping commas from filter name."] = true
+L["Flash"] = true
+L["Fluid Position Buffs on Debuffs"] = true
+L["Fluid Position Debuffs on Buffs"] = true
+L["Flyout Direction"] = true
+L["Flyout Spacing"] = true
+L["Focus"] = true
+L["FocusTarget"] = true
+L["Font Outline"] = true
+L["Font"] = true
+L["Fonts"] = true
+L["Force Off"] = true
+L["Force On"] = true
+L["Force Reaction Color"] = true
+L["Force the frames to show, they will act as if they are the player frame."] = true
+L["Forces Debuff Highlight to be disabled for these frames"] = true
+L["Forces Mouseover Glow to be disabled for these frames"] = true
+L["Forces Target Glow to be disabled for these frames"] = true
+L["Forces reaction color instead of class color on units controlled by players."] = true
+L["Format"] = true
+L["Frame Glow"] = true
+L["Frame Level"] = true
+L["Frame Orientation"] = true
+L["Frame Strata"] = true
+L["Frequent Updates"] = true
+L["Friendly Aura Type"] = true
+L["Friendly Combat Toggle"] = true
+L["Friendly NPC Frames"] = true
+L["Friendly Player Frames"] = true
+L["Friendly"] = true
+L["Full Overlay"] = true
+L["Full"] = true
+L["GM Chat"] = true
+L["GPS Arrow"] = true
+L["Gems"] = true
+L["General Options"] = true
+L["Global (Account Settings)"] = true
+L["Global Fade Transparency"] = true
+L["Global"] = true
+L["Glow"] = true
+L["Gold Format"] = true
+L["Good Color"] = true
+L["Good Scale"] = true
+L["Good Transition Color"] = true
+L["Good"] = true
+L["Gossip Frame"] = true
+L["Group By"] = true
+L["Group Spacing"] = true
+L["Grouping & Sorting"] = true
+L["Groups Per Row/Column"] = true
+L["Growth Direction"] = true
+L["Growth X-Direction"] = true
+L["Growth Y-Direction"] = true
+L["Growth direction from the first unitframe."] = true
+L["Guide:"] = true
+L["Guild Ranks"] = true
+L["Guild Registrar"] = true
+L["HH:MM Threshold"] = true
+L["HH:MM"] = true
+L["Header Font Size"] = true
+L["Heal Prediction"] = true
+L["Healer Icon"] = true
+L["Health Backdrop Multiplier"] = true
+L["Health Backdrop"] = true
+L["Health Bar"] = true
+L["Health Border"] = true
+L["Health By Value"] = true
+L["Health By Threshold"] = true
+L["Health Color"] = true
+L["Health Length"] = true
+L["Health Threshold"] = true
+L["Health"] = true
+L["Height Multiplier"] = true
+L["Height of the objective tracker. Increase size to be able to see more objectives."] = true
+L["Height"] = true
+L["Help Frame"] = true
+L["Herbalism"] = true
+L["Here you can add items or search terms that you want to be excluded from sorting. To remove an item just click on its name in the list."] = true
+L["Hide At Max Level"] = true
+L["Hide Both"] = true
+L["Hide Error Text"] = true
+L["Hide Frame"] = true
+L["Hide In Combat"] = true
+L["Hide In Vehicle"] = true
+L["Hide Spell Name"] = true
+L["Hide Time"] = true
+L["Hide specific sections in the datatext tooltip."] = true
+L["Hide tooltip while in combat."] = true
+L["Hides the red error text at the top of the screen while in combat."] = true
+L["History Size"] = true
+L["History"] = true
+L["Horizontal Spacing"] = true
+L["Horizontal"] = true
+L["Hours"] = true
+L["Hover Highlight"] = true
+L["Hover"] = true
+L["How long the cutaway health will take to fade out."] = true
+L["How long the cutaway power will take to fade out."] = true
+L["How many seconds the castbar should stay visible after the cast failed or was interrupted."] = true
+L["How much time before the cutaway health starts to fade."] = true
+L["How much time before the cutaway power starts to fade."] = true
+L["Hyperlink Hover"] = true
+L["Icon Frame"] = true
+L["Icon Inside Castbar"] = true
+L["Icon Only"] = true
+L["Icon Position"] = true
+L["Icon Size"] = true
+L["Icon"] = true
+L["Icon: BOTTOM"] = true
+L["Icon: BOTTOMLEFT"] = true
+L["Icon: BOTTOMRIGHT"] = true
+L["Icon: LEFT"] = true
+L["Icon: RIGHT"] = true
+L["Icon: TOP"] = true
+L["Icon: TOPLEFT"] = true
+L["Icon: TOPRIGHT"] = true
+L["Icons and Text (Short)"] = true
+L["Icons and Text"] = true
+L["If enabled then it checks if auras are missing instead of being present on the unit."] = true
+L["If enabled then it will require all auras to activate the filter. Otherwise it will only require any one of the auras to activate it."] = true
+L["If enabled then it will require all cooldowns to activate the filter. Otherwise it will only require any one of the cooldowns to activate it."] = true
+L["If enabled then the filter will activate if the unit is casting anything."] = true
+L["If enabled then the filter will activate if the unit is channeling anything."] = true
+L["If enabled then the filter will activate if the unit is not casting anything."] = true
+L["If enabled then the filter will activate if the unit is not channeling anything."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or higher than this value."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or lower than this value."] = true
+L["If enabled then the filter will only activate if the level of the unit matches this value."] = true
+L["If enabled then the filter will only activate if the level of the unit matches your own."] = true
+L["If enabled then the filter will only activate if the unit is casting interruptible spells."] = true
+L["If enabled then the filter will only activate if the unit is casting not interruptible spells."] = true
+L["If enabled then the filter will only activate if the unit is not casting or channeling one of the selected spells."] = true
+L["If enabled then the filter will only activate when you are in combat."] = true
+L["If enabled then the filter will only activate when you are not targeting the unit."] = true
+L["If enabled then the filter will only activate when you are out of combat."] = true
+L["If enabled then the filter will only activate when you are targeting the unit."] = true
+L["If enabled then the filter will only activate when you have a target."] = true
+L["If not set to 0 then override the size of the aura icon to this."] = true
+L["If the aura is listed with a number then you need to use that to remove it from the list."] = true
+L["If this list is empty, and if 'Interruptible' is checked, then the filter will activate on any type of cast that can be interrupted."] = true
+L["If this threshold is used then the health of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the health of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the power of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the power of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If you have a lot of 3D Portraits active then it will likely have a big impact on your FPS. Disable some portraits if you experience FPS issues."] = true
+L["If you have any plugins supporting this feature installed you can find them in the selection dropdown to the right."] = true
+L["If you unlock actionbars then trying to move a spell might instantly cast it if you cast spells on key press instead of key release."] = true
+L["Ignore UI Scale Popup"] = true
+L["Ignore mouse events."] = true
+L["Ignored Items and Search Syntax (Global)"] = true
+L["Ignored Items and Search Syntax (Profile)"] = true
+L["Import Profile"] = true
+L["Importing"] = true
+L["Inactivity Timer"] = true
+L["Index"] = true
+L["Indicate whether buffs you cast yourself should be separated before or after."] = true
+L["InfoPanel Border"] = true
+L["Information Panel"] = true
+L["Inherit Global Fade"] = true
+L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."] = true
+L["Inset"] = true
+L["Inside Information Panel"] = true
+L["Install"] = true
+L["Instance Difficulty"] = true
+L["Instance Type"] = true
+L["Interruptable"] = true
+L["Interruptible"] = true
+L["Invert Colors"] = true
+L["Invert Grouping Order"] = true
+L["Invert foreground and background colors."] = true
+L["Is Casting Anything"] = true
+L["Is Channeling Anything"] = true
+L["Is Targeted"] = true
+L["Item Count Font"] = true
+L["Item Count"] = true
+L["Item Level Threshold"] = true
+L["Item Level"] = true
+L["JustifyH"] = true
+L["Key Down"] = true
+L["Keybind Mode"] = true
+L["Keybind Text Position"] = true
+L["Keybind Text X-Offset"] = true
+L["Keybind Text Y-Offset"] = true
+L["Keybind Text"] = true
+L["Keyword Alert"] = true
+L["Keywords"] = true
+L["LBF Support"] = true
+L["LEVEL_BOSS"] = "Set level to -1 for boss units or set to 0 to disable."
+L["LFD Frame"] = true
+L["LFG Queue"] = true
+L["LFR Frame"] = true
+L["Latency"] = true
+L["Leatherworking"] = true
+L["Left Only"] = true
+L["Left to Right"] = true
+L["Left"] = true
+L["Limit the number of rows or columns."] = true
+L["List of words to color in chat if found in a message. If you wish to add multiple words you must seperate the word with a comma. To search for your current name you can use %MYNAME%.\n\nExample:\n%MYNAME%, ElvUI, RBGs, Tank"] = true
+L["Location Text"] = true
+L["Lock Positions"] = true
+L["Log Taints"] = true
+L["Log the main chat frames history. So when you reloadui or log in and out you see the history from your last session."] = true
+L["Login Message"] = true
+L["Loot Frames"] = true
+L["Loot Roll"] = true
+L["Losing Threat"] = true
+L["Low Health Threshold"] = true
+L["Low Threat"] = true
+L["Low Threshold"] = true
+L["Lower numbers mean a higher priority. Filters are processed in order from 1 to 100."] = true
+L["MM:SS Threshold"] = true
+L["MM:SS"] = true
+L["Macro Text"] = true
+L["Magic Effect"] = true
+L["Main Tanks / Main Assist"] = true
+L["Main backdrop color of the UI."] = true
+L["Main border color of the UI."] = true
+L["Main statusbar texture."] = true
+L["Make textures transparent."] = true
+L["Make the unitframe glow yellow when it is below this percent of health, it will glow red when the health value is half of this value."] = true
+L["Make the world map smaller."] = true
+L["Map Opacity When Moving"] = true
+L["Max Lines"] = true
+L["Maps"] = true
+L["Match Frame Width"] = true
+L["Match Player Level"] = true
+L["Max Alpha"] = true
+L["Max Bars"] = true
+L["Max Overflow"] = true
+L["Max Wraps"] = true
+L["Max amount of overflow allowed to extend past the end of the health bar."] = true
+L["Maximum Duration"] = true
+L["Maximum Level"] = true
+L["Maximum Time Left"] = true
+L["Media"] = true
+L["Method to sort by."] = true
+L["Middle Click - Set Focus"] = true
+L["Middle clicking the unit frame will cause your focus to match the unit."] = true
+L["Middle"] = true
+L["Min Alpha"] = true
+L["Minimap Mouseover"] = true
+L["Minimap Panels"] = true
+L["Minimum Duration"] = true
+L["Minimum Level"] = true
+L["Minimum Time Left"] = true
+L["Mining"] = true
+L["Minutes"] = true
+L["Mirror Timers"] = true
+L["Misc Frames"] = true
+L["Missing"] = true
+L["Modulating Blend"] = true
+L["Module Control"] = true
+L["Module Copy"] = true
+L["Module Reset"] = true
+L["Money Format"] = true
+L["Mouse Over"] = true
+L["Mouseover Glow"] = true
+L["Mouseover Highlight"] = true
+L["Mouseover"] = true
+L["Multi-Monitor Support"] = true
+L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."] = true
+L["NPC IDs"] = true
+L["Name Color"] = true
+L["Name Colored Glow"] = true
+L["Name Font"] = true
+L["Name Only"] = true
+L["Name"] = true
+L["NamePlate Style Filters"] = true
+L["NamePlates"] = true
+L["Nameplate"] = true
+L["Neutral"] = true
+L["Never Hide"] = true
+L["No Alert In Combat"] = true
+L["No Duration"] = true
+L["No Sorting"] = true
+L["Non-Interruptable"] = true
+L["Non-Target Alpha"] = true
+L["Not Casting Anything"] = true
+L["Not Channeling Anything"] = true
+L["Not Spell"] = true
+L["Not Targeted"] = true
+L["Not Usable"] = true
+L["Not valid spell id"] = true
+L["Num Rows"] = true
+L["Number of Groups"] = true
+L["Number of messages you scroll for each step."] = true
+L["Number of repeat characters while in combat before the chat editbox is automatically closed. Set to 0 to disable."] = true
+L["Number of time in seconds to scroll down to the bottom of the chat window if you are not scrolled down completely."] = true
+L["Objective Frame Height"] = true
+L["Off Cooldown"] = true
+L["Offset of the powerbar to the healthbar, set to 0 to disable."] = true
+L["Offset position for text."] = true
+L["Offset"] = true
+L["On Cooldown"] = true
+L["Only Match SpellID"] = true
+L["Only show when the unit is not in range."] = true
+L["Only show when you are mousing over a frame."] = true
+L["Other Filter"] = true
+L["Other's First"] = true
+L["Others"] = true
+L["Out of Power"] = true
+L["Out of Range"] = true
+L["Over Health Threshold"] = true
+L["Over Power Threshold"] = true
+L["Overlay Alpha"] = true
+L["Overlay"] = true
+L["Overnuking"] = true
+L["Override any custom visibility setting in certain situations, EX: Only show groups 1 and 2 inside a 10 man instance."] = true
+L["Override the default class color setting."] = true
+L["Owners Name"] = true
+L["PVP Trinket"] = true
+L["Panel Backdrop"] = true
+L["Panel Height"] = true
+L["Panel Texture (Left)"] = true
+L["Panel Texture (Right)"] = true
+L["Panel Transparency"] = true
+L["Panel Width (Bags)"] = true
+L["Panel Width (Bank)"] = true
+L["Panel Width"] = true
+L["Panels"] = true
+L["Parent"] = true
+L["Party / Raid"] = true
+L["Party Only"] = true
+L["Party Pets"] = true
+L["Party Targets"] = true
+L["Per Row"] = true
+L["Percent"] = true
+L["Personal"] = true
+L["Pet Name"] = true
+L["Pet"] = true
+L["PetTarget"] = true
+L["Petition Frame"] = true
+L["Pick Up Action Key"] = true
+L["Player Frame Aura Bars"] = true
+L["Player Health"] = true
+L["Player Out of Combat"] = true
+L["Player Target"] = true
+L["Player Titles"] = true
+L["Player in Combat"] = true
+L["Player"] = true
+L["Plugin"] = true
+L["Poison Effect"] = true
+L["Portrait"] = true
+L["Position Buffs on Debuffs"] = true
+L["Position Debuffs on Buffs"] = true
+L["Position of the Chat EditBox, if datatexts are disabled this will be forced to be above chat."] = true
+L["Position"] = true
+L["Power Threshold"] = true
+L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."] = true
+L["Power"] = true
+L["Energy"] = true
+L["Rage"] = true
+L["Powers"] = true
+L["Prevent the same messages from displaying in chat more than once within this set amount of seconds, set to zero to disable."] = true
+L["Primary Texture"] = true
+L["Priority"] = true
+L["Private (Character Settings)"] = true
+L["Profession Bags"] = true
+L["Profile Name"] = true
+L["Profile Specific"] = true
+L["Profile imported successfully!"] = true
+L["Profile"] = true
+L["Progress Bar"] = true
+L["Puts coordinates on the world map."] = true
+L["PvP Frames"] = true
+L["PvP Icon"] = true
+L["PvP Queue"] = true
+L["PvP Text"] = true
+L["Quest Frames"] = true
+L["Quest Starter"] = true
+L["Quiver"] = true
+L["RAID_CONTROL"] = "Raid Control"
+L["RL / ML Icons"] = true
+L["Raid Difficulty"] = true
+L["Raid Frame"] = true
+L["Raid Icon"] = true
+L["Raid Only"] = true
+L["Raid Pet"] = true
+L["Raid-40"] = true
+L["Raid-Wide Sorting"] = true
+L["RaidDebuff Indicator"] = true
+L["Range"] = true
+L["Rapidly update the health, uses more memory and cpu. Only recommended for healing."] = true
+L["Reaction Castbars"] = true
+L["Reaction Colors"] = true
+L["Reaction Type"] = true
+L["Reactions"] = true
+L["Ready Check Icon"] = true
+L["Realm Time"] = true
+L["Remaining / Max"] = true
+L["Remaining Time"] = true
+L["Remaining"] = true
+L["Reminder"] = true
+L["Remove Backdrop"] = true
+L["Remove Name"] = true
+L["Remove Spell ID or Name"] = true
+L["Remove Spell"] = true
+L["Remove SpellID"] = true
+L["Remove a Name from the list."] = true
+L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."] = true
+L["Remove a spell from the filter."] = true
+L["Replace Blizzard Fonts"] = true
+L["Replaces the default Blizzard fonts on various panels and frames with the fonts chosen in the Media section of the ElvUI Options. NOTE: Any font that inherits from the fonts ElvUI usually replaces will be affected as well if you disable this. Enabled by default."] = true
+L["Reposition Window"] = true
+L["Require All"] = true
+L["Require Target"] = true
+L["Require holding the Alt key down to move cursor or cycle through messages in the editbox."] = true
+L["Reset Anchors"] = true
+L["Reset Aura Filters"] = true
+L["Reset Editbox History"] = true
+L["Reset Filter"] = true
+L["Reset History"] = true
+L["Reset Priority"] = true
+L["Reset Zoom"] = true
+L["Reset all frames to their original positions."] = true
+L["Reset filter priority to the default state."] = true
+L["Reset the size and position of this frame."] = true
+L["Rest Icon"] = true
+L["Restore Bar"] = true
+L["Restore Defaults"] = true
+L["Restore the actionbars default settings"] = true
+L["Resurrect Icon"] = true
+L["Return filter to its default state."] = true
+L["Reverse Bag Slots"] = true
+L["Reverse Cooldown"] = true
+L["Reverse Style"] = true
+L["Reverse Toggle will enable Cooldown Text on this module when the global setting is disabled and disable them when the global setting is enabled."] = true
+L["Reverse Toggle"] = true
+L["Right Only"] = true
+L["Right Panel Height"] = true
+L["Right Panel Width"] = true
+L["Right to Left"] = true
+L["Right"] = true
+L["RightClick Self-Cast"] = true
+L["Role Icon"] = true
+L["Run the installation process."] = true
+L["Sanctuary"] = true
+L["Scale of the nameplate that is targetted."] = true
+L["Scale"] = true
+L["Scroll Interval"] = true
+L["Scroll Messages"] = true
+L["Search Syntax"] = true
+L["Search for a spell name inside of a filter."] = true
+L["Secondary Texture"] = true
+L["Seconds remaining on the aura duration before the bar starts moving. Set to 0 to disable."] = true
+L["Seconds"] = true
+L["Selected Text Color"] = true
+L["Selector Color"] = true
+L["Selector Style"] = true
+L["Securely Tanking"] = true
+L["Select Filter"] = true
+L["Select Spell"] = true
+L["Select a profile to copy from/to."] = true
+L["Select a unit to copy settings from."] = true
+L["Select the display method of the portrait."] = true
+L["Sell Interval"] = true
+L["Send ADDON_ACTION_BLOCKED errors to the Lua Error frame. These errors are less important in most cases and will not effect your game performance. Also a lot of these errors cannot be fixed. Please only report these errors if you notice a Defect in gameplay."] = true
+L["Sends your current profile to your target."] = true
+L["Sends your filter settings to your target."] = true
+L["Separate Panel Sizes"] = true
+L["Seperate"] = true
+L["Set Settings to Default"] = true
+L["Set the alpha level of portrait when frame is overlayed."] = true
+L["Set the filter type. Blacklist will hide any auras in the list and show all others. Whitelist will show any auras in the filter and hide all others."] = true
+L["Set the font outline."] = true
+L["Set the font size for everything in UI. Note: This doesn't effect somethings that have their own seperate options (UnitFrame Font, Datatext Font, ect..)"] = true
+L["Set the font size for unitframes."] = true
+L["Set the order that the group will sort."] = true
+L["Set the orientation of the UnitFrame."] = true
+L["Set the priority order of the spell, please note that prioritys are only used for the raid debuff module, not the standard buff/debuff module. If you want to disable set to zero."] = true
+L["Set the size of the individual auras."] = true
+L["Set the size of your bag buttons."] = true
+L["Set the type of auras to show when a unit is a foe."] = true
+L["Set the type of auras to show when a unit is friendly."] = true
+L["Set to either stack nameplates vertically or allow them to overlap."] = true
+L["Sets the font instance's horizontal text alignment style."] = true
+L["Share Current Profile"] = true
+L["Share Filters"] = true
+L["Short (Whole Numbers)"] = true
+L["Short Channels"] = true
+L["Shortcut to 'Filters' section of the config."] = true
+L["Shortcut to global filters."] = true
+L["Shortcuts"] = true
+L["Shorten the channel names in chat."] = true
+L["Should tooltip be anchored to mouse cursor"] = true
+L["Show Aura From Other Players"] = true
+L["Show Auras"] = true
+L["Show Bind on Equip/Use Text"] = true
+L["Show Both"] = true
+L["Show Coins"] = true
+L["Show Dispellable Debuffs"] = true
+L["Show Empty Buttons"] = true
+L["Show For DPS"] = true
+L["Show For Healers"] = true
+L["Show For Tanks"] = true
+L["Show Icon"] = true
+L["Show Junk Icon"] = true
+L["Show Quality Color"] = true
+L["Show Quest Icon"] = true
+L["Show When Not Active"] = true
+L["Show an incoming heal prediction bar on the unitframe. Also display a slightly different colored bar for incoming overheals."] = true
+L["Show the castbar icon desaturated if a spell is not interruptible."] = true
+L["Show/Hide Test Frame"] = true
+L["Side Arrows"] = true
+L["Size Override"] = true
+L["Size and Positions"] = true
+L["Size of the indicator icon."] = true
+L["Size"] = true
+L["Skin Backdrop (No Borders)"] = true
+L["Skin Backdrop"] = true
+L["Skin the blizzard chat bubbles."] = true
+L["Skins"] = true
+L["Slight Gradient"] = true
+L["Small Panels"] = true
+L["Smaller World Map"] = true
+L["Smart Aura Position"] = true
+L["Smart Raid Filter"] = true
+L["Smart"] = true
+L["Smooth Bars"] = true
+L["Smooth"] = true
+L["Smoothing Amount"] = true
+L["Socket Frame"] = true
+L["Sort By"] = true
+L["Sort Direction"] = true
+L["Sort Inverted"] = true
+L["Sort Method"] = true
+L["Soul Bag"] = true
+L["Spaced"] = true
+L["Spacing"] = true
+L["Spam Interval"] = true
+L["Spark"] = true
+L["Spell/Item IDs"] = true
+L["Split"] = true
+L["Stable"] = true
+L["Stack Counter"] = true
+L["Stack Text Position"] = true
+L["Stack Text X-Offset"] = true
+L["Stack Text Y-Offset"] = true
+L["Stack Threshold"] = true
+L["Start Near Center"] = true
+L["StatusBar Texture"] = true
+L["Statusbar Fill Orientation"] = true
+L["Statusbar"] = true
+L["Sticky Chat"] = true
+L["Strata and Level"] = true
+L["Style Filter"] = true
+L["Style"] = true
+L["Tab Font Outline"] = true
+L["Tab Font Size"] = true
+L["Tab Font"] = true
+L["Tab Panel Transparency"] = true
+L["Tab Panel"] = true
+L["Tab Selector"] = true
+L["Tabard Frame"] = true
+L["Table"] = true
+L["Tank Target"] = true
+L["Tank"] = true
+L["Tapped"] = true
+L["Target Indicator Color"] = true
+L["Target Info"] = true
+L["Target On Mouse-Down"] = true
+L["Target Scale"] = true
+L["Target units on mouse down rather than mouse up. \n\n|cffFF0000Warning: If you are using the addon 'Clique' you may have to adjust your clique settings when changing this."] = true
+L["Target/Low Health Indicator"] = true
+L["TargetTarget"] = true
+L["TargetTargetTarget"] = true
+L["Targeted Glow"] = true
+L["Targeting"] = true
+L["Testing:"] = true
+L["Text Fade"] = true
+L["Text Color"] = true
+L["Text Font Size"] = true
+L["Text Format"] = true
+L["Text Position"] = true
+L["Text Threshold"] = true
+L["Text Toggle On NPC"] = true
+L["Text xOffset"] = true
+L["Text yOffset"] = true
+L["Text"] = true
+L["Texture"] = true
+L["Textured Icon"] = true
+L["Textures"] = true
+L["The Portrait will overlay the Healthbar. This will be automatically happen if the Frame Orientation is set to Middle."] = true
+L["The Thin Border Theme option will change the overall apperance of your UI. Using Thin Border Theme is a slight performance increase over the traditional layout."] = true
+L["The amount of buttons to display per row."] = true
+L["The amount of buttons to display."] = true
+L["The button you must hold down in order to drag an ability to another action button."] = true
+L["The debuff needs to reach this amount of stacks before it is shown. Set to 0 to always show the debuff."] = true
+L["The direction that the bag frames be (Horizontal or Vertical)."] = true
+L["The direction that the bag frames will grow from the anchor."] = true
+L["The direction the auras will grow and then the direction they will grow after they reach the wrap after limit."] = true
+L["The display format of the currency icons that get displayed below the main bag. (You have to be watching a currency for this to display)"] = true
+L["The display format of the money text that is shown at the top of the main bag."] = true
+L["The display format of the money text that is shown in the gold datatext and its tooltip."] = true
+L["The first button anchors itself to this point on the bar."] = true
+L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."] = true
+L["The font that appears on the text above players heads. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = true
+L["The font that combat text will use. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = true
+L["The font that the core of the UI will use."] = true
+L["The font that the unitframes will use."] = true
+L["The frame is not shown unless you mouse over the frame."] = true
+L["The initial group will start near the center and grow out."] = true
+L["The minimum item level required for it to be shown."] = true
+L["The name you have selected is already in use by another element."] = true
+L["The object you want to attach to."] = true
+L["The size of the action buttons."] = true
+L["The size of the individual buttons on the bag frame."] = true
+L["The size of the individual buttons on the bank frame."] = true
+L["The spacing between buttons."] = true
+L["The spacing between the backdrop and the buttons."] = true
+L["The texture that will be used mainly for statusbars."] = true
+L["The unit prefixes you want to use when values are shortened in ElvUI. This is mostly used on UnitFrames."] = true
+L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."] = true
+L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."] = true
+L["Thin Border Theme"] = true
+L["Thin Borders"] = true
+L["This dictates the size of the icon when it is not attached to the castbar."] = true
+L["This feature will allow you to transfer settings to other characters."] = true
+L["This is for Customized Icons in your Interface/Icons folder."] = true
+L["This opens the UnitFrames Color settings. These settings affect all unitframes."] = true
+L["This option allows the overlay to span the whole health, including the background."] = true
+L["This section will allow you to copy settings to a select module from or to a different profile."] = true
+L["This section will help reset specfic settings back to default."] = true
+L["This selects the Chat Frame to use as the output of ElvUI messages."] = true
+L["This setting controls the size of text in item comparison tooltips."] = true
+L["This setting will be updated upon changing stances."] = true
+L["This texture will get used on objects like chat windows and dropdown menus."] = true
+L["This will override the global cooldown settings."] = true
+L["This will prevent the UI Scale Popup from being shown when changing the game window size."] = true
+L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."] = true
+L["Threat Display Mode"] = true
+L["Threat Health"] = true
+L["Threat Power"] = true
+L["Threat"] = true
+L["Threshold (in minutes) before text is shown in the HH:MM format. Set to -1 to never change to this format."] = true
+L["Threshold (in seconds) before text is shown in the MM:SS format. Set to -1 to never change to this format."] = true
+L["Threshold before text goes into decimal form. Set to -1 to disable decimals."] = true
+L["Threshold before text turns red and is in decimal form. Set to -1 for it to never turn red"] = true
+L["Threshold before the icon will fade out and back in. Set to -1 to disable."] = true
+L["Threshold 20"] = true
+L["Threshold 35"] = true
+L["Threshold 50"] = true
+L["Threshold 75"] = true
+L["Ticks"] = true
+L["Time Format"] = true
+L["Time Indicator Colors"] = true
+L["Time Remaining Reverse"] = true
+L["Time Remaining"] = true
+L["Time To Hold"] = true
+L["Time xOffset"] = true
+L["Time yOffset"] = true
+L["Time"] = true
+L["Timestamp Color"] = true
+L["Toggle Anchors"] = true
+L["Toggle Off While In Combat"] = true
+L["Toggle On While In Combat"] = true
+L["Toggle Tutorials"] = true
+L["Toggle showing of the left and right chat panels."] = true
+L["Toggle the chat tab panel backdrop."] = true
+L["Toggles the display of the actionbars backdrop."] = true
+L["Tooltip Font Settings"] = true
+L["Top Arrow"] = true
+L["Top Left"] = true
+L["Top Panel"] = true
+L["Top Right"] = true
+L["Top to Bottom"] = true
+L["Top"] = true
+L["TopLeftMiniPanel"] = "Minimap TopLeft (Inside)"
+L["TopMiniPanel"] = "Minimap Top (Inside)"
+L["TopRightMiniPanel"] = "Minimap TopRight (Inside)"
+L["Totem"] = true
+L["Trainer Frame"] = true
+L["Transparency level when not in combat, no target exists, full health, not casting, and no focus target exists."] = true
+L["Transparent Backdrops"] = true
+L["Transparent Buttons"] = true
+L["Transparent"] = true
+L["Triggers"] = true
+L["Turtle Color"] = true
+L["Tutorial Frame"] = true
+L["URL Links"] = true
+L["Under Health Threshold"] = true
+L["Under Power Threshold"] = true
+L["Uniform Threshold"] = true
+L["Unique Units"] = true
+L["Unit Prefix Style"] = true
+L["Unit Target"] = true
+L["Unit Type"] = true
+L["UnitFrames"] = true
+L["Unlock various elements of the UI to be repositioned."] = true
+L["Up"] = true
+L["Usable"] = true
+L["Use Alt Key"] = true
+L["Use Class Color"] = true
+L["Use Custom Level"] = true
+L["Use Custom Strata"] = true
+L["Use Dead Backdrop"] = true
+L["Use Default"] = true
+L["Use Indicator Color"] = true
+L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."] = true
+L["Use Target Scale"] = true
+L["Use Threat Color"] = true
+L["Use class color for the names of players when they are mentioned."] = true
+L["Use coin icons instead of colored text."] = true
+L["Use drag and drop to rearrange filter priority or right click to remove a filter."] = true
+L["Use the Name Color of the unit for the Name Glow."] = true
+L["Use the custom backdrop color instead of a multiple of the main color."] = true
+L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."] = true
+L["Use thin borders on certain unitframe elements."] = true
+L["Use this backdrop color for units that are dead or ghosts."] = true
+L["Used as RaidDebuff Indicator"] = true
+L["Value Color"] = true
+L["Value must be a number"] = true
+L["Vehicle Seat Indicator Size"] = true
+L["Vehicle"] = true
+L["Vendor Gray Detailed Report"] = true
+L["Vendor Grays"] = true
+L["Version"] = true
+L["Vertical Fill Direction"] = true
+L["Vertical Spacing"] = true
+L["Vertical"] = true
+L["Visibility State"] = true
+L["Visibility"] = true
+L["Watch Frame"] = true
+L["What point to anchor to the frame you set to attach to."] = true
+L["What to attach the buff anchor frame to."] = true
+L["What to attach the debuff anchor frame to."] = true
+L["When enabled active buff icons will light up instead of becoming darker, while inactive buff icons will become darker instead of being lit up."] = true
+L["When enabled it will only show spells that were added to the filter using a spell ID and not a name."] = true
+L["When in a raid group display if anyone in your raid is targeting the current tooltip unit."] = true
+L["When inside a battleground display personal scoreboard information on the main datatext bars."] = true
+L["When opening the Chat Editbox to type a message having this option set means it will retain the last channel you spoke in. If this option is turned off opening the Chat Editbox should always default to the SAY channel."] = true
+L["When true, the header includes the player when not in a raid."] = true
+L["When you go AFK display the AFK screen."] = true
+L["Whitelist"] = true
+L["Width Multiplier"] = true
+L["Width"] = true
+L["Will attempt to sell another item in set interval after previous one was sold."] = true
+L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."] = true
+L["Word Wrap"] = true
+L["World Map Coordinates"] = true
+L["World State Frame"] = true
+L["Wrap After"] = true
+L["X-Offset"] = true
+L["Y-Offset"] = true
+L["You do not need to use 'Is Casting Anything' or 'Is Channeling Anything' for these spells to trigger."] = true
+L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."] = true
+L["You must be targeting a player."] = true
+L["You need to hold this modifier down in order to blacklist an aura by right-clicking the icon. Set to None to disable the blacklist functionality."] = true
+L["Your Auras First"] = true
+L["xOffset"] = true
+L["yOffset"] = true
+
+L["ACTIONBARS_DESC"] = "Modify the actionbar settings."
+L["AURAS_DESC"] = "Configure the aura icons that appear near the minimap."
+L["BAGS_DESC"] = "Adjust bag settings for ElvUI."
+L["CHAT_DESC"] = "Adjust chat settings for ElvUI."
+L["COOLDOWN_DESC"] = "Adjust Cooldown Settings."
+L["DATABAR_DESC"] = "Setup on-screen display of information bars."
+L["DATATEXT_DESC"] = "Setup the on-screen display of info-texts."
+L["ELVUI_DESC"] = "ElvUI is a complete User Interface replacement addon for World of Warcraft."
+L["NAMEPLATE_DESC"] = "Modify the nameplate settings."
+L["PANEL_DESC"] = "Adjust the size of your left and right panels, this will effect your chat and bags."
+L["SKINS_DESC"] = "Adjust Skin settings."
+L["TOGGLESKIN_DESC"] = "Enable/Disable this skin."
+L["TOOLTIP_DESC"] = "Setup options for the Tooltip."
+L["UNITFRAME_DESC"] = "Modify the unitframe settings."
+L["SEARCH_SYNTAX_DESC"] = [=[With the new addition of LibItemSearch, you now have access to much more advanced item searches. The following is a documentation of the search syntax. See the full explanation at: https://github.com/Jaliborc/LibItemSearch-1.2/wiki/Search-Syntax.
+
+Specific Searching:
+ • q:[quality] or quality:[quality]. For instance, q:epic will find all epic items.
+ • l:[level], lvl:[level] or level:[level]. For example, l:30 will find all items with level 30.
+ • t:[search], type:[search] or slot:[search]. For instance, t:weapon will find all weapons.
+ • n:[name] or name:[name]. For instance, typing n:muffins will find all items with names containing "muffins".
+ • s:[set] or set:[set]. For example, s:fire will find all items in equipment sets you have with names that start with fire.
+ • r:[level], reg:[level], rl:[level], regl:[level] or reqlvl:[level]. For example, reqlvl:30 will find all items that require level 30.
+ • tt:[search], tip:[search] or tooltip:[search]. For instance, tt:binds will find all items that can be bound to account, on equip, or on pickup.
+
+
+Search Operators:
+ • ! : Negates a search. For example, !q:epic will find all items that are NOT epic.
+ • | : Joins two searches. Typing q:epic | t:weapon will find all items that are either epic OR weapons.
+ • & : Intersects two searches. For instance, q:epic & t:weapon will find all items that are epic AND weapons
+ • >, <, <=, => : Performs comparisons on numerical searches. For example, typing lvl: >30 will find all items with level HIGHER than 30.
+
+
+The following search keywords can also be used:
+ • soulbound, bound, bop : Bind on pickup items.
+ • bou : Bind on use items.
+ • boe : Bind on equip items.
+ • boa : Bind on account items.
+ • quest : Quest bound items.]=]
+L["TEXT_FORMAT_DESC"] = [=[Provide a string to change the text format.
+
+Examples:
+[namecolor][name] [difficultycolor][smartlevel] [shortclassification]
+[healthcolor][health:current-max]
+[powercolor][power:current]
+
+Health / Power Formats:
+"current" - current amount
+"percent" - percentage amount
+"current-max" - current amount followed by maximum amount, will display only max if current is equal to max
+"current-percent" - current amount followed by percentage amount, will display only max if current is equal to max
+"current-max-percent" - current amount, max amount, followed by percentage amount, will display only max if current is equal to max
+"deficit" - display the deficit value, will display nothing if there is no deficit
+
+Name Formats:
+"name:veryshort" - Name restricted to 5 characters
+"name:short" - Name restricted to 10 characters
+"name:medium" - Name restricted to 15 characters
+"name:long" - Name restricted to 20 characters
+"name:short:translit" - Name restricted to 10 characters with transliteration
+
+To disable leave the field blank, if you need more information visit https://www.tukui.org/forum/viewtopic.php?t=6]=]
+L["NAMEPLATE_FRAMELEVEL_DESC"] = [=[If you set this to 1 then all plates triggered by this style filter will be above any of the non-triggered plates.
+
+If you set this to 2 in another style filter then all plates triggered by that filter will be above plates with frame level set to 1 and all non-triggered plates, and so on.
+
+NOTE: This setting will NOT fix the issue with clicking or mousing over nameplates that are overlapped. That issue is due to us not being able to manipulate the frame level of the clickable area for nameplates.]=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to page differently.
+ Example: '[combat] 2;']=] ] = true
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to show/hide differently.
+ Example: '[combat] show;hide']=] ] = true
+
+L[ [=[Specify a filename located inside the World of Warcraft directory. Textures folder that you wish to have set as a panel background.
+
+Please Note:
+-The image size recommended is 256x128
+-You must do a complete game restart after adding a file to the folder.
+-The file type must be tga format.
+
+Example: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Or for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here.]=] ] = true
+
+-- Global Strings
+L["ACHIEVEMENTS"] = "Achievements"
+L["ALT_KEY_TEXT"] = "ALT"
+L["ARENA"] = "Arena"
+L["AUCTIONS"] = "Auctions"
+L["BAGSLOT"] = "Bags"
+L["BARBERSHOP"] = "Barber Shop"
+L["BATTLEGROUND"] = "Battleground"
+L["BATTLEFIELDS"] = "Battlegrounds"
+L["BLOCK"] = "Block"
+L["BOSS"] = "Boss"
+L["BUFFOPTIONS_LABEL"] = "Buffs and Debuffs"
+L["CLASS"] = "Class"
+L["CHANNEL"] = "Channel"
+L["COLOR"] = "Color"
+L["COLORS"] = "Colors"
+L["COMBAT"] = "Combat"
+L["COMBAT_TEXT_RUNE_BLOOD"] = "Blood Rune"
+L["COMBAT_TEXT_RUNE_DEATH"] = "Death Rune"
+L["COMBAT_TEXT_RUNE_FROST"] = "Frost Rune"
+L["COMBAT_TEXT_RUNE_UNHOLY"] = "Unholy Rune"
+L["COMBO_POINTS"] = "Combo |4Point:Points;"
+L["CTRL_KEY"] = "CTRL key"
+L["CUSTOM"] = "Custom"
+L["DAMAGER"] = "Damage"
+L["DEFAULT"] = "Default"
+L["DELETE"] = "Delete"
+L["DISABLE"] = "Disable"
+L["DRESSUP_FRAME"] = "Dressing Room"
+L["DUNGEON_DIFFICULTY"] = "Dungeon Difficulty"
+L["DUNGEONS"] = "Dungeons"
+L["EMOTE"] = "Emote"
+L["ENEMY"] = "Enemy"
+L["ENERGY"] = "Energy"
+L["FACTION_STANDING_LABEL1"] = "Hated"
+L["FACTION_STANDING_LABEL2"] = "Hostile"
+L["FACTION_STANDING_LABEL3"] = "Unfriendly"
+L["FACTION_STANDING_LABEL4"] = "Neutral"
+L["FACTION_STANDING_LABEL5"] = "Friendly"
+L["FACTION_STANDING_LABEL6"] = "Honored"
+L["FACTION_STANDING_LABEL7"] = "Revered"
+L["FACTION_STANDING_LABEL8"] = "Exalted"
+L["FILTERS"] = "Filters"
+L["FLIGHT_MAP"] = "Flight Map"
+L["FOCUS"] = "Focus"
+L["FONT_SIZE"] = "Font Size"
+L["FRIEND"] = "Friend"
+L["FRIENDS"] = "Friends"
+L["GROUP"] = "Group"
+L["GUILD"] = "Guild"
+L["GUILD_BANK"] = "Guild Bank"
+L["HAPPINESS"] = "Happiness"
+L["HEALER"] = "Healer"
+L["HEALTH"] = "Health"
+L["HIDE"] = "Hide"
+L["INSCRIPTION"] = "Inscription"
+L["INSPECT"] = "Inspect"
+L["INTERFACE_OPTIONS"] = "Interface Options"
+L["INTERRUPTED"] = "Interrupted"
+L["ITEM_BIND_QUEST"] = "Quest Item"
+L["ITEMS"] = "Items"
+L["KEY_BINDINGS"] = "Key Bindings"
+L["LANGUAGE"] = "Language"
+L["LEAVE_VEHICLE"] = "Leave Vehicle"
+L["LEVEL"] = "Level"
+L["LOCK_ACTIONBAR_TEXT"] = "Lock ActionBars"
+L["LOOT"] = "Loot"
+L["MACROS"] = "Macros"
+L["MAIL_LABEL"] = "Mail"
+L["MANA"] = "Mana"
+L["MAP_FADE_TEXT"] = "Fade Map When Moving"
+L["MERCHANT"] = "Merchant"
+L["MINIMAP_LABEL"] = "Minimap"
+L["MISCELLANEOUS"] = "Miscellaneous"
+L["NAME"] = "Name"
+L["NONE"] = "None"
+L["OFFICER"] = "Officer"
+L["OPACITY"] = "Opacity"
+L["OPTION_TOOLTIP_ACTION_BUTTON_USE_KEY_DOWN"] = "Action button keybinds will respond on key down, rather than on key up."
+L["OPTION_TOOLTIP_TIMESTAMPS"] = "Select the format of timestamps for chat messages."
+L["PARTY"] = "Party"
+L["PET"] = "Pet"
+L["PLAYER"] = "Player"
+L["PLAYER_DIFFICULTY1"] = "Normal"
+L["PLAYER_DIFFICULTY2"] = "Heroic"
+L["RAGE"] = "Rage"
+L["RAID"] = "Raid"
+L["RAID_TARGET_1"] = "Star"
+L["RAID_TARGET_2"] = "Circle"
+L["RAID_TARGET_3"] = "Diamond"
+L["RAID_TARGET_4"] = "Triangle"
+L["RAID_TARGET_5"] = "Moon"
+L["RAID_TARGET_6"] = "Square"
+L["RAID_TARGET_7"] = "Cross"
+L["RAID_TARGET_8"] = "Skull"
+L["REPUTATION"] = "Reputation"
+L["ROLE"] = "Role"
+L["RUNIC_POWER"] = "Runic Power"
+L["SAY"] = "Say"
+L["SHIFT_KEY"] = "SHIFT key"
+L["SHORT"] = "Short"
+L["SHOW"] = "Show"
+L["SPEED"] = "Speed"
+L["SPELLBOOK"] = "Spellbook"
+L["TALENTS"] = "Talents"
+L["TANK"] = "Tank"
+L["TARGET"] = "Target"
+L["TIMEMANAGER_TITLE"] = "Clock"
+L["TIMESTAMPS_LABEL"] = "Chat Timestamps"
+L["TRADE"] = "Trade"
+L["TRADESKILLS"] = "Tradeskills"
+L["TUTORIAL_TITLE47"] = "Totem Bar"
+L["UI_SCALE"] = "UI Scale"
+L["UNIT_NAMEPLATES_TYPES"] = "Nameplate Motion Type"
+L["UNIT_NAMEPLATES_TYPE_1"] = "Overlapping Nameplates"
+L["UNIT_NAMEPLATES_TYPE_2"] = "Stacking Nameplates"
+L["WHISPER"] = "Whisper"
+L["WORLD_MAP"] = "Map"
+L["XPBAR_LABEL"] = "XP Bar"
+L["YELL"] = "Yell"
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Locales/esMX.lua b/ElvUI_OptionsUI/Locales/esMX.lua
new file mode 100644
index 0000000..59ab641
--- /dev/null
+++ b/ElvUI_OptionsUI/Locales/esMX.lua
@@ -0,0 +1,1388 @@
+-- Spanish localization file for esES and esMX.
+local L = ElvUI[1].Libs.ACL:NewLocale("ElvUI", "esMX")
+
+L["%s and then %s"] = "%s y entonces %s"
+L["2D"] = "2D"
+L["3D"] = "3D"
+L["AFK Mode"] = "Modo AFK"
+L["ANCHOR_CURSOR"] = true
+L["ANCHOR_CURSOR_LEFT"] = true
+L["ANCHOR_CURSOR_RIGHT"] = true
+L["Abbreviation"] = true
+L["Above Chat"] = "Arriba del Chat"
+L["Above"] = "Encima"
+L["Accept Invites"] = "Aceptar Invitaciones"
+L["Action Paging"] = "Paginación"
+L["ActionBars"] = "Barras de Acción"
+L["Actions"] = "Acciones"
+L["Add Item or Search Syntax"] = "Agregar objetos o sintaxis de búsqueda"
+L["Add Name"] = true
+L["Add Regular Filter"] = "Agregar filtro regular"
+L["Add Special Filter"] = "Agregar filtro especial"
+L["Add Spell ID or Name"] = "Agregar nombre o ID de hechizo"
+L["Add SpellID"] = "Añadir ID de Hechizo"
+L["Add a Name to the list."] = true
+L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."] = true
+L["Add a spell to the filter."] = "Añade un hechizo al filtro."
+L["Add an item or search syntax to the ignored list. Items matching the search syntax will be ignored."] = "Agregue un objetos o una sintaxis de búsqueda a la lista ignorada. Los objetos que coincidan con la sintaxis de búsqueda serán ignorados."
+L["Additional Power Text"] = "Texto de poder adicional"
+L["Additional spacing between each individual group."] = "Espaciado adicional entre cada grupo individual."
+L["Additive Blend"] = "Mezcla Aditiva"
+L["Adjust the height of your right chat panel."] = "Ajuste la altura del panel de chat derecho."
+L["Adjust the position of the threat bar to either the left or right datatext panels."] = "Ajusta la posición de la barra de amenaza a la izquierda o derecha de los paneles de texto de datos."
+L["Adjust the size of the minimap."] = "Ajusta el tamaño del minimapa."
+L["Adjust the width of the bag frame."] = "Ajustar el ancho del marco de las bolsas."
+L["Adjust the width of the bank frame."] = "Ajustar el ancho del marco del banco."
+L["Adjust the width of your right chat panel."] = "Ajusta el ancho del panel de chat derecho."
+L["Alert Frames"] = "Alertas"
+L["Alerts"] = "Alertas"
+L["Allow LBF to handle the skinning of this element."] = true
+L["Allowed Combat Repeat"] = "Repetición de combate permitida"
+L["Alpha Fading"] = "Desvanecimiento Alfa"
+L["Alpha Key"] = "Clave Alfa"
+L["Alpha channel is taken from the color option."] = true
+L["Alpha"] = "Transparencia"
+L["Always Display"] = "Mostrar Siempre"
+L["Always Hide"] = "Ocultar Siempre"
+L["Always Show Realm"] = "Mostrar siempre el reino"
+L["Always Show Target Health"] = true
+L["Ammo Pouch"] = true
+L["An X offset (in pixels) to be used when anchoring new frames."] = true
+L["An Y offset (in pixels) to be used when anchoring new frames."] = true
+L["Anchor Point"] = "Punto de Fijación"
+L["Announce Interrupts"] = "Anunciar Interrupciones"
+L["Announce when you interrupt a spell to the specified chat channel."] = "Anunciar cuando interrumpas un hechizo en el canal especificado."
+L["Applies the font and font size settings throughout the entire user interface. Note: Some font size settings will be skipped due to them having a smaller font size by default."] = true
+L["Applies the primary texture to all statusbars."] = true
+L["Apply Font To All"] = true
+L["Apply Texture To All"] = true
+L["Apply this filter if a buff has remaining time greater than this. Set to zero to disable."] = "Aplica este filtro si un beneficio tiene un tiempo restante mayor que este. Establecer en cero para deshabilitar."
+L["Apply this filter if a buff has remaining time less than this. Set to zero to disable."] = "Aplica este filtro si un beneficio tiene un tiempo restante inferior a este. Establecer en cero para deshabilitar."
+L["Apply this filter if a debuff has remaining time greater than this. Set to zero to disable."] = "Aplica este filtro si una perjuicio tiene un tiempo restante mayor que este. Establecer en cero para deshabilitar."
+L["Apply this filter if a debuff has remaining time less than this. Set to zero to disable."] = "Aplica este filtro si un perjuicio tiene un tiempo restante inferior a este. Establecer en cero para deshabilitar."
+L["Are you sure you want to reset ActionBars settings?"] = "¿Estás seguro de que quieres restablecer la configuración de barras de acción?"
+L["Are you sure you want to reset Auras settings?"] = "¿Estás seguro de que quieres restablecer la configuración de Auras?"
+L["Are you sure you want to reset Bags settings?"] = "¿Estás seguro de que quieres restablecer la configuración de Bolsas?"
+L["Are you sure you want to reset Chat settings?"] = "¿Estás seguro de que quieres restablecer la configuración de Chat?"
+L["Are you sure you want to reset Cooldown settings?"] = "¿Estás seguro de que quieres restablecer la configuración de Reutilización?"
+L["Are you sure you want to reset DataBars settings?"] = "¿Estás seguro de que quieres restablecer la configuración de Barra de Datos?"
+L["Are you sure you want to reset DataTexts settings?"] = "¿Estás seguro de que quieres restablecer la configuración de Datos de Texto?"
+L["Are you sure you want to reset General settings?"] = "¿Estás seguro de que quieres restablecer la configuración de General?"
+L["Are you sure you want to reset NamePlates settings?"] = "¿Estás seguro de que quieres restablecer la configuración de Placas de Nombre?"
+L["Are you sure you want to reset Tooltip settings?"] = "¿Estás seguro de que quieres restablecer la configuración de Descripción Emergente?"
+L["Are you sure you want to reset UnitFrames settings?"] = "¿Estás seguro de que quieres restablecer la configuración de Marco de Unidad?"
+L["Arena Frame"] = true
+L["Arena Registrar"] = true
+L["Arena"] = true
+L["Ascending or Descending order."] = "Orden ascendente o descendente."
+L["Ascending"] = "Ascendente"
+L["Assist Target"] = "Asistir a Objetivo"
+L["Assist"] = true
+L["At what point should the text be displayed. Set to -1 to disable."] = "En qué punto debe mostrarse el texto. Establécelo en -1 para desactivar."
+L["Attach Text To"] = "Adjuntar texto a"
+L["Attach To"] = "Adjuntar a"
+L["Attempt to create URL links inside the chat."] = "Trata de crear enlaces URL dentro del chat."
+L["Attempt to lock the left and right chat frame positions. Disabling this option will allow you to move the main chat frame anywhere you wish."] = "Intenta bloquear las posiciones de los marcos de chat. Si lo deseas, puedes desactivar esta opción para tener completa mobilidad de la ventana de chat. Esto te dará la oportunidad de ubicarla donde desées."
+L["Attempt to support eyefinity/nvidia surround."] = true
+L["Aura Bars"] = "Barra de Auras"
+L["Aura Filters"] = "Filtros de Aura"
+L["Auto Greed/DE"] = "Codicia/Desencantar Automático"
+L["Auto Hide"] = "Ocultar Automáticamente"
+L["Auto Repair"] = "Reparación Automática"
+L["Auto-Hide"] = "Ocultar Automáticamente"
+L["Automatic"] = "Automático"
+L["Automatically accept invites from guild/friends."] = "Aceptar de forma automática invitaciones de la hermandad/amigos."
+L["Automatically hide the objetive frame during boss or arena fights."] = true
+L["Automatically repair using the following method when visiting a merchant."] = "Repara de forma automática usando el siguiente método cuando visites un comerciante."
+L["Automatically select greed or disenchant (when available) on green quality items. This will only work if you are the max level."] = "Tira codicia o desencanta (si se puede) automáticamente para los objetos verdes. Esto sólo funciona si ya tienes el nivel máximo."
+L["Automatically vendor gray items when visiting a vendor."] = "Vender automáticamente los objetos grises al visitar al vendedor."
+L["Available Tags"] = "Tags de Disponibles"
+L["BG Map"] = "Mapa de CB"
+L["BG Score"] = "Puntuación de CB"
+L["BINDING_HEADER_RAID_TARGET"] = "Marcador de objetivo"
+L["BOSS"] = true
+L["Backdrop Color"] = "Color de Fondo"
+L["Backdrop Faded Color"] = "Color Atenuado de Fondo"
+L["Backdrop Spacing"] = true
+L["Backdrop color of transparent frames"] = "Color de fondo de los marcos transparentes."
+L["Backdrop"] = "Fondo"
+L["Background Glow"] = true
+L["Bad Color"] = true
+L["Bad Scale"] = true
+L["Bad Transition Color"] = true
+L["Bad"] = "Hostil"
+L["Bag 1"] = true
+L["Bag 2"] = true
+L["Bag 3"] = true
+L["Bag 4"] = true
+L["Bag Sorting"] = true
+L["Bag Spacing"] = true
+L["Bag"] = true
+L["Bag-Bar"] = "Barra de las Bolsas"
+L["Bags Only"] = true
+L["Bags/Bank"] = true
+L["Bank 1"] = true
+L["Bank 2"] = true
+L["Bank 3"] = true
+L["Bank 4"] = true
+L["Bank 5"] = true
+L["Bank 6"] = true
+L["Bank 7"] = true
+L["Bank Only"] = true
+L["Bar Direction"] = "Dirección de la Barra"
+L["Bars will transition smoothly."] = "Las barras harán las transiciones suavemente."
+L["Battleground Texts"] = "Textos de los Campos de Batalla"
+L["Begin a new row or column after this many auras."] = "Empieza una nueva fila o columna después de estas auras."
+L["Below Chat"] = "Debajo del Chat"
+L["Below"] = "Debajo"
+L["Blacklist Modifier"] = true
+L["Blacklist"] = "Lista Negra"
+L["Blend Mode"] = "Modo de Mezcla"
+L["Blend"] = "Mezcla"
+L["BlizzUI Improvements"] = true
+L["Blizzard Style"] = true
+L["Blizzard"] = true
+L["Block Combat Click"] = true
+L["Block Combat Hover"] = true
+L["Block Mouseover Glow"] = true
+L["Block Target Glow"] = true
+L["Blocks all click events while in combat."] = true
+L["Blocks datatext tooltip from showing in combat."] = true
+L["Border Color"] = "Color de Borde"
+L["Border Glow"] = true
+L["Border"] = true
+L["Borders"] = "Bordes"
+L["Both"] = true
+L["Bottom Left"] = true
+L["Bottom Panel"] = "Panel Inferior"
+L["Bottom Right"] = true
+L["Bottom to Top"] = "De Abajo hacia Arriba"
+L["Bottom"] = true
+L["BottomLeftMiniPanel"] = "Minimap BottomLeft (Inside)"
+L["BottomMiniPanel"] = "Minimap Bottom (Inside)"
+L["BottomRightMiniPanel"] = "Minimap BottomRight (Inside)"
+L["Buff Indicator"] = "Indicador de Beneficio"
+L["Button Size (Bag)"] = "Tamaño de los Botones (Bolsas)"
+L["Button Size (Bank)"] = "Tamaño de los Botones (Banco)"
+L["Button Size"] = "Tamaño del Botón"
+L["Button Spacing"] = "Separación de Botones"
+L["Buttons Per Row"] = "Botones por Fila"
+L["Buttons"] = "Botones"
+L["By Type"] = "Por tipo"
+L["Calendar Frame"] = "Calendario"
+L["Cast Bar"] = true
+L["Cast Color"] = true
+L["Cast No Interrupt Color"] = true
+L["Cast Time Format"] = true
+L["Castbar"] = "Barra de Lanzamiento"
+L["Casting"] = true
+L["Center"] = "Centro"
+L["Change settings for the display of the location text that is on the minimap."] = "Cambia la configuración para mostrar el texto de ubicación que está en el minimapa."
+L["Change the alpha level of the frame."] = "Cambia el nivel de transparencia del marco"
+L["Channel Alerts"] = true
+L["Change the width and controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Channel Time Format"] = true
+L["Character Frame"] = "Personaje"
+L["Chat Bubble Names"] = true
+L["Chat Bubbles Style"] = true
+L["Chat Bubbles"] = true
+L["Chat EditBox Position"] = "Posición del Cuadro de Edición del Chat"
+L["Chat Output"] = true
+L["Check these to only have the filter active in certain difficulties. If none are checked, it is active in all difficulties."] = true
+L["CheckBox Skin"] = true
+L["Choose Export Format"] = true
+L["Choose UIPARENT to prevent it from hiding with the unitframe."] = true
+L["Choose What To Export"] = true
+L["Choose when you want the tooltip to show in combat. If a modifer is chosen, then you need to hold that down to show the tooltip."] = true
+L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."] = true
+L["Class Backdrop"] = "Fondo de Clase"
+L["Class Castbars"] = "Barras de Lanzamiento de Clase"
+L["Class Color Mentions"] = true
+L["Class Color Override"] = "Ignorar Color de Clase"
+L["Class Health"] = "Salud de Clase"
+L["Class Power"] = "Poder de Clase"
+L["Class Resources"] = "Recursos de Clase"
+L["Class Totems"] = "Tótems de Clase"
+L["Clear Filter"] = true
+L["Clear Search On Close"] = true
+L["Click Through"] = "Clic A través"
+L["Clickable Height"] = true
+L["Clickable Size"] = true
+L["Clickable Width / Width"] = true
+L["Coding:"] = "Codificación:"
+L["Color Keybind Text when Out of Range, instead of the button."] = true
+L["Color Keybind Text"] = true
+L["Color Override"] = true
+L["Color Turtle Buffs"] = "Colorear Beneficios de Tortuga"
+L["Color all buffs that reduce the unit's incoming damage."] = "Colorea todos los beneficios que reduzcan el daño recibido por la unidad."
+L["Color aurabar debuffs by type."] = "Color de los perjuicios de la barra de aura por tipo"
+L["Color by Value"] = true
+L["Color castbars by the class of player units."] = true
+L["Color castbars by the reaction type of non-player units."] = true
+L["Color health by amount remaining."] = "Color de salud por la cantidad restante."
+L["Color health by classcolor or reaction."] = "Color de salud por el color de clase o reacción."
+L["Color health by threat status."] = true
+L["Color of the actionbutton when not usable."] = true
+L["Color of the actionbutton when out of power (Mana, Rage)."] = "Color del botón cuando no tengas poder (Mana, Ira)."
+L["Color of the actionbutton when out of range."] = "Color del botón cuando el objetivo esté fuera de rango"
+L["Color of the actionbutton when usable."] = true
+L["Color power by classcolor or reaction."] = "Color de poder por el color de clase o reacción."
+L["Color power by threat status."] = true
+L["Color some texts use."] = "Color que usan algunos textos."
+L["Color the health backdrop by class or reaction."] = "Color de fondo de salud por el color de clase o reacción."
+L["Color the unit healthbar if there is a debuff that can be dispelled by you."] = "Color de la barra de salud si hay un perjuicio que puede ser disipado por ti."
+L["Color when the text is about to expire"] = "Color del texto cuando esté a punto de expirar."
+L["Color when the text is in the days format."] = "Color del texto cuando tenga formato de días."
+L["Color when the text is in the hours format."] = "Color del texto cuando tenga formato de horas."
+L["Color when the text is in the minutes format."] = "Color del texto cuando tenga formato de minutos."
+L["Color when the text is in the seconds format."] = "Color del texto cuando tenga formato de segundos."
+L["Colored Icon"] = "Icono Coloreado"
+L["Coloring (Specific)"] = "Coloreado (Específico)"
+L["Coloring"] = "Coloreado"
+L["Colorize Selected Text"] = true
+L["Colors the border according to the Quality of the Item."] = true
+L["Combat Icon"] = true
+L["Combat Override Key"] = true
+L["CombatText Font"] = "Fuente del Texto de Combate"
+L["Combo Point"] = true
+L["Comparison Font Size"] = true
+L["Condensed"] = "Condensado"
+L["Configure Auras"] = "Configurar Auras"
+L["Control enemy nameplates toggling on or off when in combat."] = true
+L["Control friendly nameplates toggling on or off when in combat."] = true
+L["Controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Controls the amount of decimals used in values displayed on elements like NamePlates and UnitFrames."] = true
+L["Controls the speed at which smoothed bars will be updated."] = true
+L["Controls how many seconds of inactivity has to pass before chat is faded."] = true
+L["Cooldown Orientation"] = true
+L["Cooldown Text"] = "Texto de Reutilización"
+L["Cooldowns"] = true
+L["Copy From"] = "Copiar Desde"
+L["Copy Settings From"] = true
+L["Copy settings from another unit."] = true
+L["Core |cff1784d1E|r|cffe5e3e3lvUI|r options."] = true
+L["Count Font Size"] = "Tamaño de Fuente del Contador"
+L["Count xOffset"] = true
+L["Count yOffset"] = true
+L["Create Custom Text"] = true
+L["Create Filter"] = "Crear Filtro"
+L["Create a filter, once created a filter can be set inside the buffs/debuffs section of each unit."] = "Crea un filtro, una vez creado podrás establecerlo dentro de la sección beneficios/perjuicios de cada unidad."
+L["Credits"] = "Créditos"
+L["Crop Icons"] = true
+L["Currency Format"] = "Formato de Moneda"
+L["Current - Max | Percent"] = true
+L["Current - Max"] = "Actual - Máximo"
+L["Current - Percent (Remaining)"] = true
+L["Current - Percent"] = "Actual - Porcentaje"
+L["Current - Remaining"] = true
+L["Current / Max"] = "Actual / Máximo"
+L["Current Level"] = true
+L["Current"] = "Actual"
+L["Curse Effect"] = true
+L["Cursor Anchor Offset X"] = true
+L["Cursor Anchor Offset Y"] = true
+L["Cursor Anchor Type"] = true
+L["Cursor Anchor"] = true
+L["Custom Backdrop"] = true
+L["Custom Color"] = true
+L["Custom Dead Backdrop"] = true
+L["Custom Faction Colors"] = true
+L["Custom Texts"] = "Texto Personalizado"
+L["Custom Texture"] = true
+L["Custom Timestamp Color"] = true
+L["Cutaway Bars"] = true
+L["DATABAR_DESC"] = true
+L["Darken Inactive"] = true
+L["DataBars"] = true
+L["DataTexts"] = "Textos de Datos"
+L["Datatext Panel (Left)"] = "Panel Izquierdo de los Datos de texto"
+L["Datatext Panel (Right)"] = "Panel Derecho de los Datos de texto"
+L["Date Format"] = true
+L["Days"] = "Días"
+L["Debuff Highlighting"] = "Resaltado de Perjuicio"
+L["Debug Tools"] = "Herramientas de Depuración"
+L["Decimal Length"] = "Longitud Decimal"
+L["Decimal Threshold"] = "Umbral Decimal"
+L["Decode Text"] = "Decodificar texto"
+L["Default Color"] = "Color Predeterminado"
+L["Default Font"] = "Fuente Predeterminado"
+L["Default Settings"] = "Configuración por defecto"
+L["Deficit"] = "Déficit"
+L["Defines how the group is sorted."] = "Define como se ordena el grupo."
+L["Defines the sort order of the selected sort method."] = "Define el orden para el método de organización seleccionado."
+L["Delete Filter"] = "Borrar Filtro"
+L["Delete a created filter, you cannot delete pre-existing filters, only custom ones."] = "Borra el filtro creado, no puedes borrar filtro pre-existentes, sólo los personalizados."
+L["Desaturate Cooldowns"] = "Tiempo de reutilización de desaturados"
+L["Desaturate Junk Items"] = "Desaturar los objetos basura"
+L["Desaturated Icon"] = true
+L["Descending"] = "Descendente"
+L["Detach From Frame"] = "Separar Del Marco"
+L["Detached Width"] = "Ancho de Separación"
+L["Direction the bag sorting will use to allocate the items."] = "Dirección de ordenado que se usará para distribuir los objetos."
+L["Direction the bar moves on gains/losses"] = true
+L["Direction the health bar moves when gaining/losing health."] = "La dirección de la barra de salud se mueve cuando ganas/pierdes salud."
+L["Disable Bag Sort"] = true
+L["Disable Bank Sort"] = true
+L["Disable Debuff Highlight"] = true
+L["Disabled Blizzard Frames"] = true
+L["Disabled Blizzard"] = true
+L["Disables the focus and target of focus unitframes."] = true
+L["Disables the player and pet unitframes."] = true
+L["Disables the target and target of target unitframes."] = true
+L["Disconnected"] = "Desconectado"
+L["Disease Effect"] = true
+L["Display Frames"] = "Mostrar Marcos"
+L["Display Item Level"] = true
+L["Display Player"] = "Mostrar Jugador"
+L["Display Target"] = "Mostrar Objetivo"
+L["Display Text"] = "Mostrar Texto"
+L["Display a healer icon over known healers inside battlegrounds or arenas."] = "Muestra un icono de sanados sobre los sanadores conocidos en los campos de batalla o arenas."
+L["Display a panel across the bottom of the screen. This is for cosmetic only."] = "Despliega un panel a través de la parte inferior de la pantalla. Es es sólo algo cosmético."
+L["Display a panel across the top of the screen. This is for cosmetic only."] = "Despliega un panel a través de la parte superior de la pantalla. Es es sólo algo cosmético."
+L["Display a spark texture at the end of the castbar statusbar to help show the differance between castbar and backdrop."] = "Muestra una textura al final de la barra de lanzamiento/estado para ayudar a diferenciar entre la barra de lanzamiento y el fondo."
+L["Display an exclamation mark on items that starts a quest."] = true
+L["Display battleground messages in the middle of the screen."] = true
+L["Display bind names on action buttons."] = "Muestra las teclas asignadas en los botones."
+L["Display cooldown text on anything with the cooldown spiral."] = "Muestra el texto de reutilización sobre todo lo que tenga la espiral de reutilización."
+L["Display data panels below the chat, used for datatexts."] = "Mostrar los paneles de datos debajo del chat para los datos de texto."
+L["Display emotion icons in chat."] = "Muestra emoticonos en el chat."
+L["Display guild ranks if a unit is guilded."] = "Mostrar rangos de hermandad si el jugador pertenece a una."
+L["Display how many of a certain item you have in your possession."] = "Despliega la cantidad de un determinado objeto que posees."
+L["Display macro names on action buttons."] = "Muestra el nombre de las macros en los botones."
+L["Display minimap panels below the minimap, used for datatexts."] = "Muestra los paneles del minimapa debajo del minimapa, usado para los textos de datos."
+L["Display player titles."] = "Mostrar los títulos de los jugadores"
+L["Display reminder bar on the minimap."] = true
+L["Display the castbar icon inside the castbar."] = true
+L["Display the castbar inside the information panel, the icon will be displayed outside the main unitframe."] = true
+L["Display the hyperlink tooltip while hovering over a hyperlink."] = "Muestra la descripción emergente del enlace cuando pasas el cursor sobre él."
+L["Display the junk icon on all grey items that can be vendored."] = true
+L["Display the name of the unit on the chat bubble."] = true
+L["Display the npc ID when mousing over a npc tooltip."] = true
+L["Display the spell or item ID when mousing over a spell or item tooltip."] = "Despliega el ID de hechizo u objeto cuando pasas el ratón sobre un hechizo o un ojbeto."
+L["Display the target of your current cast. Useful for mouseover casts."] = "Muestra el objetivo de tu hechizo actual. Es útil para hechizos por ratón."
+L["Display tick marks on the castbar for channelled spells. This will adjust automatically for spells like Drain Soul and add additional ticks based on haste."] = "Muestra las marcas de cada tick en la barra de lanzamiento para los hechizos canalizados. Esto se ajustará automáticamente con base en el hechizo y la celeridad."
+L["Displayed server time."] = true
+L["Displays a detailed report of every item sold when enabled."] = true
+L["Displays item level on equippable items."] = true
+L["Display Types"] = true
+L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."] = true
+L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."] = true
+L["Donations:"] = "Donativos:"
+L["Down"] = "Abajo"
+L["Dropdown CheckBox Skin"] = true
+L["Dungeon & Raid Filter"] = true
+L["Duration Enable"] = true
+L["Duration Font Size"] = true
+L["Duration Reverse"] = "Revertir Duración"
+L["Duration Text"] = true
+L["Duration"] = "Duración"
+L["Editbox History Size"] = true
+L["ELVUI_CREDITS"] = "Quiero dar un agradecimiento especial a las siguientes personas por ayudar a probar y codificar este addon y también a quienes me ayudaron con donativos. Nota: Para los donativos sólo muestro los nombres de quienes me enviaron un mensaje en el foro. Si tu nombre no aparece y quieres que lo agregue mándame un mensaje."
+L["ENEMY_NPC"] = "Enemy NPC"
+L["ENEMY_PLAYER"] = "Enemy Player"
+L["Elite Icon"] = true
+L["Emotion Icons"] = "Emoticonos"
+L["Enable Custom Color"] = true
+L["Enable the use of separate size options for the right chat panel."] = true
+L["Enable/Disable the Bag-Bar."] = "Activa/Desactiva la barra de las bolsas."
+L["Enable/Disable the all-in-one bag."] = "Habilitar/Deshabilitar la bolsa todo en uno."
+L["Enable/Disable the loot frame."] = "Activa/Desactiva el marco de botín."
+L["Enable/Disable the loot roll frame."] = "Activa/Desactiva el marco de sorteo de botín."
+L["Enable/Disable the minimap. |cffFF0000Warning: This will prevent you from seeing the consolidated buffs bar, and prevent you from seeing the minimap datatexts.|r"] = true
+L["Enable/Disable the scaling of targetted nameplates."] = true
+L["Enables the ElvUI Raid Control panel."] = true
+L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."] = true
+L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."] = true
+L["Enabling this will check your health amount."] = true
+L["Enabling this will check your power amount."] = true
+L["Enchanting"] = true
+L["Enemy Aura Type"] = "Tipo de Aura Enemiga"
+L["Enemy Combat Toggle"] = true
+L["Enemy NPC Frames"] = true
+L["Enemy Player Frames"] = true
+L["Enemy"] = "Enemigo"
+L["Engineering"] = true
+L["Enhanced PVP Messages"] = true
+L["Equipped Item Color"] = true
+L["Equipped Item"] = true
+L["Error decoding data. Import string may be corrupted!"] = true
+L["Error exporting profile!"] = true
+L["Exclude Name"] = true
+L["Excluded Names"] = true
+L["Excluded names will not be class colored."] = true
+L["Expiring"] = "Expiración"
+L["Export Profile"] = true
+L["Exported"] = true
+L["FRIENDLY_NPC"] = "Friendly NPC"
+L["FRIENDLY_PLAYER"] = "Friendly Player"
+L["Fade Chat Toggles"] = true
+L["Fade Out Delay"] = true
+L["Fade Out"] = true
+L["Fade Tabs No Backdrop"] = true
+L["Fade Threshold"] = "Umbral de Transparencia"
+L["Fade Undocked Tabs"] = true
+L["Fade the chat text when there is no activity."] = "Desvanecer el texto del chat cuando no hay actividad"
+L["Fader"] = true
+L["Fades the buttons that toggle chat windows when that window has been toggled off."] = true
+L["Fades the text on chat tabs that are docked in a panel where the backdrop is disabled."] = true
+L["Fades the text on chat tabs that are not docked at the left or right chat panel."] = true
+L["Fill"] = "Llenar"
+L["Filled"] = "Lleno"
+L["Filter Priority"] = true
+L["Filter Search"] = true
+L["Filter Type"] = "Tipo de Filtro"
+L["Filter already exists!"] = true
+L["Filters Page"] = true
+L["Filters are not allowed to have commas in their name. Stripping commas from filter name."] = true
+L["Flash"] = true
+L["Fluid Position Buffs on Debuffs"] = true
+L["Fluid Position Debuffs on Buffs"] = true
+L["Flyout Direction"] = true
+L["Flyout Spacing"] = true
+L["Focus"] = true
+L["FocusTarget"] = true
+L["Font Outline"] = "Contorno de Fuente"
+L["Font"] = "Fuente"
+L["Fonts"] = "Fuentes"
+L["Force Off"] = "Fuerza Apagada"
+L["Force On"] = "Fuerza Encendida"
+L["Force Reaction Color"] = true
+L["Force the frames to show, they will act as if they are the player frame."] = "Forzar a mostrar los marcos, esto funcionará si es el marco del jugador."
+L["Forces Debuff Highlight to be disabled for these frames"] = true
+L["Forces Mouseover Glow to be disabled for these frames"] = true
+L["Forces Target Glow to be disabled for these frames"] = true
+L["Forces reaction color instead of class color on units controlled by players."] = true
+L["Format"] = "Formato"
+L["Frame Glow"] = true
+L["Frame Level"] = true
+L["Frame Orientation"] = true
+L["Frame Strata"] = true
+L["Frequent Updates"] = "Actualizaciones Frecuentes"
+L["Friendly Aura Type"] = "Tipo de Aura Amistosa"
+L["Friendly Combat Toggle"] = true
+L["Friendly NPC Frames"] = true
+L["Friendly Player Frames"] = true
+L["Friendly"] = "Amistoso"
+L["Full Overlay"] = true
+L["Full"] = true
+L["GM Chat"] = true
+L["GPS Arrow"] = true
+L["Gems"] = true
+L["General Options"] = true
+L["Global (Account Settings)"] = true
+L["Global Fade Transparency"] = true
+L["Global"] = true
+L["Glow"] = "Brillo"
+L["Gold Format"] = true
+L["Good Color"] = true
+L["Good Scale"] = true
+L["Good Transition Color"] = true
+L["Good"] = "Amistoso"
+L["Gossip Frame"] = "Actualidad"
+L["Group By"] = "Agrupar Por"
+L["Group Spacing"] = true
+L["Grouping & Sorting"] = true
+L["Groups Per Row/Column"] = true
+L["Growth Direction"] = "Dirección de Crecimiento"
+L["Growth X-Direction"] = true
+L["Growth Y-Direction"] = true
+L["Growth direction from the first unitframe."] = "Dirección de crecimiento desde el primer marco de unidad."
+L["Guide:"] = true
+L["Guild Ranks"] = "Rangos de Hermandad"
+L["Guild Registrar"] = "Registrar Hermandad"
+L["HH:MM Threshold"] = true
+L["HH:MM"] = true
+L["Header Font Size"] = true
+L["Heal Prediction"] = "Predicción de Sanación"
+L["Healer Icon"] = "Icono de Sanador"
+L["Health Backdrop Multiplier"] = true
+L["Health Backdrop"] = "Fondo de Salud"
+L["Health Bar"] = true
+L["Health Border"] = "Borde de Salud"
+L["Health By Value"] = "Salud por Valor"
+L["Health Color"] = true
+L["Health Length"] = true
+L["Health Threshold"] = true
+L["Health"] = "Salud"
+L["Height Multiplier"] = "Multiplicador de Altura"
+L["Height of the objective tracker. Increase size to be able to see more objectives."] = true
+L["Height"] = "Altura"
+L["Help Frame"] = "Ayuda"
+L["Herbalism"] = true
+L["Here you can add items or search terms that you want to be excluded from sorting. To remove an item just click on its name in the list."] = true
+L["Hide At Max Level"] = true
+L["Hide Both"] = "Ocultar Ambos"
+L["Hide Error Text"] = "Ocultar Texto de Error"
+L["Hide Frame"] = true
+L["Hide In Combat"] = true
+L["Hide In Vehicle"] = true
+L["Hide Spell Name"] = true
+L["Hide Time"] = true
+L["Hide specific sections in the datatext tooltip."] = true
+L["Hide tooltip while in combat."] = "Oculta la descripción emergente mientras estás en combate."
+L["Hides the red error text at the top of the screen while in combat."] = "Oculta el texto rojo de error en la parte superior de la pantalla mientras estás en combate."
+L["History Size"] = true
+L["History"] = true
+L["Horizontal Spacing"] = "Espaciado Horizontal"
+L["Horizontal"] = "Horizontal"
+L["Hours"] = "Horas"
+L["Hover Highlight"] = true
+L["Hover"] = true
+L["How long the cutaway health will take to fade out."] = true
+L["How long the cutaway power will take to fade out."] = true
+L["How many seconds the castbar should stay visible after the cast failed or was interrupted."] = true
+L["How much time before the cutaway health starts to fade."] = true
+L["How much time before the cutaway power starts to fade."] = true
+L["Hyperlink Hover"] = "Cursor Sobre Hipervínculo"
+L["Icon Frame"] = true
+L["Icon Inside Castbar"] = true
+L["Icon Only"] = true
+L["Icon Position"] = true
+L["Icon Size"] = true
+L["Icon"] = "Icono"
+L["Icon: BOTTOM"] = "Icono: ABAJO"
+L["Icon: BOTTOMLEFT"] = "Icono: ABAJO-IZQUIERDA"
+L["Icon: BOTTOMRIGHT"] = "Icono: ABAJO-DERECHA"
+L["Icon: LEFT"] = "Icono: IZQUIERDA"
+L["Icon: RIGHT"] = "Icono: DERECHA"
+L["Icon: TOP"] = "Icono: ARRIBA"
+L["Icon: TOPLEFT"] = "Icono: ARRIBA-IZQUIERDA"
+L["Icon: TOPRIGHT"] = "Icono: ARRIBA-DERECHA"
+L["Icons and Text (Short)"] = true
+L["Icons and Text"] = "Iconos y Texto"
+L["If enabled then it checks if auras are missing instead of being present on the unit."] = true
+L["If enabled then it will require all auras to activate the filter. Otherwise it will only require any one of the auras to activate it."] = true
+L["If enabled then it will require all cooldowns to activate the filter. Otherwise it will only require any one of the cooldowns to activate it."] = true
+L["If enabled then the filter will activate if the unit is casting anything."] = true
+L["If enabled then the filter will activate if the unit is channeling anything."] = true
+L["If enabled then the filter will activate if the unit is not casting anything."] = true
+L["If enabled then the filter will activate if the unit is not channeling anything."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or higher than this value."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or lower than this value."] = true
+L["If enabled then the filter will only activate if the level of the unit matches this value."] = true
+L["If enabled then the filter will only activate if the level of the unit matches your own."] = true
+L["If enabled then the filter will only activate if the unit is casting interruptible spells."] = true
+L["If enabled then the filter will only activate if the unit is casting not interruptible spells."] = true
+L["If enabled then the filter will only activate if the unit is not casting or channeling one of the selected spells."] = true
+L["If enabled then the filter will only activate when you are in combat."] = true
+L["If enabled then the filter will only activate when you are not targeting the unit."] = true
+L["If enabled then the filter will only activate when you are out of combat."] = true
+L["If enabled then the filter will only activate when you are targeting the unit."] = true
+L["If enabled then the filter will only activate when you have a target."] = true
+L["If not set to 0 then override the size of the aura icon to this."] = "Si no está a 0 entonces sobrescribe el tamaño del icono del aura con este."
+L["If the aura is listed with a number then you need to use that to remove it from the list."] = true
+L["If this list is empty, and if 'Interruptible' is checked, then the filter will activate on any type of cast that can be interrupted."] = true
+L["If this threshold is used then the health of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the health of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the power of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the power of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If you have a lot of 3D Portraits active then it will likely have a big impact on your FPS. Disable some portraits if you experience FPS issues."] = true
+L["If you have any plugins supporting this feature installed you can find them in the selection dropdown to the right."] = true
+L["If you unlock actionbars then trying to move a spell might instantly cast it if you cast spells on key press instead of key release."] = true
+L["Ignore UI Scale Popup"] = true
+L["Ignore mouse events."] = "Ignorar los eventos del ratón"
+L["Ignored Items and Search Syntax (Global)"] = true
+L["Ignored Items and Search Syntax (Profile)"] = true
+L["Import Profile"] = true
+L["Importing"] = true
+L["Inactivity Timer"] = true
+L["Index"] = "Índice"
+L["Indicate whether buffs you cast yourself should be separated before or after."] = "Indica si los beneficios lanzados por ti deberían estar separados antes o después."
+L["InfoPanel Border"] = true
+L["Information Panel"] = "Panel Informativo"
+L["Inherit Global Fade"] = true
+L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."] = true
+L["Inset"] = "Hundido"
+L["Inside Information Panel"] = true
+L["Install"] = "Instalar"
+L["Instance Difficulty"] = true
+L["Instance Type"] = true
+L["Interruptable"] = "Interrumpible"
+L["Interruptible"] = "Interrumpible"
+L["Invert Colors"] = true
+L["Invert Grouping Order"] = "Invertir orden de agrupamiento"
+L["Invert foreground and background colors."] = true
+L["Is Casting Anything"] = true
+L["Is Channeling Anything"] = true
+L["Is Targeted"] = true
+L["Item Count Font"] = true
+L["Item Count"] = "Conteo de Objetos"
+L["Item Level Threshold"] = true
+L["Item Level"] = true
+L["JustifyH"] = "Justificado Horizontal"
+L["Key Down"] = "Tecla Pulsada"
+L["Keybind Mode"] = "Asignar Teclas"
+L["Keybind Text Position"] = true
+L["Keybind Text X-Offset"] = true
+L["Keybind Text Y-Offset"] = true
+L["Keybind Text"] = "Mostrar Atajos"
+L["Keyword Alert"] = "Alerta por Palabra Clave"
+L["Keywords"] = "Palabras Claves"
+L["LBF Support"] = true
+L["LEVEL_BOSS"] = "Set level to -1 for boss units or set to 0 to disable."
+L["LFD Frame"] = true
+L["LFG Queue"] = true
+L["LFR Frame"] = true
+L["Latency"] = "Latencia"
+L["Leatherworking"] = true
+L["Left Only"] = "Sólo el Izquierdo"
+L["Left to Right"] = true
+L["Left"] = "Izquierda"
+L["Limit the number of rows or columns."] = "Limita el número de filas o de columnas."
+L["List of words to color in chat if found in a message. If you wish to add multiple words you must seperate the word with a comma. To search for your current name you can use %MYNAME%.\n\nExample:\n%MYNAME%, ElvUI, RBGs, Tank"] = "Lista de palabras a colorear si son encontradas en un mensaje del chat. Si quieres agregar varias palabras debes separarlas con comas. Para buscar tu nombre actual puedes usar %MYNAME%.\n\nEjemplo:\n%MYNAME%, ElvUI, Tanque"
+L["Location Text"] = "Texto de Ubicación"
+L["Lock Positions"] = "Bloquear Posiciones"
+L["Log Taints"] = "Registro Exhaustivo"
+L["Log the main chat frames history. So when you reloadui or log in and out you see the history from your last session."] = "Guardar el historial de los marcos de chat principales. Así cuando recargues la interfaz o reconectes verás el historial de chat de tu última sesión."
+L["Login Message"] = "Mensaje de inicio"
+L["Loot Frames"] = "Despojo"
+L["Loot Roll"] = "Marco de Botín"
+L["Losing Threat"] = true
+L["Low Health Threshold"] = "Umbral de Salud Baja"
+L["Low Threat"] = true
+L["Low Threshold"] = "Umbral Bajo"
+L["Lower numbers mean a higher priority. Filters are processed in order from 1 to 100."] = true
+L["MM:SS Threshold"] = true
+L["MM:SS"] = true
+L["Macro Text"] = "Texto de Macro"
+L["Magic Effect"] = true
+L["Main Tanks / Main Assist"] = "Tanques Principales/Ayudante Principal"
+L["Main backdrop color of the UI."] = "Color principal de fondo para la interfaz."
+L["Main border color of the UI."] = true
+L["Main statusbar texture."] = "Textura de la barra de estado principal."
+L["Make textures transparent."] = "Hacer las texturas transparentes."
+L["Make the unitframe glow yellow when it is below this percent of health, it will glow red when the health value is half of this value."] = true
+L["Make the world map smaller."] = true
+L["Map Opacity When Moving"] = true
+L["Maps"] = "Mapas"
+L["Match Frame Width"] = "Coincidir con la Anchura del Marco"
+L["Match Player Level"] = true
+L["Max Alpha"] = true
+L["Max Bars"] = true
+L["Max Lines"] = true
+L["Max Overflow"] = true
+L["Max Wraps"] = "Filas/Columnas Máximas"
+L["Max amount of overflow allowed to extend past the end of the health bar."] = true
+L["Maximum Duration"] = true
+L["Maximum Level"] = true
+L["Maximum Time Left"] = true
+L["Media"] = "Medios"
+L["Method to sort by."] = true
+L["Middle Click - Set Focus"] = "Clic Intermedio - Establecer Foco"
+L["Middle clicking the unit frame will cause your focus to match the unit."] = "Hacer clic intermedio en el marco de unidad causará que tu foco sea la unidad."
+L["Middle"] = "Medio"
+L["Min Alpha"] = true
+L["Minimap Mouseover"] = "Ratón por encima del Minimapa"
+L["Minimap Panels"] = "Paneles del Minimapa"
+L["Minimum Duration"] = true
+L["Minimum Level"] = true
+L["Minimum Time Left"] = true
+L["Mining"] = true
+L["Minutes"] = "Minutos"
+L["Mirror Timers"] = true
+L["Misc Frames"] = "Misceláneos"
+L["Missing"] = true
+L["Modulating Blend"] = "Mezcla Moduladora"
+L["Module Control"] = "Control del Módulo"
+L["Module Copy"] = true
+L["Module Reset"] = true
+L["Money Format"] = true
+L["Mouse Over"] = "Pasar el ratón sobre"
+L["Mouseover Glow"] = true
+L["Mouseover Highlight"] = true
+L["Mouseover"] = "Pasar el ratón por encima"
+L["Multi-Monitor Support"] = true
+L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."] = "Multiplica el ancho o alto de los fondos por este valor. Es útil si deseas tener más de una barra con fondo."
+L["NAMEPLATE_FRAMELEVEL_DESC"] = true
+L["NPC IDs"] = true
+L["Name Color"] = true
+L["Name Colored Glow"] = true
+L["Name Font"] = "Fuente para Nombres"
+L["Name Only"] = true
+L["Name"] = "Nombre"
+L["NamePlate Style Filters"] = true
+L["NamePlates"] = "Placas de Nombre"
+L["Nameplate"] = true
+L["Neutral"] = "Neutral"
+L["Never Hide"] = "Nunca Ocultar"
+L["No Alert In Combat"] = true
+L["No Duration"] = true
+L["No Sorting"] = "No Ordenar"
+L["Non-Interruptable"] = "No-Interrumpible"
+L["Non-Target Alpha"] = true
+L["Not Casting Anything"] = true
+L["Not Channeling Anything"] = true
+L["Not Spell"] = true
+L["Not Targeted"] = true
+L["Not Usable"] = true
+L["Not valid spell id"] = "No es un id de hechizo válido"
+L["Num Rows"] = "Número de Filas"
+L["Number of Groups"] = "Número de Grupos"
+L["Number of messages you scroll for each step."] = true
+L["Number of repeat characters while in combat before the chat editbox is automatically closed. Set to 0 to disable."] = true
+L["Number of time in seconds to scroll down to the bottom of the chat window if you are not scrolled down completely."] = "Tiempo en segundos para desplazarse al final de la ventana de chat si no se ha desplazado completamente hasta el final."
+L["Objective Frame Height"] = true
+L["Off Cooldown"] = true
+L["Offset of the powerbar to the healthbar, set to 0 to disable."] = "Desplazamiento de la barra de poder sobre la barra de salud, 0 para desactivar."
+L["Offset position for text."] = "Posición de desplazamiento para el texto."
+L["Offset"] = "Desplazamiento"
+L["On Cooldown"] = true
+L["Only Match SpellID"] = true
+L["Only show when the unit is not in range."] = true
+L["Only show when you are mousing over a frame."] = true
+L["Other Filter"] = true
+L["Other's First"] = "Los de Otros Primero"
+L["Others"] = "Otros"
+L["Out of Power"] = "Sin Poder"
+L["Out of Range"] = "Fuera de Rango"
+L["Over Health Threshold"] = true
+L["Over Power Threshold"] = true
+L["Overlay Alpha"] = true
+L["Overlay"] = "Recubrir"
+L["Overnuking"] = true
+L["Override any custom visibility setting in certain situations, EX: Only show groups 1 and 2 inside a 10 man instance."] = "Sobrescribir cualquier opción de visibilidad en ciertas situaciones, Ej: Sólo mostrar grupos 1 y 2 dentro de una mazmorra de banda de 10 personas."
+L["Override the default class color setting."] = "Ignorar el ajuste predeterminado del color de clase."
+L["Owners Name"] = true
+L["PVP Trinket"] = "Abalorio JcJ"
+L["Panel Backdrop"] = "Fondo del Panel"
+L["Panel Height"] = "Altura del Panel"
+L["Panel Texture (Left)"] = "Textura del Panel Izquierdo"
+L["Panel Texture (Right)"] = "Textura del Panel Derecho"
+L["Panel Transparency"] = "Transparencia del Panel"
+L["Panel Width (Bags)"] = "Ancho del Panel (Bolsas)"
+L["Panel Width (Bank)"] = "Ancho del Panel (Banco)"
+L["Panel Width"] = "Anchura del Panel"
+L["Panels"] = "Paneles"
+L["Parent"] = true
+L["Party / Raid"] = true
+L["Party Only"] = true
+L["Party Pets"] = "Mascotas de Grupo"
+L["Party Targets"] = "Objetivos del Grupo"
+L["Per Row"] = "Por Fila"
+L["Percent"] = "Porcentaje"
+L["Personal"] = true
+L["Pet Name"] = true
+L["Pet"] = true
+L["PetTarget"] = true
+L["Petition Frame"] = "Petición"
+L["Pick Up Action Key"] = true
+L["Player Frame Aura Bars"] = true
+L["Player Health"] = true
+L["Player Out of Combat"] = true
+L["Player Target"] = true
+L["Player Titles"] = "Títulos de Jugador"
+L["Player in Combat"] = true
+L["Player"] = "Player"
+L["Plugin"] = true
+L["Poison Effect"] = true
+L["Portrait"] = "Retrato"
+L["Position Buffs on Debuffs"] = true
+L["Position Debuffs on Buffs"] = true
+L["Position of the Chat EditBox, if datatexts are disabled this will be forced to be above chat."] = "Posición del Cuadro de Edición del Chat. Si los textos de datos se deshabilitan éste se colocará arriba del chat."
+L["Position"] = "Posición"
+L["Power Threshold"] = true
+L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."] = "El texto de poder estará oculto en los objetivos PNJ, además el texto del nombre será fijado donde el texto de poder."
+L["Power"] = "Poder"
+L["Powers"] = "Poderes"
+L["Prevent the same messages from displaying in chat more than once within this set amount of seconds, set to zero to disable."] = "Previene que los mismos mensajes se muestren más de una vez en el chat dentro de un cierto número de segundos. Establécelo a cero para desactivar."
+L["Primary Texture"] = "Textura Primaria"
+L["Priority"] = "Prioridad"
+L["Private (Character Settings)"] = true
+L["Profession Bags"] = true
+L["Profile Name"] = true
+L["Profile Specific"] = true
+L["Profile imported successfully!"] = true
+L["Profile"] = "Perfile"
+L["Progress Bar"] = true
+L["Puts coordinates on the world map."] = true
+L["PvP Frames"] = "JcJ"
+L["PvP Icon"] = true
+L["PvP Queue"] = true
+L["PvP Text"] = true
+L["Quest Frames"] = "Misión"
+L["Quest Starter"] = true
+L["Quiver"] = true
+L["RAID_CONTROL"] = "Control de bandas"
+L["RL / ML Icons"] = true
+L["Raid Difficulty"] = true
+L["Raid Frame"] = "Banda"
+L["Raid Icon"] = "Icono de Banda"
+L["Raid Only"] = true
+L["Raid Pet"] = "Marcos de Banda con Mascotas"
+L["Raid-40"] = "Marcos de Banda de 40"
+L["Raid-Wide Sorting"] = true
+L["RaidDebuff Indicator"] = "Indicador de Perjuicios de Banda"
+L["Range"] = true
+L["Rapidly update the health, uses more memory and cpu. Only recommended for healing."] = "Actualizar la salud rápidamente, consume más memoria y cpu. Recomendado sólo para sanadores."
+L["Reaction Castbars"] = true
+L["Reaction Colors"] = true
+L["Reaction Type"] = true
+L["Reactions"] = "Reacciones"
+L["Ready Check Icon"] = true
+L["Realm Time"] = true
+L["Remaining / Max"] = true
+L["Remaining Time"] = true
+L["Remaining"] = "Restante"
+L["Reminder"] = true
+L["Remove Backdrop"] = "Quitar Fondo"
+L["Remove Name"] = true
+L["Remove Spell ID or Name"] = true
+L["Remove Spell"] = true
+L["Remove SpellID"] = "Eliminar ID de Hechizo"
+L["Remove a Name from the list."] = true
+L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."] = true
+L["Remove a spell from the filter."] = "Elimina un hechizo del filtro."
+L["Replace Blizzard Fonts"] = true
+L["Replaces the default Blizzard fonts on various panels and frames with the fonts chosen in the Media section of the ElvUI Options. NOTE: Any font that inherits from the fonts ElvUI usually replaces will be affected as well if you disable this. Enabled by default."] = true
+L["Reposition Window"] = "Rest. Marco"
+L["Require All"] = true
+L["Require Target"] = true
+L["Require holding the Alt key down to move cursor or cycle through messages in the editbox."] = true
+L["Reset Anchors"] = "Rest. Anclas"
+L["Reset Aura Filters"] = true
+L["Reset Editbox History"] = true
+L["Reset Filter"] = true
+L["Reset History"] = true
+L["Reset Priority"] = true
+L["Reset Zoom"] = true
+L["Reset all frames to their original positions."] = "Coloca todos los marcos en sus posiciones originales"
+L["Reset filter priority to the default state."] = true
+L["Reset the size and position of this frame."] = "Restaurar el tamaño y la posición de este marco."
+L["Rest Icon"] = "Icono de Descanso"
+L["Restore Bar"] = "Restaurar Barra"
+L["Restore Defaults"] = "Restaurar por Defecto"
+L["Restore the actionbars default settings"] = "Restaura las barras de acción a los ajustes predeterminados."
+L["Resurrect Icon"] = true
+L["Return filter to its default state."] = true
+L["Reverse Bag Slots"] = true
+L["Reverse Cooldown"] = true
+L["Reverse Style"] = true
+L["Reverse Toggle will enable Cooldown Text on this module when the global setting is disabled and disable them when the global setting is enabled."] = true
+L["Reverse Toggle"] = true
+L["Right Only"] = "Sólo el Derecho"
+L["Right Panel Height"] = true
+L["Right Panel Width"] = true
+L["Right to Left"] = true
+L["Right"] = "Derecha"
+L["RightClick Self-Cast"] = true
+L["Role Icon"] = "Icono de Rol"
+L["Run the installation process."] = "Ejecutar el proceso de instalación"
+L["Sanctuary"] = true
+L["Scale of the nameplate that is targetted."] = true
+L["Scale"] = true
+L["Scroll Interval"] = "Intervalo de Desplazamiento"
+L["Scroll Messages"] = true
+L["Search Syntax"] = true
+L["Search for a spell name inside of a filter."] = true
+L["Secondary Texture"] = "Textura Secundaria"
+L["Seconds remaining on the aura duration before the bar starts moving. Set to 0 to disable."] = true
+L["Seconds"] = "Segundos"
+L["Selected Text Color"] = true
+L["Selector Color"] = true
+L["Selector Style"] = true
+L["Securely Tanking"] = true
+L["Select Filter"] = "Seleccionar Filtro"
+L["Select Spell"] = "Seleccionar Hechizo"
+L["Select a profile to copy from/to."] = true
+L["Select a unit to copy settings from."] = "Selecciona una unidad desde la que copiar la configuración."
+L["Select the display method of the portrait."] = "Selecciona el método de despliegue del retrato."
+L["Sell Interval"] = true
+L["Send ADDON_ACTION_BLOCKED errors to the Lua Error frame. These errors are less important in most cases and will not effect your game performance. Also a lot of these errors cannot be fixed. Please only report these errors if you notice a Defect in gameplay."] = "Envia los errores ADDON_ACTION_BLOCKED al marco de errores de Lua. Esos errores en la mayoría de los casos son poco importantes y no afectan al rendimiento del juego. Muchos de esos errores no pueden ser subsanados. Por favor, reporta sólo esos errores si notas algún defecto que entorpezca el juego"
+L["Sends your current profile to your target."] = "Envía tu perfil actual a tu objetivo."
+L["Sends your filter settings to your target."] = "Envía los ajustes de tus filtros a tu objetivo."
+L["Separate Panel Sizes"] = true
+L["Seperate"] = "Separar"
+L["Set Settings to Default"] = true
+L["Set the alpha level of portrait when frame is overlayed."] = true
+L["Set the filter type. Blacklist will hide any auras in the list and show all others. Whitelist will show any auras in the filter and hide all others."] = true
+L["Set the font outline."] = "Establece el contorno de fuente."
+L["Set the font size for everything in UI. Note: This doesn't effect somethings that have their own seperate options (UnitFrame Font, Datatext Font, ect..)"] = "Establece el tamaño de la fuente para la interfaz. Nota: Esto no afecta elementos que tengan sus propias opciones (Marcos de Unidad, Textos de Datos, etc.)"
+L["Set the font size for unitframes."] = "Establece el tamaño de la fuente para los marcos de unidad."
+L["Set the order that the group will sort."] = "Establece el orden en que el grupo será organizado."
+L["Set the orientation of the UnitFrame."] = true
+L["Set the priority order of the spell, please note that prioritys are only used for the raid debuff module, not the standard buff/debuff module. If you want to disable set to zero."] = "Establece el orden de prioridad del hechizo, ten en cuenta que la prioridad sólo se usa para el módulo de perjuicios de banda, no para el módulo estandar de beneficios/perjuicios. 0 para desactivar."
+L["Set the size of the individual auras."] = "Establece el tamaño de las auras individuales."
+L["Set the size of your bag buttons."] = "Establece el tamaño de tus botones de la bolsa."
+L["Set the type of auras to show when a unit is a foe."] = "Establece el tipo de auras a mostrar cuando la unidad es enemiga."
+L["Set the type of auras to show when a unit is friendly."] = "Establece el tipo de auras a mostrar cuando la unidad es amistosa."
+L["Set to either stack nameplates vertically or allow them to overlap."] = true
+L["Sets the font instance's horizontal text alignment style."] = "Establece la alineación horizontal del texto."
+L["Share Current Profile"] = "Compartir Perfil Actual"
+L["Share Filters"] = "Compartir Filtros"
+L["Short (Whole Numbers)"] = true
+L["Short Channels"] = "Recortar Canales"
+L["Shortcut to 'Filters' section of the config."] = true
+L["Shortcut to global filters."] = true
+L["Shortcuts"] = true
+L["Shorten the channel names in chat."] = "Recorta los nombre de canal en el chat."
+L["Should tooltip be anchored to mouse cursor"] = true
+L["Show Aura From Other Players"] = "Mostrar Auras de Otros Jugadores"
+L["Show Auras"] = "Mostrar Auras"
+L["Show Bind on Equip/Use Text"] = true
+L["Show Both"] = "Mostrar Ambos"
+L["Show Coins"] = true
+L["Show Dispellable Debuffs"] = true
+L["Show Empty Buttons"] = true
+L["Show For DPS"] = true
+L["Show For Healers"] = true
+L["Show For Tanks"] = true
+L["Show Icon"] = true
+L["Show Junk Icon"] = true
+L["Show Quality Color"] = true
+L["Show Quest Icon"] = true
+L["Show When Not Active"] = "Mostrar Cuando No Esté Activo"
+L["Show an incoming heal prediction bar on the unitframe. Also display a slightly different colored bar for incoming overheals."] = "Muestra una barra de predicción de sanación en el marco de unidad. También muestra una barra ligeramente coloreada para sobresanaciones recibidas."
+L["Show the castbar icon desaturated if a spell is not interruptible."] = true
+L["Show/Hide Test Frame"] = true
+L["Side Arrows"] = true
+L["Size Override"] = "Sobrescribir Tamaño"
+L["Size and Positions"] = true
+L["Size of the indicator icon."] = "Tamaño del icono indicador."
+L["Size"] = "Tamaño"
+L["Skin Backdrop (No Borders)"] = true
+L["Skin Backdrop"] = "Apariencia del Fondo"
+L["Skin the blizzard chat bubbles."] = "Modificar la apariencia de las Burbujas de Chat de Blizzard"
+L["Skins"] = "Cubiertas"
+L["Small Panels"] = true
+L["Smaller World Map"] = true
+L["Smart Aura Position"] = true
+L["Smart Raid Filter"] = "Filtro de Banda Inteligente"
+L["Smart"] = true
+L["Smooth Bars"] = "Barras Suavizadas"
+L["Smooth"] = true
+L["Smoothing Amount"] = true
+L["Socket Frame"] = "Incrustación"
+L["Sort By"] = true
+L["Sort Direction"] = "Dirección de Ordenado"
+L["Sort Inverted"] = "Ordenado Invertido"
+L["Sort Method"] = "Método de Organización"
+L["Soul Bag"] = true
+L["Spaced"] = "Separadas"
+L["Spacing"] = true
+L["Spam Interval"] = "Intervalo de Spam"
+L["Spark"] = "Desatar"
+L["Spell/Item IDs"] = "IDs de Hechizo/Objeto"
+L["Split"] = true
+L["Stable"] = "Establo"
+L["Stack Counter"] = true
+L["Stack Text Position"] = true
+L["Stack Text X-Offset"] = true
+L["Stack Text Y-Offset"] = true
+L["Stack Threshold"] = true
+L["Start Near Center"] = "Comenzar Cerca del Centro"
+L["StatusBar Texture"] = "Textura de la Barra de Estado"
+L["Statusbar Fill Orientation"] = true
+L["Statusbar"] = true
+L["Sticky Chat"] = "Chat Pegajoso"
+L["Strata and Level"] = true
+L["Style Filter"] = true
+L["Style"] = "Estilo"
+L["Tab Font Outline"] = "Contorno de Fuente de la Pestaña"
+L["Tab Font Size"] = "Tamaño de Fuente de la Pestaña"
+L["Tab Font"] = "Fuente de la Pestaña"
+L["Tab Panel Transparency"] = "Transparencia del Panel de Pestañas"
+L["Tab Panel"] = "Panel de Pestañas"
+L["Tab Selector"] = true
+L["Tabard Frame"] = "Tabardos"
+L["Table"] = true
+L["Tank Target"] = "Objetivo del Tanque"
+L["Tank"] = "Tanque"
+L["Tapped"] = "Golpear"
+L["Target Indicator Color"] = true
+L["Target Info"] = true
+L["Target On Mouse-Down"] = "Apuntar al Presionar el Botón del Ratón"
+L["Target Scale"] = true
+L["Target units on mouse down rather than mouse up. \n\n|cffFF0000Warning: If you are using the addon 'Clique' you may have to adjust your clique settings when changing this."] = "Apuntar unidades al presionar el botón en lugar de soltarlo. \n\n|cffFF0000Advertencia: Si estás usando Clique es probable que tengas que modificar tus ajustes de Clique cuando cambies esta opción.|r"
+L["Target/Low Health Indicator"] = true
+L["TargetTarget"] = true
+L["TargetTargetTarget"] = true
+L["Targeted Glow"] = true
+L["Targeting"] = true
+L["Testing:"] = "Pruebas:"
+L["Text Fade"] = true
+L["Text Color"] = "Color de Texto"
+L["Text Font Size"] = "Tamaño de Fuente de Texto"
+L["Text Format"] = "Formato de Texto"
+L["Text Position"] = "Posición del Texto"
+L["Text Threshold"] = "Límite del Texto"
+L["Text Toggle On NPC"] = "Alternar Texto en PNJ"
+L["Text xOffset"] = "Desplazamiento X del Texto"
+L["Text yOffset"] = "Desplazamiento Y del Texto"
+L["Text"] = "Texto"
+L["Texture"] = "Textura"
+L["Textured Icon"] = "Icono Texturizado"
+L["Textures"] = "Texturas"
+L["The Portrait will overlay the Healthbar. This will be automatically happen if the Frame Orientation is set to Middle."] = true
+L["The Thin Border Theme option will change the overall apperance of your UI. Using Thin Border Theme is a slight performance increase over the traditional layout."] = true
+L["The amount of buttons to display per row."] = "Número de botones a mostrar por fila"
+L["The amount of buttons to display."] = "Número de botones a mostrar"
+L["The button you must hold down in order to drag an ability to another action button."] = "Tecla que debes mantener presionado para mover una habilidad a otro botón de acción."
+L["The debuff needs to reach this amount of stacks before it is shown. Set to 0 to always show the debuff."] = true
+L["The direction that the bag frames be (Horizontal or Vertical)."] = "La dirección que los marcos de bolsas tienen (Horizontal o Vertical)."
+L["The direction that the bag frames will grow from the anchor."] = "La dirección que los marcos de bolsas crecerán desde el punto de fijación."
+L["The direction the auras will grow and then the direction they will grow after they reach the wrap after limit."] = true
+L["The display format of the currency icons that get displayed below the main bag. (You have to be watching a currency for this to display)"] = "El formato de moneda que se muestra debajo de la bolsa principal (debes monitorear una divisa para que se muestre)."
+L["The display format of the money text that is shown at the top of the main bag."] = true
+L["The display format of the money text that is shown in the gold datatext and its tooltip."] = true
+L["The first button anchors itself to this point on the bar."] = "El primer botón se fija a este punto de la barra."
+L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."] = "La siguiente macro debe ser verdadera para que el grupo se muestre, además de cualquier filtro que ya exista."
+L["The font that appears on the text above players heads. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "Cambia la fuente del texto que aparece encima de las cabezas de los jugadores. |cffFF0000AVISO: Esto requiere que reinicies el juego o reconectes."
+L["The font that combat text will use. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "La fuente que usará el texto de combate. |cffFF0000ADVERTENCIA: Esto requiere un reinicio del juego o salir y entrar nuevamente para que este cambio surta efecto.|r"
+L["The font that the core of the UI will use."] = "La fuente que usará el núcleo de la interfaz."
+L["The font that the unitframes will use."] = "La fuente que usa el marco de unidad."
+L["The frame is not shown unless you mouse over the frame."] = "El marco no se muestra a menos que pases el ratón sobre él."
+L["The initial group will start near the center and grow out."] = "El grupo inicial comenzará cerca del centro y crecer."
+L["The minimum item level required for it to be shown."] = true
+L["The name you have selected is already in use by another element."] = "El nombre que has seleccionado ya está en uso por otro elemento."
+L["The object you want to attach to."] = "El objeto que quieres adjuntar a."
+L["The size of the action buttons."] = "El tamaño de los botones de acción."
+L["The size of the individual buttons on the bag frame."] = "El tamaño de los botones individuales en el marco de las bolsas"
+L["The size of the individual buttons on the bank frame."] = "El tamaño de los botones individuales en el marco del banco"
+L["The spacing between buttons."] = "Separación entre los botones."
+L["The spacing between the backdrop and the buttons."] = "El espacio entre el fondo y los botones."
+L["The texture that will be used mainly for statusbars."] = "La textura que se usará principalmente para las barras de estado."
+L["The unit prefixes you want to use when values are shortened in ElvUI. This is mostly used on UnitFrames."] = true
+L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."] = true
+L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."] = true
+L["Thin Border Theme"] = "Tema de Borde Delgado"
+L["Thin Borders"] = "Bordes Delgados"
+L["This dictates the size of the icon when it is not attached to the castbar."] = true
+L["This feature will allow you to transfer settings to other characters."] = "Esta característica te permitirá transferir ciertos ajustes a otros personajes."
+L["This is for Customized Icons in your Interface/Icons folder."] = true
+L["This opens the UnitFrames Color settings. These settings affect all unitframes."] = true
+L["This option allows the overlay to span the whole health, including the background."] = true
+L["This section will allow you to copy settings to a select module from or to a different profile."] = true
+L["This section will help reset specfic settings back to default."] = true
+L["This selects the Chat Frame to use as the output of ElvUI messages."] = true
+L["This setting controls the size of text in item comparison tooltips."] = true
+L["This setting will be updated upon changing stances."] = true
+L["This texture will get used on objects like chat windows and dropdown menus."] = "Esta textura se usará en objetos como las ventanas de chat y menús desplegables."
+L["This will override the global cooldown settings."] = true
+L["This will prevent the UI Scale Popup from being shown when changing the game window size."] = true
+L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."] = true
+L["Threat Display Mode"] = "Modo de Despliegue de Amenaza"
+L["Threat Health"] = true
+L["Threat Power"] = true
+L["Threat"] = "Amenaza"
+L["Threshold (in minutes) before text is shown in the HH:MM format. Set to -1 to never change to this format."] = true
+L["Threshold (in seconds) before text is shown in the MM:SS format. Set to -1 to never change to this format."] = true
+L["Threshold before text goes into decimal form. Set to -1 to disable decimals."] = true
+L["Threshold before text turns red and is in decimal form. Set to -1 for it to never turn red"] = "Umbral para que el texto se ponga rojo y esté en forma decimal. Establécelo en -1 para que nunca se ponga rojo"
+L["Threshold before the icon will fade out and back in. Set to -1 to disable."] = true
+L["Ticks"] = "Ticks"
+L["Time Format"] = true
+L["Time Indicator Colors"] = true
+L["Time Remaining Reverse"] = "Revertir Tiempo Restante"
+L["Time Remaining"] = "Tiempo Restante"
+L["Time To Hold"] = true
+L["Time xOffset"] = true
+L["Time yOffset"] = true
+L["Time"] = "Tiempo"
+L["Timestamp Color"] = true
+L["Toggle Anchors"] = "Reubicar Anclas"
+L["Toggle Off While In Combat"] = true
+L["Toggle On While In Combat"] = true
+L["Toggle Tutorials"] = "Ver/Ocultar Tutoriales"
+L["Toggle showing of the left and right chat panels."] = "Muestra/Oculta los paneles de chat izquierdo y derecho."
+L["Toggle the chat tab panel backdrop."] = "Muestra/oculta el fondo del panel de pestañas"
+L["Toggles the display of the actionbars backdrop."] = "Muestra/Oculta el fondo de las barras de acción."
+L["Tooltip Font Settings"] = true
+L["Top Arrow"] = "Top Flecha"
+L["Top Left"] = "Top Izquierda"
+L["Top Panel"] = "Panel Superior"
+L["Top Right"] = "Top Derecho"
+L["Top to Bottom"] = "De Arriba hacia Abajo"
+L["Top"] = true
+L["TopLeftMiniPanel"] = "Minimap TopLeft (Inside)"
+L["TopMiniPanel"] = "Minimap Top (Inside)"
+L["TopRightMiniPanel"] = "Minimap TopRight (Inside)"
+L["Totem"] = true
+L["Trainer Frame"] = "Entrenador"
+L["Transparency level when not in combat, no target exists, full health, not casting, and no focus target exists."] = true
+L["Transparent Backdrops"] = true
+L["Transparent Buttons"] = true
+L["Transparent"] = "Transparente"
+L["Triggers"] = true
+L["Turtle Color"] = "Color de Tortuga"
+L["Tutorial Frame"] = true
+L["URL Links"] = "Enlaces URL"
+L["Under Health Threshold"] = "Por debajo del umbral de salud"
+L["Under Power Threshold"] = "Por debajo del umbral de potencia"
+L["Uniform Threshold"] = true
+L["Unique Units"] = true
+L["Unit Prefix Style"] = true
+L["Unit Target"] = true
+L["Unit Type"] = true
+L["UnitFrames"] = "Marco de Unidad"
+L["Unlock various elements of the UI to be repositioned."] = "Desbloquea varios elementos de la interfaz para ser reubicados."
+L["Up"] = "Arriba"
+L["Usable"] = true
+L["Use Alt Key"] = true
+L["Use Class Color"] = true
+L["Use Custom Level"] = true
+L["Use Custom Strata"] = true
+L["Use Dead Backdrop"] = true
+L["Use Default"] = "Usar Predeterminado"
+L["Use Indicator Color"] = true
+L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."] = true
+L["Use Target Scale"] = true
+L["Use Threat Color"] = true
+L["Use class color for the names of players when they are mentioned."] = true
+L["Use coin icons instead of colored text."] = true
+L["Use drag and drop to rearrange filter priority or right click to remove a filter."] = true
+L["Use the Name Color of the unit for the Name Glow."] = true
+L["Use the custom backdrop color instead of a multiple of the main color."] = true
+L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."] = true
+L["Use thin borders on certain unitframe elements."] = true
+L["Use this backdrop color for units that are dead or ghosts."] = true
+L["Used as RaidDebuff Indicator"] = true
+L["Value Color"] = "Color de Dato"
+L["Value must be a number"] = "El valor debe ser un número"
+L["Vehicle Seat Indicator Size"] = "Tamaño del indicador del asiento del vehículo"
+L["Vehicle"] = "Vehículo"
+L["Vendor Gray Detailed Report"] = "Informe detallado del vendedor gris"
+L["Vendor Grays"] = "Vender Objetos Grises"
+L["Version"] = "Versión"
+L["Vertical Fill Direction"] = "Dirección de relleno vertical"
+L["Vertical Spacing"] = "Espaciado Vertical"
+L["Vertical"] = "Vertical"
+L["Visibility State"] = "Estado de Visibilidad"
+L["Visibility"] = "Visibilidad"
+L["Watch Frame"] = true
+L["What point to anchor to the frame you set to attach to."] = "Punto de fijación a utilizar del marco que se va a sujetar."
+L["What to attach the buff anchor frame to."] = "Dónde sujetar el fijador del marco de beneficios."
+L["What to attach the debuff anchor frame to."] = "Dónde sujetar el fijador del marco de perjuicios."
+L["When enabled active buff icons will light up instead of becoming darker, while inactive buff icons will become darker instead of being lit up."] = true
+L["When enabled it will only show spells that were added to the filter using a spell ID and not a name."] = true
+L["When in a raid group display if anyone in your raid is targeting the current tooltip unit."] = "Cuando estás en una banda muestra si alguien en tu banda tiene marcado como objetivo a la unidad actual de la descripción emergente."
+L["When inside a battleground display personal scoreboard information on the main datatext bars."] = "Cuando estás dentro de un campo de batalla muestra la puntuación personal en las barras de texto principales."
+L["When opening the Chat Editbox to type a message having this option set means it will retain the last channel you spoke in. If this option is turned off opening the Chat Editbox should always default to the SAY channel."] = "Cuando abres el Cuadro de Edición del chat para escribir un mensaje teniendo esta opción activa significa que recordará el último canal en el que habló. Si esta opción esta desactivada siempre hablarás por defecto en el canal DECIR."
+L["When true, the header includes the player when not in a raid."] = "Cuando está activo, la cabecera incluye al jugador cuando no está en una banda."
+L["When you go AFK display the AFK screen."] = "Cuando vayas AFK, visualice la pantalla AFK."
+L["Whitelist"] = "Lista Blanca"
+L["Width Multiplier"] = "Multiplicador de Anchura"
+L["Width"] = "Anchura"
+L["Will attempt to sell another item in set interval after previous one was sold."] = true
+L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."] = true
+L["Word Wrap"] = "Ajuste de Línea"
+L["World Map Coordinates"] = "Coordenadas del Mapa Mundial"
+L["World State Frame"] = true
+L["Wrap After"] = "Auras por Fila/Columna"
+L["X-Offset"] = "DesplazamientoX"
+L["Y-Offset"] = "DesplazamientoY"
+L["You do not need to use 'Is Casting Anything' or 'Is Channeling Anything' for these spells to trigger."] = true
+L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."] = "No puedes eliminar un hechizo de un filtro por defecto que no ha sido personalizado. Establece el hechizo a falso."
+L["You must be targeting a player."] = "Debes enfocar a un jugador."
+L["You need to hold this modifier down in order to blacklist an aura by right-clicking the icon. Set to None to disable the blacklist functionality."] = true
+L["Your Auras First"] = "Tus Auras Primero"
+L["xOffset"] = "DesplazamientoX"
+L["yOffset"] = "DesplazamientoY"
+
+L["ACTIONBARS_DESC"] = "Modify the actionbar settings."
+L["AURAS_DESC"] = "Configura los iconos de las auras que aparecen cerca del minimapa."
+L["BAGS_DESC"] = "Ajusta las opciones de las bolsas para ElvUI."
+L["CHAT_DESC"] = "Configura los ajustes del chat para ElvUI."
+L["COOLDOWN_DESC"] = "Adjust Cooldown Settings."
+L["DATATEXT_DESC"] = "Configura el despliegue en pantalla de los textos de datos."
+L["ELVUI_DESC"] = "ElvUI es un addon que reemplaza la interfaz completa de World of Warcraft."
+L["NAMEPLATE_DESC"] = "Modifica las opciones de la placa de nombre"
+L["PANEL_DESC"] = "Ajusta el tamaño de los paneles izquierdo y derecho. Esto afectará las ventanas de chat y las bolsas."
+L["SKINS_DESC"] = "Configura los Ajustes de Cubiertas."
+L["TOGGLESKIN_DESC"] = "Activa/Desactiva esta cubierta."
+L["TOOLTIP_DESC"] = "Configuración para las Descripciones Emergentes."
+L["UNITFRAME_DESC"] = "Modify the unitframe settings."
+L["SEARCH_SYNTAX_DESC"] = [=[With the new addition of LibItemSearch, you now have access to much more advanced item searches. The following is a documentation of the search syntax. See the full explanation at: https://github.com/Jaliborc/LibItemSearch-1.2/wiki/Search-Syntax.
+
+Specific Searching:
+ • q:[quality] or quality:[quality]. For instance, q:epic will find all epic items.
+ • l:[level], lvl:[level] or level:[level]. For example, l:30 will find all items with level 30.
+ • t:[search], type:[search] or slot:[search]. For instance, t:weapon will find all weapons.
+ • n:[name] or name:[name]. For instance, typing n:muffins will find all items with names containing "muffins".
+ • s:[set] or set:[set]. For example, s:fire will find all items in equipment sets you have with names that start with fire.
+ • r:[level], reg:[level], rl:[level], regl:[level] or reqlvl:[level]. For example, reqlvl:30 will find all items that require level 30.
+ • tt:[search], tip:[search] or tooltip:[search]. For instance, tt:binds will find all items that can be bound to account, on equip, or on pickup.
+
+
+Search Operators:
+ • ! : Negates a search. For example, !q:epic will find all items that are NOT epic.
+ • | : Joins two searches. Typing q:epic | t:weapon will find all items that are either epic OR weapons.
+ • & : Intersects two searches. For instance, q:epic & t:weapon will find all items that are epic AND weapons
+ • >, <, <=, => : Performs comparisons on numerical searches. For example, typing lvl: >30 will find all items with level HIGHER than 30.
+
+
+The following search keywords can also be used:
+ • soulbound, bound, bop : Bind on pickup items.
+ • bou : Bind on use items.
+ • boe : Bind on equip items.
+ • boa : Bind on account items.
+ • quest : Quest bound items.]=]
+
+L["TEXT_FORMAT_DESC"] = [=[Proporciona una cadena para cambiar el formato de texto.
+
+Ejemplos:
+[namecolor][name] [difficultycolor][smartlevel] [shortclassification]
+[healthcolor][health:current-max]
+[powercolor][power:current]
+
+Formatos de Salud / Poder:
+'current' - cantidad actual
+'percent' - cantidad porcentual
+'current-max' - cantidad actual seguido de cantidad máxima, sólo se mostrará la máxima si la actual es igual a la máxima
+'current-percent' - cantidad actual seguido de porcentaje
+'current-max-percent' - cantidad actual, cantidad máxima y porcentaje, sólo se mostrará la máxima si la actual es igual a la máxima
+'deficit' - muestra el valor de déficit, no muestra nada si no hay déficit
+
+Formatos de Nombre:
+'name:short' - Nombre restringido a 10 caracteres
+'name:medium' - Nombre restringido a 15 caracteres
+'name:long' - Nombre restringido a 20 caracteres
+
+Para desactivarlo dejar el campo en blanco, si necesitas más información visita https://www.tukui.org/forum/viewtopic.php?t=6]=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to page differently.
+ Example: '[combat] 2;']=] ] = [=[Esto funciona como una macro. Puedes ejecutar diferentes situaciones para paginar la barra de acción de forma diferente.
+ Ejemplo: '[combat] 2;']=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to show/hide differently.
+ Example: '[combat] show;hide']=] ] = [=[Esto funciona como una macro. Puede ejecutar diferentes situaciones para mostrar u ocultar la barra de acción de forma diferente.
+ Ejemplo: '[combat] show;hide']=]
+
+L[ [=[Specify a filename located inside the World of Warcraft directory. Textures folder that you wish to have set as a panel background.
+
+Please Note:
+-The image size recommended is 256x128
+-You must do a complete game restart after adding a file to the folder.
+-The file type must be tga format.
+
+Example: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Or for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here.]=] ] = [=[Especifica un archivo ubicado en el directorio texture de World of Warcraft que deseas tener establecido como fondo de panel.
+
+Nota:
+-El tamaño de imagen recomendada es 256x128
+-Debes reiniciar el juego completamente después de agregar un archivo a la carpeta.
+-El archivo debe ser formato tga.
+
+Ejemplo: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+O también puedes simplemente colocar un archivo tga en la carpeta de WoW, y escribir aquí el nombre del archivo.]=]
+
+-- Global Strings
+L["ACHIEVEMENTS"] = "Logros"
+L["ALT_KEY_TEXT"] = "ALT"
+L["ARENA"] = "Arena"
+L["AUCTIONS"] = "Subastas"
+L["BAGSLOT"] = "Bolsa"
+L["BARBERSHOP"] = "Peluquería"
+L["BATTLEGROUND"] = "Campo de batalla"
+L["BATTLEFIELDS"] = "Campos de batalla"
+L["BLOCK"] = "Bloqueo"
+L["BUFFOPTIONS_LABEL"] = "Beneficios y perjuicios"
+L["CLASS"] = "Clase"
+L["CHANNEL"] = "Canal"
+L["COLOR"] = "Color"
+L["COLORS"] = "Colores"
+L["COMBAT"] = "Combate"
+L["COMBAT_TEXT_RUNE_BLOOD"] = "Blood Rune"
+L["COMBAT_TEXT_RUNE_DEATH"] = "Death Rune"
+L["COMBAT_TEXT_RUNE_FROST"] = "Frost Rune"
+L["COMBAT_TEXT_RUNE_UNHOLY"] = "Unholy Rune"
+L["COMBO_POINTS"] = "|4Punto:Puntos; de combo"
+L["CTRL_KEY"] = "CTRL"
+L["CUSTOM"] = "Pers."
+L["DAMAGER"] = "Daño"
+L["DEFAULT"] = "Predeterminado"
+L["DELETE"] = "Eliminar"
+L["DISABLE"] = "Desactivar"
+L["DRESSUP_FRAME"] = "Probador"
+L["DUNGEON_DIFFICULTY"] = "Dificultad de mazmorra"
+L["DUNGEONS"] = "Mazmorras"
+L["EMOTE"] = "Emoción"
+L["ENEMY"] = "Enemigo"
+L["ENERGY"] = "Energía"
+L["FACTION_STANDING_LABEL1"] = "Odiado"
+L["FACTION_STANDING_LABEL2"] = "Hostil"
+L["FACTION_STANDING_LABEL3"] = "Adverso"
+L["FACTION_STANDING_LABEL4"] = "Neutral"
+L["FACTION_STANDING_LABEL5"] = "Amistoso"
+L["FACTION_STANDING_LABEL6"] = "Honorable"
+L["FACTION_STANDING_LABEL7"] = "Venerado"
+L["FACTION_STANDING_LABEL8"] = "Exaltado"
+L["FILTERS"] = "Filtros"
+L["FLIGHT_MAP"] = "Mapa de vuelo"
+L["FOCUS"] = "Enfoque"
+L["FONT_SIZE"] = "Tamaño de la fuente"
+L["FRIEND"] = "Amigo"
+L["FRIENDS"] = "Amigos"
+L["GROUP"] = "Group"
+L["GUILD"] = "Hermandad"
+L["GUILD_BANK"] = "Banco de hermandad"
+L["HAPPINESS"] = "Felicidad"
+L["HEALER"] = "Sanador"
+L["HEALTH"] = "Salud"
+L["HIDE"] = "Ocultar"
+L["INSCRIPTION"] = "Inscripción"
+L["INSPECT"] = "Inspeccionar"
+L["INTERFACE_OPTIONS"] = "Opciones de interfaz"
+L["INTERRUPTED"] = "Interrumpido"
+L["ITEM_BIND_QUEST"] = "Objeto de misión"
+L["ITEMS"] = "Objetos"
+L["KEY_BINDINGS"] = "Teclado"
+L["LANGUAGE"] = "Idioma"
+L["LEAVE_VEHICLE"] = "Leave Vehicle"
+L["LEVEL"] = "Nivel"
+L["LOCK_ACTIONBAR_TEXT"] = "Bloquear barras de acción"
+L["LOOT"] = "Loot"
+L["MACROS"] = "Macros"
+L["MAIL_LABEL"] = "Correo"
+L["MANA"] = "Maná"
+L["MAP_FADE_TEXT"] = "Atenuar mapa al moverse"
+L["MERCHANT"] = "Merchant"
+L["MINIMAP_LABEL"] = "Minimapa"
+L["MISCELLANEOUS"] = "Miscelánea"
+L["NAME"] = "Nombre"
+L["NONE"] = "Ninguno"
+L["OFFICER"] = "Oficial"
+L["OPACITY"] = "Opacidad"
+L["OPTION_TOOLTIP_ACTION_BUTTON_USE_KEY_DOWN"] = "Los atajos de los botones de acción responderán al pulsar una tecla y no al soltarla."
+L["OPTION_TOOLTIP_TIMESTAMPS"] = "Selecciona el formato de la hora para los mensajes de chat."
+L["PARTY"] = "Grupo"
+L["PET"] = "Mascota"
+L["PLAYER"] = "Jugador"
+L["PLAYER_DIFFICULTY1"] = "Normal"
+L["PLAYER_DIFFICULTY2"] = "Heroic"
+L["RAGE"] = "Ira"
+L["RAID"] = "Banda"
+L["RAID_TARGET_1"] = "Estrella"
+L["RAID_TARGET_2"] = "Círculo"
+L["RAID_TARGET_3"] = "Diamante"
+L["RAID_TARGET_4"] = "Triángulo"
+L["RAID_TARGET_5"] = "Luna"
+L["RAID_TARGET_6"] = "Cuadrado"
+L["RAID_TARGET_7"] = "Cruz"
+L["RAID_TARGET_8"] = "Calavera"
+L["REPUTATION"] = "Reputación"
+L["ROLE"] = "Función"
+L["RUNIC_POWER"] = "Poder rúnico"
+L["SAY"] = "Hablar"
+L["SHIFT_KEY"] = "MAYÚS"
+L["SHORT"] = "Corto"
+L["SHOW"] = "Mostrar"
+L["SPEED"] = "Velocidad"
+L["SPELLBOOK"] = "Hechizos"
+L["TALENTS"] = "Talentos"
+L["TANK"] = "Tanque"
+L["TARGET"] = "Objetivo"
+L["TIMEMANAGER_TITLE"] = "Reloj"
+L["TIMESTAMPS_LABEL"] = "Hora de chat"
+L["TRADE"] = "Comerciar"
+L["TRADESKILLS"] = "Hab. comerciales"
+L["TUTORIAL_TITLE47"] = "Totem Bar"
+L["UI_SCALE"] = "Tamaño de la IU"
+L["UNIT_NAMEPLATES_TYPES"] = "Comportamiento placas de nombre"
+L["UNIT_NAMEPLATES_TYPE_1"] = "Solapar placas de nombre"
+L["UNIT_NAMEPLATES_TYPE_2"] = "Apilar placas de nombre"
+L["WHISPER"] = "Susurrar"
+L["WORLD_MAP"] = "Mapa"
+L["XPBAR_LABEL"] = "Barra de experiencia"
+L["YELL"] = "Gritar"
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Locales/frFR.lua b/ElvUI_OptionsUI/Locales/frFR.lua
new file mode 100644
index 0000000..7f75c5f
--- /dev/null
+++ b/ElvUI_OptionsUI/Locales/frFR.lua
@@ -0,0 +1,1388 @@
+-- French localization file for frFR.
+local L = ElvUI[1].Libs.ACL:NewLocale("ElvUI", "frFR")
+
+L["%s and then %s"] = "%s et alors %s"
+L["2D"] = "2D"
+L["3D"] = "3D"
+L["AFK Mode"] = "Mode ABS"
+L["ANCHOR_CURSOR"] = true
+L["ANCHOR_CURSOR_LEFT"] = true
+L["ANCHOR_CURSOR_RIGHT"] = true
+L["Abbreviation"] = true
+L["Above Chat"] = "En-dessus du Chat"
+L["Above"] = "Au-dessus"
+L["Accept Invites"] = "Invitations automatiques"
+L["Action Paging"] = "Pagination d'action"
+L["ActionBars"] = "Barres d'actions"
+L["Actions"] = "Actions"
+L["Add Item or Search Syntax"] = "Ajouter un élément ou une syntaxe pour la recherche"
+L["Add Name"] = true
+L["Add Regular Filter"] = "Ajouter un filtre"
+L["Add Special Filter"] = "Ajouter un filtre spécial"
+L["Add Spell ID or Name"] = true
+L["Add SpellID"] = "Ajouter l'identifiant d'un sort"
+L["Add a Name to the list."] = true
+L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."] = true
+L["Add a spell to the filter."] = "Ajouter un sort au filtre."
+L["Add an item or search syntax to the ignored list. Items matching the search syntax will be ignored."] = true
+L["Additional Power Text"] = true
+L["Additional spacing between each individual group."] = true
+L["Additive Blend"] = true
+L["Adjust the height of your right chat panel."] = "Ajuste la hauteur de la fenêtre de discussion de droite."
+L["Adjust the position of the threat bar to either the left or right datatext panels."] = "Ajustez la position de la barre de menace sur le panel des textes d'informations à gauche ou à droite."
+L["Adjust the size of the minimap."] = "Ajuster la taille de la minicarte."
+L["Adjust the width of the bag frame."] = "Ajuster la largeur de la fenêtre du sac."
+L["Adjust the width of the bank frame."] = "Ajuster la largeur de la fenêtre du sac de banque."
+L["Adjust the width of your right chat panel."] = "Ajuste la largeur de la fenêtre de discussion de droite."
+L["Alert Frames"] = "Fenêtre d'Alerte"
+L["Alerts"] = "Alertes"
+L["Allow LBF to handle the skinning of this element."] = "Autoriser LBF à gérer l'habillage de cet élement."
+L["Allowed Combat Repeat"] = "Répétition des combats autorisé"
+L["Alpha Fading"] = true
+L["Alpha Key"] = true
+L["Alpha channel is taken from the color option."] = true
+L["Alpha"] = "Transparence"
+L["Always Display"] = "Toujours afficher"
+L["Always Hide"] = "Toujours masqué"
+L["Always Show Realm"] = true
+L["Always Show Target Health"] = true
+L["Ammo Pouch"] = true
+L["An X offset (in pixels) to be used when anchoring new frames."] = "Un décalage X (en pixels) à utiliser lors d'un ancrage d'une nouvelle fenêtre."
+L["An Y offset (in pixels) to be used when anchoring new frames."] = "Un décalage Y (en pixels) à utiliser lors d'un ancrage d'une nouvelle fenêtre."
+L["Anchor Point"] = "Point d'ancrage"
+L["Announce Interrupts"] = "Annoncer les interruptions"
+L["Announce when you interrupt a spell to the specified chat channel."] = "Annonce quand vous interrompez un sort dans le canal de chat spécifié."
+L["Applies the font and font size settings throughout the entire user interface. Note: Some font size settings will be skipped due to them having a smaller font size by default."] = true
+L["Applies the primary texture to all statusbars."] = "Appliquer les textures à toutes les barres de statut"
+L["Apply Font To All"] = "Appliquer la police partout"
+L["Apply Texture To All"] = "Appliquer la texture partout"
+L["Apply this filter if a buff has remaining time greater than this. Set to zero to disable."] = true
+L["Apply this filter if a buff has remaining time less than this. Set to zero to disable."] = true
+L["Apply this filter if a debuff has remaining time greater than this. Set to zero to disable."] = true
+L["Apply this filter if a debuff has remaining time less than this. Set to zero to disable."] = true
+L["Are you sure you want to reset ActionBars settings?"] = true
+L["Are you sure you want to reset Auras settings?"] = true
+L["Are you sure you want to reset Bags settings?"] = true
+L["Are you sure you want to reset Chat settings?"] = true
+L["Are you sure you want to reset Cooldown settings?"] = true
+L["Are you sure you want to reset DataBars settings?"] = true
+L["Are you sure you want to reset DataTexts settings?"] = true
+L["Are you sure you want to reset General settings?"] = true
+L["Are you sure you want to reset NamePlates settings?"] = true
+L["Are you sure you want to reset Tooltip settings?"] = true
+L["Are you sure you want to reset UnitFrames settings?"] = true
+L["Arena Frame"] = true
+L["Arena Registrar"] = true
+L["Arena"] = "Arène"
+L["Ascending or Descending order."] = "Ordre ascendant ou descendant."
+L["Ascending"] = "Ascendant"
+L["Assist Target"] = 'Cible de soutien'
+L["Assist"] = true
+L["At what point should the text be displayed. Set to -1 to disable."] = "A quel moment le texte devrait être affiché. Mettre à -1 pour désactiver."
+L["Attach Text To"] = "Attacher le texte à"
+L["Attach To"] = "Attacher à"
+L["Attempt to create URL links inside the chat."] = "Tentative pour créer un lien URL dans les fenêtres de discussion."
+L["Attempt to lock the left and right chat frame positions. Disabling this option will allow you to move the main chat frame anywhere you wish."] = "Tentative pour verrouiller les positions gauche et droite du cadre de discussion. La désactivation de cette option vous permet de déplacer la fenêtre de discussion principale où vous le souhaitez."
+L["Attempt to support eyefinity/nvidia surround."] = "Tente de supporter eyefinity/nvidia surround."
+L["Aura Bars"] = "Barre d'auras"
+L["Aura Filters"] = "Filtres d'auras"
+L["Auto Greed/DE"] = "Dez / Cupidité Auto"
+L["Auto Hide"] = true
+L["Auto Repair"] = "Réparation automatique"
+L["Auto-Hide"] = 'Masquer Automatiquement'
+L["Automatic"] = "Automatique"
+L["Automatically accept invites from guild/friends."] = "Accepter automatiquement les invitations venant d'amis / joueurs de la guilde."
+L["Automatically hide the objetive frame during boss or arena fights."] = true
+L["Automatically repair using the following method when visiting a merchant."] = "Répare automatiquement votre équipement chez le marchand selon le mode de réparation sélectionné."
+L["Automatically select greed or disenchant (when available) on green quality items. This will only work if you are the max level."] = "Choisi automatiquement la cupidité ou le désenchantement (quand il est disponible) sur les objets inhabituels (vert). Ceci ne fonctionne que si vous êtes au niveau maximum."
+L["Automatically vendor gray items when visiting a vendor."] = "Vendre automatiquement les objets gris quand vous rendez visite à un marchand."
+L["Available Tags"] = true
+L["BG Map"] = "Carte Champs de bataille"
+L["BG Score"] = "Scores Champs de bataille"
+L["BINDING_HEADER_RAID_TARGET"] = "Marqueurs de cible"
+L["BOSS"] = true
+L["Backdrop Color"] = "Couleur de fond"
+L["Backdrop Faded Color"] = "Couleur de fond estompé"
+L["Backdrop Spacing"] = "Espacement du fond"
+L["Backdrop color of transparent frames"] = "Couleur de fond pour les cadres estompés."
+L["Backdrop"] = "Fond"
+L["Background Glow"] = "Brillance du fond"
+L["Bad Color"] = true
+L["Bad Scale"] = true
+L["Bad Transition Color"] = true
+L["Bad"] = "Mauvais"
+L["Bag 1"] = true
+L["Bag 2"] = true
+L["Bag 3"] = true
+L["Bag 4"] = true
+L["Bag Sorting"] = "Tri des sacs"
+L["Bag Spacing"] = true
+L["Bag"] = true
+L["Bag-Bar"] = "Barre des sacs"
+L["Bags Only"] = "Sacs seulement"
+L["Bags/Bank"] = "Sacs / banque"
+L["Bank 1"] = true
+L["Bank 2"] = true
+L["Bank 3"] = true
+L["Bank 4"] = true
+L["Bank 5"] = true
+L["Bank 6"] = true
+L["Bank 7"] = true
+L["Bank Only"] = "Banque seulement"
+L["Bar Direction"] = "Direction de la barre"
+L["Bars will transition smoothly."] = "La transitions des barres seront fluides."
+L["Battleground Texts"] = "Textes des champs de bataille"
+L["Begin a new row or column after this many auras."] = "Commencer une nouvelle ligne ou colonne après cette limite d'auras."
+L["Below Chat"] = "En-dessous du Chat"
+L["Below"] = "En dessous"
+L["Blacklist Modifier"] = true
+L["Blacklist"] = "Liste noire"
+L["Blend Mode"] = true
+L["Blend"] = true
+L["BlizzUI Improvements"] = true
+L["Blizzard Style"] = "Style Blizzard"
+L["Blizzard"] = true
+L["Block Combat Click"] = "Empêcher le clic en combat"
+L["Block Combat Hover"] = "Empêcher le survol en combat"
+L["Block Mouseover Glow"] = true
+L["Block Target Glow"] = true
+L["Blocks all click events while in combat."] = "Empêcher tous les clics d'évenements durant le combat."
+L["Blocks datatext tooltip from showing in combat."] = "Empêcher l'affichage des infobulles des textes d'informations en combat."
+L["Border Color"] = "Couleur de la bordure"
+L["Border Glow"] = true
+L["Border"] = "Bordure"
+L["Borders"] = "Bordures"
+L["Both"] = "Les deux"
+L["Bottom Left"] = "En bas à gauche"
+L["Bottom Panel"] = "Bandeau en bas"
+L["Bottom Right"] = "En bas à droite"
+L["Bottom to Top"] = "Du bas vers le haut"
+L["Bottom"] = "En bas"
+L["BottomLeftMiniPanel"] = "Minicarte en en bas à gauche (intérieur)"
+L["BottomMiniPanel"] = "Minicarte en bas (intérieur)"
+L["BottomRightMiniPanel"] = "Minicarte en bas à droite (intérieur)"
+L["Buff Indicator"] = "Indicateur d'amélioration"
+L["Button Size (Bag)"] = "Taille des boutons (Sac)"
+L["Button Size (Bank)"] = "Taille des boutons (Banque)"
+L["Button Size"] = "Taille des boutons"
+L["Button Spacing"] = "Espacement des boutons"
+L["Buttons Per Row"] = "Boutons par ligne"
+L["Buttons"] = "Boutons"
+L["By Type"] = "Par Catégorie"
+L["Calendar Frame"] = "Fenêtre du Calendrier"
+L["Cast Bar"] = "Barre d'incantation"
+L["Cast Color"] = "Couleur d'incantation"
+L["Cast No Interrupt Color"] = true
+L["Cast Time Format"] = true
+L["Castbar"] = "Barre d'incantation"
+L["Casting"] = "Incantation"
+L["Center"] = "Centrer"
+L["Change settings for the display of the location text that is on the minimap."] = "Modifier les paramètres pour l'affichage du texte d'emplacement sur la minicarte."
+L["Change the alpha level of the frame."] = "Changer le niveau alpha de la fenêtre."
+L["Channel Alerts"] = true
+L["Change the width and controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Channel Time Format"] = true
+L["Character Frame"] = "Fenêtre du Personnage"
+L["Chat Bubble Names"] = true
+L["Chat Bubbles Style"] = "Style des bulles de discussion"
+L["Chat Bubbles"] = "Bulles de discussion"
+L["Chat EditBox Position"] = "Position de la fenêtre de saisie du Chat"
+L["Chat Output"] = true
+L["Check these to only have the filter active in certain difficulties. If none are checked, it is active in all difficulties."] = true
+L["CheckBox Skin"] = true
+L["Choose Export Format"] = "Choisissez le format d'exportation"
+L["Choose UIPARENT to prevent it from hiding with the unitframe."] = true
+L["Choose What To Export"] = "Choisissez quoi exporter"
+L["Choose when you want the tooltip to show in combat. If a modifer is chosen, then you need to hold that down to show the tooltip."] = true
+L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."] = true
+L["Class Backdrop"] = "Fond selon la classe"
+L["Class Castbars"] = "Barres d'incantation selon la classe"
+L["Class Color Mentions"] = "Colorer les mentions suivant la classe"
+L["Class Color Override"] = 'Remplacer les couleurs de classes'
+L["Class Health"] = "Santé selon la Classe"
+L["Class Power"] = "Énergie selon la Classe"
+L["Class Resources"] = "Ressources des Classes"
+L["Class Totems"] = "Barre des totems"
+L["Clear Filter"] = true
+L["Clear Search On Close"] = "Effacer la recherche lors de la fermeture"
+L["Click Through"] = "Clic à travers"
+L["Clickable Height"] = "Hauteur cliquable"
+L["Clickable Size"] = true
+L["Clickable Width / Width"] = "Largeur cliquable / Largeur"
+L["Coding:"] = "Codage :"
+L["Color Keybind Text when Out of Range, instead of the button."] = true
+L["Color Keybind Text"] = true
+L["Color Override"] = true
+L["Color Turtle Buffs"] = "Colore les améliorations 'Turtle'"
+L["Color all buffs that reduce the unit's incoming damage."] = "Colorer toutes les améliorations réduisant les dégâts entrants de l'unité."
+L["Color aurabar debuffs by type."] = "Colore les affaiblissement de la barre d'auras par catégorie."
+L["Color by Value"] = true
+L["Color castbars by the class of player units."] = true
+L["Color castbars by the reaction type of non-player units."] = true
+L["Color health by amount remaining."] = "Colore le cadre selon la vie restante."
+L["Color health by classcolor or reaction."] = "Colore la vie par la couleur de la classe ou par l'aggro."
+L["Color health by threat status."] = true
+L["Color of the actionbutton when not usable."] = "Couleur du bouton d'action quand inutilisable"
+L["Color of the actionbutton when out of power (Mana, Rage)."] = "Couleur du bouton d'action quand il n'y a pas ressource (Mana, Rage)."
+L["Color of the actionbutton when out of range."] = "Couleur du bouton d'action quand hors de portée."
+L["Color of the actionbutton when usable."] = "Couleur du bouton d'action quand utilisable"
+L["Color power by classcolor or reaction."] = "Colore l'énergie de la classe par la couleur de la classe ou par l'aggro."
+L["Color power by threat status."] = true
+L["Color some texts use."] = "Couleur utilisée par les Textes d'informations."
+L["Color the health backdrop by class or reaction."] = "Colore l'arrière-plan de la barre de vie par la couleur de la classe ou par l'aggro."
+L["Color the unit healthbar if there is a debuff that can be dispelled by you."] = "Colore la barre de vie de l'unité qui peut être dissipé par vous-même."
+L["Color when the text is about to expire"] = "Couleur lorsque le texte est sur le point d'expirer."
+L["Color when the text is in the days format."] = "Couleur quand le texte est exprimé en jours."
+L["Color when the text is in the hours format."] = "Couleur quand le texte est exprimé en heure."
+L["Color when the text is in the minutes format."] = "Couleur quand le texte est exprimé en minute."
+L["Color when the text is in the seconds format."] = "Couleur quand le texte est exprimé en seconde."
+L["Colored Icon"] = "Icône Coloré"
+L["Coloring (Specific)"] = "Coloration (Spécifique)"
+L["Coloring"] = "Coloration"
+L["Colorize Selected Text"] = true
+L["Colors the border according to the Quality of the Item."] = true
+L["Combat Icon"] = "Icône de combat"
+L["Combat Override Key"] = true
+L["CombatText Font"] = "Police des textes de combat"
+L["Combo Point"] = "Points de combo"
+L["Comparison Font Size"] = true
+L["Condensed"] = "Condensé"
+L["Configure Auras"] = "Configure les Auras"
+L["Control enemy nameplates toggling on or off when in combat."] = true
+L["Control friendly nameplates toggling on or off when in combat."] = true
+L["Controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Controls the amount of decimals used in values displayed on elements like NamePlates and UnitFrames."] = true
+L["Controls the speed at which smoothed bars will be updated."] = true
+L["Controls how many seconds of inactivity has to pass before chat is faded."] = true
+L["Cooldown Orientation"] = true
+L["Cooldown Text"] = "Texte temps de recharge"
+L["Cooldowns"] = true
+L["Copy From"] = "Copier depuis"
+L["Copy Settings From"] = "Copier les options de"
+L["Copy settings from another unit."] = "Copier les options d'une autre unité"
+L["Core |cff1784d1E|r|cffe5e3e3lvUI|r options."] = true
+L["Count Font Size"] = "Taille du texte du décompte"
+L["Count xOffset"] = "Décalage X de la pile"
+L["Count yOffset"] = "Décalage Y de la pile"
+L["Create Custom Text"] = "Créer un texte personnalisé"
+L["Create Filter"] = "Créer un filtre"
+L["Create a filter, once created a filter can be set inside the buffs/debuffs section of each unit."] = "Créer un filtre, chaque filtre créé peut être configuré dans la section Amélioration / Affaiblissements de chaque unité."
+L["Credits"] = "Crédits"
+L["Crop Icons"] = true
+L["Currency Format"] = "Format monétaire"
+L["Current - Max | Percent"] = true
+L["Current - Max"] = "Actuel - Max"
+L["Current - Percent (Remaining)"] = "Actuel - Pourcentage (restant)"
+L["Current - Percent"] = "Actuel - Pourcent"
+L["Current - Remaining"] = "Actuel - Restant"
+L["Current / Max"] = "Actuel / Max"
+L["Current Level"] = "Niveau actuel"
+L["Current"] = "Actuel"
+L["Curse Effect"] = true
+L["Cursor Anchor Offset X"] = true
+L["Cursor Anchor Offset Y"] = true
+L["Cursor Anchor Type"] = true
+L["Cursor Anchor"] = "Ancrage sur le curseur"
+L["Custom Backdrop"] = true
+L["Custom Color"] = true
+L["Custom Dead Backdrop"] = "Fond 'mort' personnalisé"
+L["Custom Faction Colors"] = "Couleur de la faction"
+L["Custom Texts"] = "Textes personnalisés"
+L["Custom Texture"] = true
+L["Custom Timestamp Color"] = "Couleur personnalisée pour les heures"
+L["Cutaway Bars"] = true
+L["DATABAR_DESC"] = true
+L["Darken Inactive"] = "Foncé Inactif"
+L["DataBars"] = "Barres d'expériences"
+L["DataTexts"] = "Textes d'informations"
+L["Datatext Panel (Left)"] = "Panneaux d'informations (gauche)"
+L["Datatext Panel (Right)"] = "Panneaux d'informations (droite)"
+L["Date Format"] = true
+L["Days"] = "Jours"
+L["Debuff Highlighting"] = "Surbrillance des affaiblissements"
+L["Debug Tools"] = "Outils de débogage"
+L["Decimal Length"] = true
+L["Decimal Threshold"] = "Seuil décimal"
+L["Decode Text"] = "Texte décodé"
+L["Default Color"] = true
+L["Default Font"] = "Police par défaut"
+L["Default Settings"] = "Options par défaut"
+L["Deficit"] = "Déficit"
+L["Defines how the group is sorted."] = "Définit la façon dont le groupe est trié."
+L["Defines the sort order of the selected sort method."] = "Définit l'ordre de tri selon la méthode choisie (Ascendant/Descendant)"
+L["Delete Filter"] = "Supprimer un filtre"
+L["Delete a created filter, you cannot delete pre-existing filters, only custom ones."] = "Supprimer un filtre créé. Vous ne pouvez pas supprimer un filtre préexistant mais seulement ceux que vous avez personnalisé."
+L["Desaturate Cooldowns"] = true
+L["Desaturate Junk Items"] = true
+L["Desaturated Icon"] = true
+L["Descending"] = "Descendant"
+L["Detach From Frame"] = "Détacher du cadre"
+L["Detached Width"] = 'Largeur de détachement'
+L["Direction the bag sorting will use to allocate the items."] = "Direction du tri du sac qui sera utilisé pour allouer les objets."
+L["Direction the bar moves on gains/losses"] = "Direction que prend la barre lors de gains/pertes"
+L["Direction the health bar moves when gaining/losing health."] = "Sens de direction de la barre de vie quand vous en gagnez ou perdez."
+L["Disable Bag Sort"] = "Désactiver le tri des sacs"
+L["Disable Bank Sort"] = "Désactiver le tri de la banque"
+L["Disable Debuff Highlight"] = "Désactiver le surlignage des affaiblissements"
+L["Disabled Blizzard Frames"] = "Désactiver les cadres Blizzard"
+L["Disabled Blizzard"] = "Désactiver Blizzard"
+L["Disables the focus and target of focus unitframes."] = "Désactiver les cadres de la focalisation et de la cible de la focalisation."
+L["Disables the player and pet unitframes."] = "Désactiver les cadres du joueur et des familiers."
+L["Disables the target and target of target unitframes."] = "Désactiver les cadres de la cible et de la cible de la cible."
+L["Disconnected"] = "Déconnecté"
+L["Disease Effect"] = true
+L["Display Frames"] = "Afficher les cadres"
+L["Display Item Level"] = "Afficher le niveau d'objet"
+L["Display Player"] = "Afficher le joueur"
+L["Display Target"] = "Afficher la cible"
+L["Display Text"] = "Afficher le texte"
+L["Display a healer icon over known healers inside battlegrounds or arenas."] = "Affiche un icône soigneur sur le ou les soigneur(s) connu(s) à l'intérieur d'un champ de bataille ou arène"
+L["Display a panel across the bottom of the screen. This is for cosmetic only."] = "Affiche un bandeau au bas de l'écran. Option purement cosmétique."
+L["Display a panel across the top of the screen. This is for cosmetic only."] = "Affiche un bandeau en haut de l'écran. Option purement cosmétique."
+L["Display a spark texture at the end of the castbar statusbar to help show the differance between castbar and backdrop."] = "Affiche une texture lumineuse à la fin de la barre de sort pour aider à montrer la différence de couleur entre la barre de sort et le fond."
+L["Display an exclamation mark on items that starts a quest."] = true
+L["Display battleground messages in the middle of the screen."] = "Afficher le message du champ de bataille au milieu de l'écran"
+L["Display bind names on action buttons."] = "Affiche les noms des raccourcis sur les boutons de la barre d'action."
+L["Display cooldown text on anything with the cooldown spiral."] = "Affiche le temps de recharge au format numérique plutôt que la spirale d'origine."
+L["Display data panels below the chat, used for datatexts."] = "Afficher les panneaux de données sous le Chat utilisés pour les textes d'information"
+L["Display emotion icons in chat."] = "Afficher les émoticônes dans le chat"
+L["Display guild ranks if a unit is guilded."] = "Affiche le rang de la guilde si un joueur est guildé"
+L["Display how many of a certain item you have in your possession."] = "Affiche combien vous avez d'objets de ce type en votre possession."
+L["Display macro names on action buttons."] = "Affiche les noms des macros sur les boutons dans la barre d'action."
+L["Display minimap panels below the minimap, used for datatexts."] = "Afficher les panneaux sous la minicarte, utilisé pour les textes d'information."
+L["Display player titles."] = "Affiche le titre du joueur"
+L["Display reminder bar on the minimap."] = true
+L["Display the castbar icon inside the castbar."] = "Afficher l'icône à l'intérieur de la barre d'incantation."
+L["Display the castbar inside the information panel, the icon will be displayed outside the main unitframe."] = "Afficher la barre d'incantation à l'intérieur du panneau d'information, l'icone sera affichée à l'extérieur du cadre."
+L["Display the hyperlink tooltip while hovering over a hyperlink."] = "Afficher une infobulle pendant le survol d'un lien d'objet, sort, etc..."
+L["Display the junk icon on all grey items that can be vendored."] = "Afficher l'cône de camelotte sur tous les objets gris qui peuvent être vendu"
+L["Display the name of the unit on the chat bubble."] = true
+L["Display the npc ID when mousing over a npc tooltip."] = true
+L["Display the spell or item ID when mousing over a spell or item tooltip."] = "Affiche le sort ou l'ID de l'objet dans une infobulle quand vous passez votre souris sur le sort ou l'objet."
+L["Display the target of your current cast. Useful for mouseover casts."] = "Afficher la cible de votre incantation en cours. Utile pour les incantations en survol de souris."
+L["Display tick marks on the castbar for channelled spells. This will adjust automatically for spells like Drain Soul and add additional ticks based on haste."] = "Affichage des marques de graduation (ticks) sur la barre de lancement de sort. Cela s'ajustera automatiquement pour les sorts comme Drain d'âme qui est basé sur la Hâte."
+L["Displayed server time."] = true
+L["Displays a detailed report of every item sold when enabled."] = true
+L["Displays item level on equippable items."] = "Afficher le niveau d'objet sur les objets qui peuvent être équipés."
+L["Display Types"] = true
+L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."] = "Ne pas afficher les auras qui dépassent cette durée (en secondes). 0 pour désactiver"
+L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."] = "Ne pas afficher les auras qui ont une durée plus courte que cette durée (en secondes). 0 pour désactiver."
+L["Donations:"] = "Donateurs :"
+L["Down"] = "En bas"
+L["Dropdown CheckBox Skin"] = true
+L["Dungeon & Raid Filter"] = "Filtres de donjons et de raid"
+L["Duration Enable"] = true
+L["Duration Font Size"] = true
+L["Duration Reverse"] = "Durée inversée"
+L["Duration Text"] = "Texte de durée"
+L["Duration"] = "Durée"
+L["Editbox History Size"] = true
+L["ELVUI_CREDITS"] = "Je voudrais remercier tout spécialement ceux qui m'ont aidé à maintenir cet addon avec les codeurs, testeurs et les personnes qui m'ont aussi aidé via les dons. Veuillez noter que pour les dons, je n'affiche que les noms des personnes qui m'ont envoyés un message privé sur le forum. Si votre nom est absent et que vous désirez que je l'ajoute, merci de m’envoyer un message privé."
+L["ENEMY_NPC"] = "PNJ ennemi"
+L["ENEMY_PLAYER"] = "Joueur ennemi"
+L["Elite Icon"] = "Icône élite"
+L["Emotion Icons"] = "Emoticônes"
+L["Enable Custom Color"] = true
+L["Enable the use of separate size options for the right chat panel."] = "Activer cette option pour utiliser une taille spécifique de la fenêtre de discussion de droite."
+L["Enable/Disable the Bag-Bar."] = "Activer / Désactiver la barre des sacs."
+L["Enable/Disable the all-in-one bag."] = "Activer / désactiver le sac tout-en-un."
+L["Enable/Disable the loot frame."] = "Activer / désactiver le cadre de butin."
+L["Enable/Disable the loot roll frame."] = "Activer / désactiver le cadre du tirage au sort du butin."
+L["Enable/Disable the minimap. |cffFF0000Warning: This will prevent you from seeing the consolidated buffs bar, and prevent you from seeing the minimap datatexts.|r"] = true
+L["Enable/Disable the scaling of targetted nameplates."] = true
+L["Enables the ElvUI Raid Control panel."] = "Activer le panneau de raid d'ElvUI"
+L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."] = "Activer ceci permet d'afficher les cadres des joueurs sans 'trou' en remplissant les groupes, mais vous ne serez plus en mesure de distinguer les groupes de raid."
+L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."] = "Activer ceci inverse l'ordre du groupe quand il n'est pas complet, ceci inversera son ordre de départ"
+L["Enabling this will check your health amount."] = true
+L["Enabling this will check your power amount."] = true
+L["Enchanting"] = true
+L["Enemy Aura Type"] = "Type d'aura inamicale"
+L["Enemy Combat Toggle"] = true
+L["Enemy NPC Frames"] = true
+L["Enemy Player Frames"] = true
+L["Enemy"] = "Ennemi"
+L["Engineering"] = true
+L["Enhanced PVP Messages"] = "Messages PVP améliorés"
+L["Equipped Item Color"] = true
+L["Equipped Item"] = true
+L["Error decoding data. Import string may be corrupted!"] = "Erreur lors du décodage des données. Celles-ci sont peut être corropues"
+L["Error exporting profile!"] = "Erreur d'exportation du profil"
+L["Exclude Name"] = "Exclure le nom"
+L["Excluded Names"] = "Exclure les noms"
+L["Excluded names will not be class colored."] = "Exclure les noms sans couleur de classe"
+L["Expiring"] = "Expiration"
+L["Export Profile"] = "Exporter le profil"
+L["Exported"] = "Exporté"
+L["FRIENDLY_NPC"] = "PNJ alliés"
+L["FRIENDLY_PLAYER"] = "Joueur allié"
+L["Fade Chat Toggles"] = true
+L["Fade Out Delay"] = true
+L["Fade Out"] = true
+L["Fade Tabs No Backdrop"] = "Estomper les onglets sans arrière-plan"
+L["Fade Threshold"] = "Seuil du fondu"
+L["Fade Undocked Tabs"] = "Estompe l'affiche des onglets non groupés"
+L["Fade the chat text when there is no activity."] = "Estomper la discussion quand il n'y a pas d'activité"
+L["Fader"] = true
+L["Fades the buttons that toggle chat windows when that window has been toggled off."] = true
+L["Fades the text on chat tabs that are docked in a panel where the backdrop is disabled."] = true
+L["Fades the text on chat tabs that are not docked at the left or right chat panel."] = true
+L["Fill"] = "Remplissage"
+L["Filled"] = "Rempli"
+L["Filter Priority"] = true
+L["Filter Search"] = true
+L["Filter Type"] = "Type de filtre"
+L["Filter already exists!"] = true
+L["Filters Page"] = true
+L["Filters are not allowed to have commas in their name. Stripping commas from filter name."] = true
+L["Flash"] = true
+L["Fluid Position Buffs on Debuffs"] = "Position fluide des améliorations avec les affaiblissements"
+L["Fluid Position Debuffs on Buffs"] = "Position fluide des affaiblissements avec les améliorations"
+L["Flyout Direction"] = "Sens d'agrandissement"
+L["Flyout Spacing"] = true
+L["Focus"] = true
+L["FocusTarget"] = true
+L["Font Outline"] = "Contours extérieurs de la police"
+L["Font"] = "Police"
+L["Fonts"] = "Polices"
+L["Force Off"] = "Forcer Off"
+L["Force On"] = "Forcer On"
+L["Force Reaction Color"] = "Forcer les couleurs suivant les réactions"
+L["Force the frames to show, they will act as if they are the player frame."] = "Forcer l'affichage des cadres, ils agiront comme sur le cadre de joueur."
+L["Forces Debuff Highlight to be disabled for these frames"] = "Forcer la désactivation du surlignage des affaiblissements pour désactiver ces éléments"
+L["Forces Mouseover Glow to be disabled for these frames"] = true
+L["Forces Target Glow to be disabled for these frames"] = true
+L["Forces reaction color instead of class color on units controlled by players."] = "Forcer les couleurs suivant les réactions au lieu des classes sur les unités contrôlées par les joueurs."
+L["Format"] = "Format"
+L["Frame Glow"] = true
+L["Frame Level"] = "Niveau de la fenêtre"
+L["Frame Orientation"] = "Orientation de la fenêtre"
+L["Frame Strata"] = "Couche de la fenêtre"
+L["Frequent Updates"] = "Mise à Jours fréquentes"
+L["Friendly Aura Type"] = "Type d'Aura amical"
+L["Friendly Combat Toggle"] = true
+L["Friendly NPC Frames"] = true
+L["Friendly Player Frames"] = true
+L["Friendly"] = "Amical"
+L["Full Overlay"] = true
+L["Full"] = "Plein"
+L["GM Chat"] = true
+L["GPS Arrow"] = true
+L["Gems"] = true
+L["General Options"] = "Options générales"
+L["Global (Account Settings)"] = "Global (Configuration du compte)"
+L["Global Fade Transparency"] = "Option générale de transparence et d'affichage"
+L["Global"] = "Global"
+L["Glow"] = "Lueur"
+L["Gold Format"] = "Format monétaire"
+L["Good Color"] = true
+L["Good Scale"] = true
+L["Good Transition Color"] = true
+L["Good"] = "Bonne"
+L["Gossip Frame"] = "Fenêtre PNJ"
+L["Group By"] = "Groupe par"
+L["Group Spacing"] = true
+L["Grouping & Sorting"] = "Regroupement et tri"
+L["Groups Per Row/Column"] = "Nombres de groupes par ligne/colonne"
+L["Growth Direction"] = "Direction de la croissance"
+L["Growth X-Direction"] = true
+L["Growth Y-Direction"] = true
+L["Growth direction from the first unitframe."] = "Direction de croissance du premier cadre d'unité."
+L["Guide:"] = true
+L["Guild Ranks"] = "Rangs de la guilde"
+L["Guild Registrar"] = "Bannière de Guilde"
+L["HH:MM Threshold"] = true
+L["HH:MM"] = true
+L["Header Font Size"] = true
+L["Heal Prediction"] = "Soin prévisionnel"
+L["Healer Icon"] = "Icône de soigneur"
+L["Health Backdrop Multiplier"] = true
+L["Health Backdrop"] = "Fond de vie personnalisé"
+L["Health Bar"] = "Barre de vie"
+L["Health Border"] = "Bordure de la santé personnalisée"
+L["Health By Value"] = "Vie par valeur"
+L["Health Color"] = true
+L["Health Length"] = true
+L["Health Threshold"] = true
+L["Health"] = "Vie"
+L["Height Multiplier"] = "Multiplicateur hauteur"
+L["Height of the objective tracker. Increase size to be able to see more objectives."] = "Hauteur de la fenêtre des suivis d'objectif, augmenter pour afficher plus d'objectifs"
+L["Height"] = "Hauteur"
+L["Help Frame"] = "Fenêtre d'Assistance clientèle"
+L["Herbalism"] = true
+L["Here you can add items or search terms that you want to be excluded from sorting. To remove an item just click on its name in the list."] = true
+L["Hide At Max Level"] = "Cacher au niveau maximum"
+L["Hide Both"] = "Masquer les deux"
+L["Hide Error Text"] = "Cacher les textes d'erreurs"
+L["Hide Frame"] = true
+L["Hide In Combat"] = "Cacher en combat"
+L["Hide In Vehicle"] = "Cacher en véhicule"
+L["Hide Spell Name"] = true
+L["Hide Time"] = true
+L["Hide specific sections in the datatext tooltip."] = true
+L["Hide tooltip while in combat."] = "Masquer toutes les infobulles quand vous êtes en combat."
+L["Hides the red error text at the top of the screen while in combat."] = "Cacher les textes d'erreurs en haut de l'écran en combat."
+L["History Size"] = true
+L["History"] = true
+L["Horizontal Spacing"] = "Espace horizontal"
+L["Horizontal"] = "Horizontale"
+L["Hours"] = "Heures"
+L["Hover Highlight"] = true
+L["Hover"] = true
+L["How long the cutaway health will take to fade out."] = true
+L["How long the cutaway power will take to fade out."] = true
+L["How many seconds the castbar should stay visible after the cast failed or was interrupted."] = true
+L["How much time before the cutaway health starts to fade."] = true
+L["How much time before the cutaway power starts to fade."] = true
+L["Hyperlink Hover"] = "Survol des liens"
+L["Icon Frame"] = true
+L["Icon Inside Castbar"] = "Icône à l'intérieur de la barre d'incantation"
+L["Icon Only"] = true
+L["Icon Position"] = true
+L["Icon Size"] = "Taille de l'icône"
+L["Icon"] = "Icône"
+L["Icon: BOTTOM"] = "Icône : BAS"
+L["Icon: BOTTOMLEFT"] = "Icône : BAS-GAUCHE"
+L["Icon: BOTTOMRIGHT"] = "Icône : BAS-DROITE"
+L["Icon: LEFT"] = "Icône : GAUCHE"
+L["Icon: RIGHT"] = "Icône : DROITE"
+L["Icon: TOP"] = "Icône : HAUT"
+L["Icon: TOPLEFT"] = "Icône : HAUT-GAUCHE"
+L["Icon: TOPRIGHT"] = "Icône : HAUT-DROITE"
+L["Icons and Text (Short)"] = "Icônes et textes (court)"
+L["Icons and Text"] = "Icônes et textes"
+L["If enabled then it checks if auras are missing instead of being present on the unit."] = true
+L["If enabled then it will require all auras to activate the filter. Otherwise it will only require any one of the auras to activate it."] = true
+L["If enabled then it will require all cooldowns to activate the filter. Otherwise it will only require any one of the cooldowns to activate it."] = true
+L["If enabled then the filter will activate if the unit is casting anything."] = true
+L["If enabled then the filter will activate if the unit is channeling anything."] = true
+L["If enabled then the filter will activate if the unit is not casting anything."] = true
+L["If enabled then the filter will activate if the unit is not channeling anything."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or higher than this value."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or lower than this value."] = true
+L["If enabled then the filter will only activate if the level of the unit matches this value."] = true
+L["If enabled then the filter will only activate if the level of the unit matches your own."] = true
+L["If enabled then the filter will only activate if the unit is casting interruptible spells."] = true
+L["If enabled then the filter will only activate if the unit is casting not interruptible spells."] = true
+L["If enabled then the filter will only activate if the unit is not casting or channeling one of the selected spells."] = true
+L["If enabled then the filter will only activate when you are in combat."] = true
+L["If enabled then the filter will only activate when you are not targeting the unit."] = true
+L["If enabled then the filter will only activate when you are out of combat."] = true
+L["If enabled then the filter will only activate when you are targeting the unit."] = true
+L["If enabled then the filter will only activate when you have a target."] = true
+L["If not set to 0 then override the size of the aura icon to this."] = "Si ce n'est pas réglé sur 0, alors remplacer la taille de l'icône d'aura à celui ci."
+L["If the aura is listed with a number then you need to use that to remove it from the list."] = true
+L["If this list is empty, and if 'Interruptible' is checked, then the filter will activate on any type of cast that can be interrupted."] = true
+L["If this threshold is used then the health of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the health of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the power of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the power of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If you have a lot of 3D Portraits active then it will likely have a big impact on your FPS. Disable some portraits if you experience FPS issues."] = "Si vous avez beaucoup de portraits 3D actifs, vos IPS (FPS) risquent d'être grandement impactés. Désactiver quelques portraits au besoin."
+L["If you have any plugins supporting this feature installed you can find them in the selection dropdown to the right."] = true
+L["If you unlock actionbars then trying to move a spell might instantly cast it if you cast spells on key press instead of key release."] = true
+L["Ignore UI Scale Popup"] = true
+L["Ignore mouse events."] = "Ignorer les évènements de la souris."
+L["Ignored Items and Search Syntax (Global)"] = true
+L["Ignored Items and Search Syntax (Profile)"] = true
+L["Import Profile"] = "Importer le profil"
+L["Importing"] = "Importation"
+L["Inactivity Timer"] = true
+L["Index"] = "Index"
+L["Indicate whether buffs you cast yourself should be separated before or after."] = "Indique si les améliorations que vous lancez doivent être séparées avant ou après."
+L["InfoPanel Border"] = "Bordure du panneau d'information"
+L["Information Panel"] = "Panneau d'information"
+L["Inherit Global Fade"] = "Utiliser l'option de transparence générale"
+L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."] = true
+L["Inset"] = "Insérer"
+L["Inside Information Panel"] = "A l'intérieur du panneau d'information"
+L["Install"] = "Installer"
+L["Instance Difficulty"] = "Difficulté de l'instance"
+L["Instance Type"] = "Type d'instance"
+L["Interruptable"] = "Interruptible"
+L["Interruptible"] = "Interrompable"
+L["Invert Colors"] = true
+L["Invert Grouping Order"] = "Inverser l'ordre des groupes"
+L["Invert foreground and background colors."] = true
+L["Is Casting Anything"] = true
+L["Is Channeling Anything"] = true
+L["Is Targeted"] = "est ciblé"
+L["Item Count Font"] = "Police d'équipement du compteur"
+L["Item Count"] = "Nombre d'objet"
+L["Item Level Threshold"] = "Seuil de niveau d'objet"
+L["Item Level"] = "Niveau d'objet"
+L["JustifyH"] = "JustifierH"
+L["KEY_BINDINGS"] = true
+L["Key Down"] = "Touche enfoncée"
+L["Keybind Mode"] = "Mode raccourcis"
+L["Keybind Text Position"] = true
+L["Keybind Text X-Offset"] = true
+L["Keybind Text Y-Offset"] = true
+L["Keybind Text"] = "Texte des raccourcis"
+L["Keyword Alert"] = "Alerte mots-clés"
+L["Keywords"] = "Mots-clés"
+L["LBF Support"] = true
+L["LEVEL_BOSS"] = "Set level to -1 for boss units or set to 0 to disable."
+L["LFD Frame"] = true
+L["LFG Queue"] = "Outil raid"
+L["LFR Frame"] = true
+L["Latency"] = "Latence"
+L["Leatherworking"] = true
+L["Left Only"] = "Gauche seulement"
+L["Left to Right"] = "de gauche à droite"
+L["Left"] = "Gauche"
+L["Limit the number of rows or columns."] = "Limiter le nombre de lignes ou de colonnes."
+L["List of words to color in chat if found in a message. If you wish to add multiple words you must seperate the word with a comma. To search for your current name you can use %MYNAME%.\n\nExample:\n%MYNAME%, ElvUI, RBGs, Tank"] = "Liste des mots à colorer dans la fenêtre de discussion s'ils y sont trouvés. Si vous souhaitez ajouter plusieurs mots, vous devez séparer le mot avec une virgule. Pour rechercher votre nom actuel, vous pouvez utiliser %MYNAME%.\n\nExemple:\n%MYNAME%, ElvUI, RBG, Tank"
+L["Location Text"] = "Texte de localisation"
+L["Lock Positions"] = "Verrouiller les positions"
+L["Log Taints"] = "Journal des corruptions"
+L["Log the main chat frames history. So when you reloadui or log in and out you see the history from your last session."] = "Active la fenêtre principale de l'historique de discussion. Ainsi quand vous rechargez l'interface ou effectuez une connexion / déconnexion, vous voyez l'historique de la dernière session"
+L["Login Message"] = "Message de connexion"
+L["Loot Frames"] = "Fenêtre de butin"
+L["Loot Roll"] = "Cadre de butin"
+L["Losing Threat"] = true
+L["Low Health Threshold"] = "Seuil vie faible"
+L["Low Threat"] = true
+L["Low Threshold"] = "Seuil minimal"
+L["Lower numbers mean a higher priority. Filters are processed in order from 1 to 100."] = true
+L["MM:SS Threshold"] = true
+L["MM:SS"] = true
+L["Macro Text"] = "Texte sur Macro"
+L["Magic Effect"] = true
+L["Main Tanks / Main Assist"] = "Tank Principal / Assistant principal"
+L["Main backdrop color of the UI."] = "Couleur principale de fond de l'Interface."
+L["Main border color of the UI."] = "Couleur de bordure principale de l'Interface."
+L["Main statusbar texture."] = "Texture de la barre principale."
+L["Make textures transparent."] = "Mettre les textures transparentes."
+L["Make the unitframe glow yellow when it is below this percent of health, it will glow red when the health value is half of this value."] = true
+L["Make the world map smaller."] = "Rendre la carte du monde plus petite"
+L["Map Opacity When Moving"] = "Opacité de la carte en mouvement"
+L["Maps"] = "Cartes"
+L["Match Frame Width"] = "Accorder à la largeur du cadre"
+L["Match Player Level"] = true
+L["Max Alpha"] = true
+L["Max Bars"] = "Barres maximum"
+L["Max Lines"] = true
+L["Max Overflow"] = "Dépassement maximum"
+L["Max Wraps"] = "Retour à la ligne maximale"
+L["Max amount of overflow allowed to extend past the end of the health bar."] = "Quantité maximale de débordement autorisée à dépasser la fin de la barre de vie."
+L["Maximum Duration"] = "Durée maximum"
+L["Maximum Level"] = "Niveau maximum"
+L["Maximum Time Left"] = true
+L["Media"] = "Média"
+L["Method to sort by."] = "Méthode de tri d'affichage"
+L["Middle Click - Set Focus"] = "Clic milieu - Réglage de la focalisation"
+L["Middle clicking the unit frame will cause your focus to match the unit."] = "Le clic du milieu sur une unité la mettra en focalisation."
+L["Middle"] = "Milieu"
+L["Min Alpha"] = true
+L["Minimap Mouseover"] = "Au survol de la minicarte"
+L["Minimap Panels"] = "Panneaux de la Minicarte"
+L["Minimum Duration"] = "Durée minimum"
+L["Minimum Level"] = "Niveau minimum"
+L["Minimum Time Left"] = true
+L["Mining"] = true
+L["Minutes"] = "Minutes"
+L["Mirror Timers"] = "Fenêtre des Timers mirroirs"
+L["Misc Frames"] = "Divers"
+L["Missing"] = "Manquant"
+L["Modulating Blend"] = true
+L["Module Control"] = true
+L["Module Copy"] = true
+L["Module Reset"] = true
+L["Money Format"] = "Format monétaire"
+L["Mouse Over"] = "Au survol"
+L["Mouseover Glow"] = true
+L["Mouseover Highlight"] = true
+L["Mouseover"] = "Au survol de la souris"
+L["Multi-Monitor Support"] = "Support Multi-Moniteur"
+L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."] = "Multiplie la hauteur ou la largeur de l'arrière-plan par cette valeur. Très utile si vous souhaitez avoir une barre de plus en arrière-plan."
+L["NAMEPLATE_FRAMELEVEL_DESC"] = true
+L["NPC IDs"] = true
+L["Name Color"] = "Couleur du nom"
+L["Name Colored Glow"] = true
+L["Name Font"] = "Nom de la police"
+L["Name Only"] = true
+L["Name"] = "Nom"
+L["NamePlate Style Filters"] = true
+L["NamePlates"] = "Noms"
+L["Nameplate"] = true
+L["Neutral"] = "Neutre"
+L["Never Hide"] = "Jamais caché"
+L["No Alert In Combat"] = "Pas d'alerte en combat"
+L["No Duration"] = true
+L["No Sorting"] = "Aucun tri"
+L["Non-Interruptable"] = "Non-interruptible"
+L["Non-Target Alpha"] = true
+L["Not Casting Anything"] = true
+L["Not Channeling Anything"] = true
+L["Not Spell"] = true
+L["Not Targeted"] = "Non ciblé"
+L["Not Usable"] = "Non utilisable"
+L["Not valid spell id"] = "ID du sort invalide"
+L["Num Rows"] = "Nombre de lignes"
+L["Number of Groups"] = "Nombre de groupes"
+L["Number of messages you scroll for each step."] = "Nombre de messages par défilement."
+L["Number of repeat characters while in combat before the chat editbox is automatically closed. Set to 0 to disable."] = true
+L["Number of time in seconds to scroll down to the bottom of the chat window if you are not scrolled down completely."] = "Temps en secondes pour faire défiler vers le bas de la fenêtre de discussion si vous ne l'avez pas fait défiler jusqu'en bas."
+L["Objective Frame Height"] = "Hauteur du cadre d'objectif"
+L["Off Cooldown"] = true
+L["Offset of the powerbar to the healthbar, set to 0 to disable."] = "Décalage de la barre de pouvoir à la barre de vie, mettre 0 pour désactiver."
+L["Offset position for text."] = "Décalage de la position du texte."
+L["Offset"] = "Décalage"
+L["On Cooldown"] = true
+L["Only Match SpellID"] = "Seulement les ID de sort correspondants"
+L["Only show when the unit is not in range."] = true
+L["Only show when you are mousing over a frame."] = true
+L["Other Filter"] = "Autre filtre"
+L["Other's First"] = "Les autres en premier"
+L["Others"] = "Autres"
+L["Out of Power"] = "Sans ressource"
+L["Out of Range"] = "Hors de portée"
+L["Over Health Threshold"] = true
+L["Over Power Threshold"] = true
+L["Overlay Alpha"] = true
+L["Overlay"] = "Superposition"
+L["Overnuking"] = true
+L["Override any custom visibility setting in certain situations, EX: Only show groups 1 and 2 inside a 10 man instance."] = "Remplace tout paramètre de visibilité dans certaines situations, Ex: afficher seulement le groupe 1 et 2 quand vous êtes dans un raid à 10 joueurs."
+L["Override the default class color setting."] = "Remplacer les réglages des couleurs de classes par défaut."
+L["Owners Name"] = "Nom des propriétaires"
+L["PVP Trinket"] = "Bijou PVP"
+L["Panel Backdrop"] = "Arrière-plan de la fenêtre de discussion"
+L["Panel Height"] = "Hauteur de la fenêtre de discussion"
+L["Panel Texture (Left)"] = "Texture de la fenêtre de discussion (Gauche)"
+L["Panel Texture (Right)"] = "Texture de la fenêtre de discussion (Droite)"
+L["Panel Transparency"] = "Transparence du panneau"
+L["Panel Width (Bags)"] = "Largeur du panneau (Sac)"
+L["Panel Width (Bank)"] = "Largeur du panneau (Banque)"
+L["Panel Width"] = "Largeur de la fenêtre de discussion"
+L["Panels"] = "Fenêtre"
+L["Parent"] = "Parent"
+L["Party / Raid"] = "Groupe / Raid"
+L["Party Only"] = "Groupe seulement"
+L["Party Pets"] = "Familiers des coéquipiers"
+L["Party Targets"] = "Cible des coéquipiers"
+L["Per Row"] = "par ligne"
+L["Percent"] = "Pourcent"
+L["Personal"] = "Personnel"
+L["Pet Name"] = "Nom du familier"
+L["Pet"] = true
+L["PetTarget"] = true
+L["Petition Frame"] = "Fenêtre de Charte"
+L["Pick Up Action Key"] = true
+L["Player Frame Aura Bars"] = "Barre d'aura du joueur"
+L["Player Health"] = true
+L["Player Out of Combat"] = true
+L["Player Target"] = true
+L["Player Titles"] = "Titre du joueur"
+L["Player in Combat"] = "Joueur en combat"
+L["Player"] = "Joueur"
+L["Plugin"] = "Plugin"
+L["Poison Effect"] = true
+L["Portrait"] = "Portrait"
+L["Position Buffs on Debuffs"] = "Positionner les améliorations sur les affaiblissements"
+L["Position Debuffs on Buffs"] = "Positionner les affaiblissements sur les améliorations"
+L["Position of the Chat EditBox, if datatexts are disabled this will be forced to be above chat."] = "Postion du cadre d'écriture de la fenêtre de Chat. Si les Texte d'informations sont désactivés, elle apparaitra au dessus du Chat."
+L["Position"] = "Position"
+L["Power Threshold"] = true
+L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."] = "Le texte d'énergie sera masqué sur les PNJ ciblés, de plus le nom sera repositionné sur le texte d'énergie."
+L["Power"] = "Énergie"
+L["Powers"] = "Énergies"
+L["Prevent the same messages from displaying in chat more than once within this set amount of seconds, set to zero to disable."] = "Empêche l'affichage du même message plus d'une fois dans la fenêtre de discussion durant un laps de temps. Définir sur 0 pour désactiver."
+L["Primary Texture"] = "Texture primaire"
+L["Priority"] = "Priorité"
+L["Private (Character Settings)"] = "Privée (Paramètres du personnages)"
+L["Profession Bags"] = true
+L["Profile Name"] = "Nom du profil"
+L["Profile Specific"] = "Profil spécifique"
+L["Profile imported successfully!"] = "Profil importé avec succès"
+L["Profile"] = "Profil"
+L["Progress Bar"] = true
+L["Puts coordinates on the world map."] = "Mettre les coordonnées sur la carte du monde"
+L["PvP Frames"] = "Fenêtre JcJ"
+L["PvP Icon"] = true
+L["PvP Queue"] = true
+L["PvP Text"] = "Texte PVP"
+L["Quest Frames"] = "Fenêtre de Quête"
+L["Quest Starter"] = true
+L["Quiver"] = true
+L["RAID_CONTROL"] = "Contrôle de raid"
+L["RL / ML Icons"] = true
+L["Raid Difficulty"] = true
+L["Raid Frame"] = "Fenêtre de Raid"
+L["Raid Icon"] = "Icône de Raid"
+L["Raid Only"] = "Raid seulement"
+L["Raid Pet"] = "Cadres de raid des familiers"
+L["Raid-40"] = "Cadres de raid 40"
+L["Raid-Wide Sorting"] = "Affichage du raid-large"
+L["RaidDebuff Indicator"] = "Indicateur d'affaiblissement en raid"
+L["Range"] = true
+L["Rapidly update the health, uses more memory and cpu. Only recommended for healing."] = "Mise à jour rapide de la barre de vie, ce qui augmente la charge de la mémoire et du processeur. Recommandé seulement pour les soigneurs."
+L["Reaction Castbars"] = "Réaction des barres d'incantation"
+L["Reaction Colors"] = true
+L["Reaction Type"] = true
+L["Reactions"] = "Réactions"
+L["Ready Check Icon"] = "Icône d'appel"
+L["Realm Time"] = true
+L["Remaining / Max"] = true
+L["Remaining Time"] = true
+L["Remaining"] = "Restant"
+L["Reminder"] = true
+L["Remove Backdrop"] = 'Supprimer le fond'
+L["Remove Name"] = true
+L["Remove Spell ID or Name"] = true
+L["Remove Spell"] = true
+L["Remove SpellID"] = "Supprimer l'identifiant d'un sort"
+L["Remove a Name from the list."] = true
+L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."] = "Supprimer un sort depuis le filtre. Utilisez l'ID du sort si vous voyez cet ID dans le nom du sort."
+L["Remove a spell from the filter."] = "Supprimer un sort depuis le filtre."
+L["Replace Blizzard Fonts"] = "Remplace les polices Blizzard"
+L["Replaces the default Blizzard fonts on various panels and frames with the fonts chosen in the Media section of the ElvUI Options. NOTE: Any font that inherits from the fonts ElvUI usually replaces will be affected as well if you disable this. Enabled by default."] = true
+L["Reposition Window"] = true
+L["Require All"] = true
+L["Require Target"] = true
+L["Require holding the Alt key down to move cursor or cycle through messages in the editbox."] = "Maintenir ALT enfoncé et bouger le cursor pour faire défiler les messages dans la zone de saisie."
+L["Reset Anchors"] = "Réinitialiser les ancres"
+L["Reset Aura Filters"] = "Réinitialiser les filtres des auras"
+L["Reset Editbox History"] = true
+L["Reset Filter"] = "Réinitialiser les filtres"
+L["Reset History"] = true
+L["Reset Priority"] = true
+L["Reset Zoom"] = "Réinitialiser le zoom"
+L["Reset all frames to their original positions."] = "Réinitialiser les cadres à leurs positions initiales."
+L["Reset filter priority to the default state."] = true
+L["Reset the size and position of this frame."] = true
+L["Rest Icon"] = "Icône reposé"
+L["Restore Bar"] = "Restaurer la barre"
+L["Restore Defaults"] = "Restaurer les paramètres par défaut"
+L["Restore the actionbars default settings"] = "Restaure la barre d'actions avec ses paramètres par défaut."
+L["Resurrect Icon"] = true
+L["Return filter to its default state."] = true
+L["Reverse Bag Slots"] = true
+L["Reverse Cooldown"] = true
+L["Reverse Style"] = true
+L["Reverse Toggle will enable Cooldown Text on this module when the global setting is disabled and disable them when the global setting is enabled."] = true
+L["Reverse Toggle"] = true
+L["Right Only"] = "Droite seulement"
+L["Right Panel Height"] = "Hauteur de la fenêtre de discussion de droite"
+L["Right Panel Width"] = "Largeur de la fenêtre de discussion de droite"
+L["Right to Left"] = "De droite à gauche"
+L["Right"] = "Droite"
+L["RightClick Self-Cast"] = true
+L["Role Icon"] = "Icône de rôle"
+L["Run the installation process."] = "Démarrer le processus d'installation."
+L["Sanctuary"] = true
+L["Scale of the nameplate that is targetted."] = true
+L["Scale"] = "Echelle"
+L["Scroll Interval"] = "Intervalle de défilement"
+L["Scroll Messages"] = "Défilement des messages"
+L["Search Syntax"] = "Syntaxe pour la recherche"
+L["Search for a spell name inside of a filter."] = true
+L["Secondary Texture"] = "Texture secondaire"
+L["Seconds remaining on the aura duration before the bar starts moving. Set to 0 to disable."] = "Secondes restantes à l'aura avant que la barre ne commence à bouger. Mettez 0 pour désactiver cette option."
+L["Seconds"] = "Secondes"
+L["Selected Text Color"] = true
+L["Selector Color"] = true
+L["Selector Style"] = true
+L["Securely Tanking"] = true
+L["Select Filter"] = "Sélectionner un filtre"
+L["Select Spell"] = "Sélectionner un sort"
+L["Select a profile to copy from/to."] = true
+L["Select a unit to copy settings from."] = "Sélectionnez les réglages d'un cadre à copier."
+L["Select the display method of the portrait."] = "Sélectionnez la méthode d'affichage du portrait."
+L["Sell Interval"] = true
+L["Send ADDON_ACTION_BLOCKED errors to the Lua Error frame. These errors are less important in most cases and will not effect your game performance. Also a lot of these errors cannot be fixed. Please only report these errors if you notice a Defect in gameplay."] = "Envoyer les ADDON_ACTION_BLOCKED dans la fenêtre d'erreur LUA. Ces erreurs sont minimes dans la plupart des cas et n'affecteront pas votre expérience de jeu. Tenez compte que nombreuses de celles-ci ne peuvent être fixé. Signalez-les uniquement si cela affecte grandement le jeu."
+L["Sends your current profile to your target."] = "Envoi votre profil actuel à votre cible."
+L["Sends your filter settings to your target."] = "Envoi vos paramètres de filtre à votre cible."
+L["Separate Panel Sizes"] = "Séparer la taille des fenêtres de discussion."
+L["Seperate"] = "Séparer"
+L["Set Settings to Default"] = true
+L["Set the alpha level of portrait when frame is overlayed."] = true
+L["Set the filter type. Blacklist will hide any auras in the list and show all others. Whitelist will show any auras in the filter and hide all others."] = "Définir le type de filtre. La liste noire masquera toutes les auras dans la liste et rendra visible les autres. La liste blanche montrera les auras dans la liste et masquera tous les autres."
+L["Set the font outline."] = "Configure le contour extérieur de la police."
+L["Set the font size for everything in UI. Note: This doesn't effect somethings that have their own seperate options (UnitFrame Font, Datatext Font, ect..)"] = "Définie la taille de la police d'écriture pour toute l'interface utilisateur. Note: Ceci n'affecte pas les modules qui ont leurs propres paramètres (Portait d'unité, Textes d'Informations, etc)"
+L["Set the font size for unitframes."] = "Configure la taille de la police d'écriture pour les cadres d'unités."
+L["Set the order that the group will sort."] = "Définir l'ordre de tri d'affichage du groupe"
+L["Set the orientation of the UnitFrame."] = "Définir l'orientation des cadres d'unités"
+L["Set the priority order of the spell, please note that prioritys are only used for the raid debuff module, not the standard buff/debuff module. If you want to disable set to zero."] = "Définir l'ordre de priorité du sort, merci de noter que ces priorités ne sont utilisées que pour le mode d'affaiblissement de raid, ce n'est pas un module améliorations / affaiblissement standard. Si vous souhaitez le désactiver, mettez la valeur sur 0."
+L["Set the size of the individual auras."] = "Définit la taille de l'aura individuelle."
+L["Set the size of your bag buttons."] = "Définissez la taille de vos boutons de sac."
+L["Set the type of auras to show when a unit is a foe."] = "Définir le type d'auras à afficher quand l'unité est hostile."
+L["Set the type of auras to show when a unit is friendly."] = "Définir le type d'auras à afficher quand l'unité est amical."
+L["Set to either stack nameplates vertically or allow them to overlap."] = true
+L["Sets the font instance's horizontal text alignment style."] = "Réglages de l'alignement horizontal du texte de la police d'écriture."
+L["Share Current Profile"] = "Partagez votre profil actuel"
+L["Share Filters"] = "Partagez les filtres"
+L["Short (Whole Numbers)"] = "Court (nombres entiers)"
+L["Short Channels"] = "Raccourcis canaux"
+L["Shortcut to 'Filters' section of the config."] = true
+L["Shortcut to global filters."] = true
+L["Shortcuts"] = "Raccourcis"
+L["Shorten the channel names in chat."] = "Minimise le nom des canaux de discussion."
+L["Should tooltip be anchored to mouse cursor"] = "L'infobulle doit être ancrée sur le curseur de la souris"
+L["Show Aura From Other Players"] = "N'importe quelle unité"
+L["Show Auras"] = "Afficher les auras"
+L["Show Bind on Equip/Use Text"] = true
+L["Show Both"] = "Afficher les deux"
+L["Show Coins"] = "Afficher les pièces"
+L["Show Dispellable Debuffs"] = "Voir les affaiblissements dissipables"
+L["Show Empty Buttons"] = "Voir les emplacements vide"
+L["Show For DPS"] = "Voir pour les DPS"
+L["Show For Healers"] = "Voir pour les soigneurs"
+L["Show For Tanks"] = "Voir pour les tanks"
+L["Show Icon"] = true
+L["Show Junk Icon"] = "Afficher l'icône camelotte"
+L["Show Quality Color"] = true
+L["Show Quest Icon"] = true
+L["Show When Not Active"] = "Afficher les manquants"
+L["Show an incoming heal prediction bar on the unitframe. Also display a slightly different colored bar for incoming overheals."] = "Affiche une barre sur la prédiction des soins à venir sur le cadre d'unité. Ainsi qu'une barre de couleur légèrement différente pour les soins entrants excédants."
+L["Show the castbar icon desaturated if a spell is not interruptible."] = true
+L["Show/Hide Test Frame"] = true
+L["Side Arrows"] = true
+L["Size Override"] = "Forcer la taille"
+L["Size and Positions"] = "Taille et positions"
+L["Size of the indicator icon."] = "Taille de l'indicateur de l'icône."
+L["Size"] = "Taille"
+L["Skin Backdrop (No Borders)"] = "Habiller le fond (sans bordures)"
+L["Skin Backdrop"] = "Habiller le fond"
+L["Skin the blizzard chat bubbles."] = "Habillage des bulles de Chat."
+L["Skins"] = "Habillage"
+L["Small Panels"] = "Petits panneaux"
+L["Smaller World Map"] = "Carte du monde plus petite"
+L["Smart Aura Position"] = "Positionnement intelligent des auras"
+L["Smart Raid Filter"] = "Filtre intelligent de Raid"
+L["Smart"] = "Intelligent"
+L["Smooth Bars"] = "Barres fluides"
+L["Smooth"] = true
+L["Smoothing Amount"] = true
+L["Socket Frame"] = "Fenêtre de sertissage"
+L["Sort By"] = "Afficher par"
+L["Sort Direction"] = "Type de direction"
+L["Sort Inverted"] = "Tri inversé"
+L["Sort Method"] = "Méthode de tri"
+L["Soul Bag"] = true
+L["Spaced"] = "Espacé"
+L["Spacing"] = "Espace"
+L["Spam Interval"] = "Intervalle contre le Spam"
+L["Spark"] = "Lueur"
+L["Spell/Item IDs"] = "ID de l'objet / du sort"
+L["Split"] = true
+L["Stable"] = "Écurie"
+L["Stack Counter"] = "Compteur de pile"
+L["Stack Text Position"] = true
+L["Stack Text X-Offset"] = true
+L["Stack Text Y-Offset"] = true
+L["Stack Threshold"] = "Seuil de pile"
+L["Start Near Center"] = "Démarrer près du centre"
+L["StatusBar Texture"] = "Texture de la barre d'état."
+L["Statusbar Fill Orientation"] = "Orientation la barre d'état."
+L["Statusbar"] = true
+L["Sticky Chat"] = "Fenêtre de chat adhésive"
+L["Strata and Level"] = "Couche et niveau"
+L["Style Filter"] = true
+L["Style"] = "Style"
+L["TALENTS"] = "Talents"
+L["Tab Font Outline"] = "Contour de la police extérieure des onglets"
+L["Tab Font Size"] = "Taille de la police des onglets"
+L["Tab Font"] = "Police des onglets"
+L["Tab Panel Transparency"] = "Transparence de l'étiquette"
+L["Tab Panel"] = "Étiquette de l'onglet"
+L["Tab Selector"] = true
+L["Tabard Frame"] = "Tabard"
+L["Table"] = "Tableau"
+L["Tank Target"] = "Cible de tank"
+L["Tank"] = true
+L["Tapped"] = "Collé"
+L["Target Indicator Color"] = "Couleur de l'indicateur de la cible"
+L["Target Info"] = "Info de la cible"
+L["Target On Mouse-Down"] = "Cibler lors d'un appui sur le clic (et non pas en relachant le clic)"
+L["Target Scale"] = true
+L["Target units on mouse down rather than mouse up. \n\n|cffFF0000Warning: If you are using the addon 'Clique' you may have to adjust your clique settings when changing this."] = "Cible les unités avec un appui sur le clic souris plutôt qu'au relâchement du clic. \n\n|cffFF0000Attention: Si vous utilisez l'addon 'Clique' vous devrez peut-être ajuster vos paramètres de clic lors du changement de celui-ci."
+L["Target/Low Health Indicator"] = "Indicateur de la cible"
+L["TargetTarget"] = true
+L["TargetTargetTarget"] = true
+L["Targeted Glow"] = true
+L["Targeting"] = true
+L["Testing:"] = "Testeurs :"
+L["Text Fade"] = true
+L["Text Color"] = "Couleur du texte"
+L["Text Font Size"] = "Police d'écriture du texte"
+L["Text Format"] = "Format du texte"
+L["Text Position"] = "Position du texte"
+L["Text Threshold"] = "Seuil du texte"
+L["Text Toggle On NPC"] = "Afficher le texte des PNJ"
+L["Text xOffset"] = "Décalage de l'axe X du texte"
+L["Text yOffset"] = "Décalage de l'axe Y du texte"
+L["Text"] = "Texte"
+L["Texture"] = true
+L["Textured Icon"] = "Texture de l'icône"
+L["Textures"] = "Textures"
+L["The Portrait will overlay the Healthbar. This will be automatically happen if the Frame Orientation is set to Middle."] = true
+L["The Thin Border Theme option will change the overall apperance of your UI. Using Thin Border Theme is a slight performance increase over the traditional layout."] = true
+L["The amount of buttons to display per row."] = "Nombre de boutons à afficher par ligne."
+L["The amount of buttons to display."] = "Nombre de boutons à afficher."
+L["The button you must hold down in order to drag an ability to another action button."] = "Définir la touche qui doit être maintenue enfoncée pour pouvoir glisser une capacité sur un autre bouton d'action."
+L["The debuff needs to reach this amount of stacks before it is shown. Set to 0 to always show the debuff."] = "L'affaiblissement doit atteindre ce nombre de stacks pour être affiché. Mettre à 0 pour toujours afficher l'affaiblissement"
+L["The direction that the bag frames be (Horizontal or Vertical)."] = "La direction des fenêtres de sac (Horizontale ou Verticale)."
+L["The direction that the bag frames will grow from the anchor."] = "La direction que prendra la barre des sacs en partant du point d'ancrage."
+L["The direction the auras will grow and then the direction they will grow after they reach the wrap after limit."] = "Sens de progression des Auras sur la ligne et comment elles vont se comporter une fois la limite atteinte."
+L["The display format of the currency icons that get displayed below the main bag. (You have to be watching a currency for this to display)"] = "Le format d'affichage des icônes de devises qui sont affichés dans les sacs. (Vous devez montrer cette devise pour l'afficher)"
+L["The display format of the money text that is shown at the top of the main bag."] = "Le format d'affichage de l'argent que vous avez visible en haut du sac principal."
+L["The display format of the money text that is shown in the gold datatext and its tooltip."] = "L'affichage du format de l'argent que vous possédez dans le texte d'informations Argent et dans son infobulle."
+L["The first button anchors itself to this point on the bar."] = "Ancrage du premier bouton sur le point de la barre."
+L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."] = "La macro suivante doit être cochée pour que le groupe soit affiché, en plus de la configuration des filtres."
+L["The font that appears on the text above players heads. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "Police qui apparait sur le texte au dessus de la tête des joueurs. |cffFF0000ATTENTION: requiert un redémarrage du jeu ou une reconnexion pour que les changements soient pris en compte.|r"
+L["The font that combat text will use. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "La police qui sera utilisée pour les textes de combat. |cffFF0000Note : Ce changement nécessite de relancer le jeu ou d'une reconnexion pour prendre effet.|r"
+L["The font that the core of the UI will use."] = "La police que le cœur de l'Interface utilisera"
+L["The font that the unitframes will use."] = "Police utilisée par défaut pour les cadres d'unités."
+L["The frame is not shown unless you mouse over the frame."] = "Le cadre est invisible tant que vous n'avez pas passé votre souris dessus."
+L["The initial group will start near the center and grow out."] = "Le premier groupe commence à proximité du centre et s'en développe hors."
+L["The minimum item level required for it to be shown."] = "Le niveau d'objet minimum requis pour être affiché"
+L["The name you have selected is already in use by another element."] = "Le nom que vous avez sélectionné est déjà utilisé par un autre élément."
+L["The object you want to attach to."] = "L'objet que vous souhaitez attacher à."
+L["The size of the action buttons."] = "Taille des boutons d'action."
+L["The size of the individual buttons on the bag frame."] = "La taille des boutons individuels sur la fenêtre du sac."
+L["The size of the individual buttons on the bank frame."] = "La taille des boutons individuels sur la fenêtre de la banque."
+L["The spacing between buttons."] = "Espacement entre deux boutons."
+L["The spacing between the backdrop and the buttons."] = "Espace entre le fond et les boutons."
+L["The texture that will be used mainly for statusbars."] = "La texture qui sera utilisé principalement pour la barre de statut."
+L["The unit prefixes you want to use when values are shortened in ElvUI. This is mostly used on UnitFrames."] = true
+L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."] = true
+L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."] = true
+L["Thin Border Theme"] = "Thème aec bordures fines"
+L["Thin Borders"] = "Bordures fines"
+L["This dictates the size of the icon when it is not attached to the castbar."] = "Ceci force la taille de l'icône lorsqu'elle n'est pas rattachée à la barre d'incantation."
+L["This feature will allow you to transfer settings to other characters."] = "Cette fonctionnalité vous permettra de transférer les paramètres à d'autres personnages."
+L["This is for Customized Icons in your Interface/Icons folder."] = true
+L["This opens the UnitFrames Color settings. These settings affect all unitframes."] = "Ouvre la configuration des couleurs des unités. Ces options impactent toutes les barres d'unités."
+L["This option allows the overlay to span the whole health, including the background."] = true
+L["This section will allow you to copy settings to a select module from or to a different profile."] = true
+L["This section will help reset specfic settings back to default."] = true
+L["This selects the Chat Frame to use as the output of ElvUI messages."] = true
+L["This setting controls the size of text in item comparison tooltips."] = true
+L["This setting will be updated upon changing stances."] = "Ce réglage sera activé lors d'un changement de posture"
+L["This texture will get used on objects like chat windows and dropdown menus."] = "Cette texture sera utilisée pour les fenêtres de discussion et les menus déroulants."
+L["This will override the global cooldown settings."] = true
+L["This will prevent the UI Scale Popup from being shown when changing the game window size."] = true
+L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."] = true
+L["Threat Display Mode"] = "Affichage du Mode de Menace."
+L["Threat Health"] = true
+L["Threat Power"] = true
+L["Threat"] = "Menace"
+L["Threshold (in minutes) before text is shown in the HH:MM format. Set to -1 to never change to this format."] = true
+L["Threshold (in seconds) before text is shown in the MM:SS format. Set to -1 to never change to this format."] = true
+L["Threshold before text goes into decimal form. Set to -1 to disable decimals."] = "Seuil avant que le texte ne s'affiche sous forme décimale. Mettre à -1 pour désactiver l'affichage en décimal."
+L["Threshold before text turns red and is in decimal form. Set to -1 for it to never turn red"] = "Seuil avant que le texte devienne rouge sous forme de décimal. Mettre -1 pour qu'il ne devienne jamais rouge."
+L["Threshold before the icon will fade out and back in. Set to -1 to disable."] = true
+L["Ticks"] = "Ticks"
+L["Time Format"] = true
+L["Time Indicator Colors"] = true
+L["Time Remaining Reverse"] = "Temps restant inversé"
+L["Time Remaining"] = "Temps restant"
+L["Time To Hold"] = true
+L["Time xOffset"] = "Décalage X du temps"
+L["Time yOffset"] = "Décalage Y du temps"
+L["Time"] = "Temps"
+L["Timestamp Color"] = "Couleur des heures"
+L["Toggle Anchors"] = "Afficher les ancres"
+L["Toggle Off While In Combat"] = true
+L["Toggle On While In Combat"] = true
+L["Toggle Tutorials"] = "Afficher les tutoriels"
+L["Toggle showing of the left and right chat panels."] = "Afficher ou masquer le côté gauche / droit des panneaux de discussion."
+L["Toggle the chat tab panel backdrop."] = "Affiche le fond de l'onglet du panneau de discussion."
+L["Toggles the display of the actionbars backdrop."] = "Affiche ou non la couleur de fond de la barre d'action."
+L["Tooltip Font Settings"] = "Configuration des polices des infobulles"
+L["Top Arrow"] = true
+L["Top Left"] = "En haut à gauche"
+L["Top Panel"] = "Bandeau en haut"
+L["Top Right"] = "En haut à droite"
+L["Top to Bottom"] = "Du haut vers le bas"
+L["Top"] = "En haut"
+L["TopLeftMiniPanel"] = "Minicarte en haut à gauche (intérieur)"
+L["TopMiniPanel"] = "Minicarte en haut (Inside)"
+L["TopRightMiniPanel"] = "Minicarte en haut à droite (intérieur)"
+L["Totem"] = true
+L["Trainer Frame"] = "Entraîneur"
+L["Transparency level when not in combat, no target exists, full health, not casting, and no focus target exists."] = true
+L["Transparent Backdrops"] = true
+L["Transparent Buttons"] = true
+L["Transparent"] = "Transparent"
+L["Triggers"] = true
+L["Turtle Color"] = "Couleur Turtle"
+L["Tutorial Frame"] = true
+L["URL Links"] = "Liens URL"
+L["Under Health Threshold"] = true
+L["Under Power Threshold"] = true
+L["Uniform Threshold"] = "Déclencheur identique"
+L["Unique Units"] = true
+L["Unit Prefix Style"] = "Style des préfixes d'unités"
+L["Unit Target"] = true
+L["Unit Type"] = true
+L["UnitFrames"] = "Cadre d'unité"
+L["Unlock various elements of the UI to be repositioned."] = "Déverrouille divers éléments de l'interface utilisateur pour être repositionné."
+L["Up"] = "Haut"
+L["Usable"] = "Uilisable"
+L["Use Alt Key"] = "Utiliser la touche Alt"
+L["Use Class Color"] = true
+L["Use Custom Level"] = "Utiliser un niveau définie"
+L["Use Custom Strata"] = "Utiliser une couche définie"
+L["Use Dead Backdrop"] = "Utiliser le fond pour les joueurs morts"
+L["Use Default"] = "Par défaut"
+L["Use Indicator Color"] = true
+L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."] = true
+L["Use Target Scale"] = true
+L["Use Threat Color"] = true
+L["Use class color for the names of players when they are mentioned."] = "Utiliser les couleurs de classe pour les noms des joueurs lorsqu'ils sont mentionnés."
+L["Use coin icons instead of colored text."] = "Utiliser les icônes de pièces au lieu du texte coloré."
+L["Use drag and drop to rearrange filter priority or right click to remove a filter."] = true
+L["Use the Name Color of the unit for the Name Glow."] = true
+L["Use the custom backdrop color instead of a multiple of the main color."] = true
+L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."] = "Utilisez un profil spécifique pour les filtres d'indicateur d'amélioration au lieu d'utiliser le filtre global."
+L["Use thin borders on certain unitframe elements."] = "Utiliser les bordures fines sur certains cadres d'unités."
+L["Use this backdrop color for units that are dead or ghosts."] = "Utiliser cette couleur de fond pour les joueurs morts ou en fantômes"
+L["Used as RaidDebuff Indicator"] = "Utiliser comme indicateur d'affaiblissement en raid"
+L["Value Color"] = "Couleur des Textes d'informations"
+L["Value must be a number"] = "La valeur doit être un nombre"
+L["Vehicle Seat Indicator Size"] = true
+L["Vehicle"] = true
+L["Vendor Gray Detailed Report"] = true
+L["Vendor Grays"] = "Vendre les objets gris"
+L["Version"] = "Version"
+L["Vertical Fill Direction"] = "Orientation verticale"
+L["Vertical Spacing"] = "Espace vertical"
+L["Vertical"] = "Verticale"
+L["Visibility State"] = "État de visibilité"
+L["Visibility"] = "Visibilité"
+L["Watch Frame"] = true
+L["What point to anchor to the frame you set to attach to."] = "Quel point d'ancrage sur le cadre vous choisissez à attacher."
+L["What to attach the buff anchor frame to."] = "Choisissez à quoi vous voulez attacher les améliorations sur le cadre."
+L["What to attach the debuff anchor frame to."] = "Choisissez à quoi vous voulez attacher les affaiblissements sur le cadre."
+L["When enabled active buff icons will light up instead of becoming darker, while inactive buff icons will become darker instead of being lit up."] = true
+L["When enabled it will only show spells that were added to the filter using a spell ID and not a name."] = "Si activé, seuls les sorts ajoutés au filtre à l'aide de leur ID et non d'un nom seront visibles."
+L["When in a raid group display if anyone in your raid is targeting the current tooltip unit."] = "Dans un groupe de raid, affiche l'infobulle d une personne ciblée par une autre."
+L["When inside a battleground display personal scoreboard information on the main datatext bars."] = "Lorsqu'à l'intérieur d'un champ de bataille, afficher le tableau des scores personnels dans la barre principale des textes d'informations."
+L["When opening the Chat Editbox to type a message having this option set means it will retain the last channel you spoke in. If this option is turned off opening the Chat Editbox should always default to the SAY channel."] = "Permet de retenir les derniers messages sur le canal de discussion que vous avez utilisé. Si cette option est désactivé, le canal utilisé par défaut sera Dire."
+L["When true, the header includes the player when not in a raid."] = "Quand coché, l'en-tête est affichée lorsque le joueur n'est pas dans un raid."
+L["When you go AFK display the AFK screen."] = "Quand vous êtes AFK, affiche un écran spécial."
+L["Whitelist"] = "Liste blanche"
+L["Width Multiplier"] = "Multiplicateur largeur"
+L["Width"] = "Largeur"
+L["Will attempt to sell another item in set interval after previous one was sold."] = true
+L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."] = "Voir les améliorations avec les affaiblissements quand il n'y a pas d'affaiblissement actif, et vice versa."
+L["Word Wrap"] = "Césure des mots"
+L["World Map Coordinates"] = "Coordonnées de la carte du Monde"
+L["World State Frame"] = true
+L["Wrap After"] = "Retour à la ligne après"
+L["X-Offset"] = "Décalage de l'axe X"
+L["Y-Offset"] = "Décalage de l'axe Y"
+L["You do not need to use 'Is Casting Anything' or 'Is Channeling Anything' for these spells to trigger."] = true
+L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."] = "Vous ne pouvez pas supprimer un sort du filtre qui est par défaut.configurer le sort en désactivé."
+L["You must be targeting a player."] = "Vous devez cibler un joueur."
+L["You need to hold this modifier down in order to blacklist an aura by right-clicking the icon. Set to None to disable the blacklist functionality."] = "Vous devez maintenir le modifieur enfoncé pour retirer une aura en cliquant du droit sur l'icône. Sélectionnez Aucun pour désactiver la liste noire."
+L["Your Auras First"] = "Vos Auras en premier"
+L["xOffset"] = "Décalage de l'axe X"
+L["yOffset"] = "Décalage de l'axe Y"
+
+L["ACTIONBARS_DESC"] = "Modifier les options des barres d'actions."
+L["AURAS_DESC"] = "Configure les icônes qui apparaissent près de la Minicarte."
+L["BAGS_DESC"] = "Ajuster les paramètres des sacs pour ElvUI."
+L["CHAT_DESC"] = "Ajuste les paramètres du chat pour ElvUI."
+L["COOLDOWN_DESC"] = "Adjust Cooldown Settings."
+L["DATATEXT_DESC"] = "Configuration de l'affichage des textes d'informations."
+L["ELVUI_DESC"] = "ElvUI est une interface de remplacement complète pour World of Warcraft."
+L["NAMEPLATE_DESC"] = "Modifier la configuration des barre de noms des unités."
+L["PANEL_DESC"] = "Ajuste la largeur et la hauteur des fenêtres de chat, cela ajuste aussi les sacs."
+L["SKINS_DESC"] = "Ajuste les paramètres d'habillage."
+L["TOGGLESKIN_DESC"] = "Active ou désactive l'habillage ElvUI des éléments ci-dessous."
+L["TOOLTIP_DESC"] = "Configuration des infobulles."
+L["UNITFRAME_DESC"] = "Modifier les options des cadres d'unités."
+L["SEARCH_SYNTAX_DESC"] = [=[With the new addition of LibItemSearch, you now have access to much more advanced item searches. The following is a documentation of the search syntax. See the full explanation at: https://github.com/Jaliborc/LibItemSearch-1.2/wiki/Search-Syntax.
+
+Specific Searching:
+ • q:[quality] or quality:[quality]. For instance, q:epic will find all epic items.
+ • l:[level], lvl:[level] or level:[level]. For example, l:30 will find all items with level 30.
+ • t:[search], type:[search] or slot:[search]. For instance, t:weapon will find all weapons.
+ • n:[name] or name:[name]. For instance, typing n:muffins will find all items with names containing "muffins".
+ • s:[set] or set:[set]. For example, s:fire will find all items in equipment sets you have with names that start with fire.
+ • r:[level], reg:[level], rl:[level], regl:[level] or reqlvl:[level]. For example, reqlvl:30 will find all items that require level 30.
+ • tt:[search], tip:[search] or tooltip:[search]. For instance, tt:binds will find all items that can be bound to account, on equip, or on pickup.
+
+
+Search Operators:
+ • ! : Negates a search. For example, !q:epic will find all items that are NOT epic.
+ • | : Joins two searches. Typing q:epic | t:weapon will find all items that are either epic OR weapons.
+ • & : Intersects two searches. For instance, q:epic & t:weapon will find all items that are epic AND weapons
+ • >, <, <=, => : Performs comparisons on numerical searches. For example, typing lvl: >30 will find all items with level HIGHER than 30.
+
+
+The following search keywords can also be used:
+ • soulbound, bound, bop : Bind on pickup items.
+ • bou : Bind on use items.
+ • boe : Bind on equip items.
+ • boa : Bind on account items.
+ • quest : Quest bound items.]=]
+
+L["TEXT_FORMAT_DESC"] = [=[Entrer une séquence pour changer le format du texte.
+
+Exemples:
+[namecolor][name] [difficultycolor][smartlevel] [shortclassification]
+[healthcolor][health:current-max]
+[powercolor][power:current]
+
+Formats de la Vie / des Ressources:
+'current' - Quantité actuelle
+'percent' - Quantité en pourcentage
+'current-max' - Quantité actuelle maximale, n'affichera seulement la quantité maximale si la quantité actuelle est égale au maximum.
+'current-percent' - Quantité actuelle suivie par quantité en pourcentage, n'affichera seulement la quantité maximale si la quantité actuelle est égale au maximum
+'current-max-percent' - Quantité actuelle, quantité maximale, suivie par quantité en pourcentage, n'affichera seulement la quantité maximale si la quantité actuelle est égale au maximum
+'deficit' - Affiche la valeur du déficit, n'affichera rien si il n'y a pas de déficit
+
+Format des Noms:
+'name:short' - Nom limité à 10 caractères
+'name:medium' - Nom limité à 15 caractères
+'name:long' - Nom limité à 20 caractères
+
+Pour désactiver, laisser le champs vide. Pour plus d'information, merci de visiter https://www.tukui.org/forum/viewtopic.php?t=6]=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to page differently.
+ Example: '[combat] 2;']=] ] = [=[Ceci fonctionne comme une macro, vous pouvez exécuter différentes situations pour avoir une pagination de la barre d'actions différente.
+ Exemple: '[combat] 2;']=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to show/hide differently.
+ Example: '[combat] show;hide']=] ] = [=[Ceci fonctionne comme une macro, vous pouvez exécuter différentes situations pour afficher ou masquer la barre d'actions différemment.
+ Exemple: '[combat] show;hide']=]
+
+L[ [=[Specify a filename located inside the World of Warcraft directory. Textures folder that you wish to have set as a panel background.
+
+Please Note:
+-The image size recommended is 256x128
+-You must do a complete game restart after adding a file to the folder.
+-The file type must be tga format.
+
+Example: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Or for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here.]=] ] = [=[Indiquez un nom de fichier situé dans le répertoire World of Warcraft, le dossier des Textures que vous souhaitez utiliser en fond de panneau.
+
+Notez:
+La taille de l'image recommandée est de 256x128 pixels
+Vous devez redémarrer le jeu après avoir ajouté un fichier dans le dossier.
+Le format du fichier doit être en .tga
+
+Exemple: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Ou pour la majorité des utilsateurs, il serait plus simple de mettre le fichier tga dans le dossier de World of Warcraft puis de taper son nom ici.]=]
+
+-- Global Strings
+L["ACHIEVEMENTS"] = "Hauts faits"
+L["ALT_KEY_TEXT"] = "ALT"
+L["ARENA"] = "Arène"
+L["AUCTIONS"] = "Ventes"
+L["BAGSLOT"] = "Sac"
+L["BARBERSHOP"] = "Salon de coiffure"
+L["BATTLEGROUND"] = "Champ de bataille"
+L["BATTLEFIELDS"] = "Champs de bataille"
+L["BLOCK"] = "Blocage"
+L["BUFFOPTIONS_LABEL"] = "Améliorations et affaiblissements"
+L["CLASS"] = "Classe"
+L["CHANNEL"] = "Canal"
+L["COLOR"] = "Couleur"
+L["COLORS"] = "Couleurs"
+L["COMBAT"] = "Combat"
+L["COMBAT_TEXT_RUNE_BLOOD"] = "Rune de sang"
+L["COMBAT_TEXT_RUNE_DEATH"] = "Rune de la mort"
+L["COMBAT_TEXT_RUNE_FROST"] = "Rune de givre"
+L["COMBAT_TEXT_RUNE_UNHOLY"] = "Rune impie"
+L["COMBO_POINTS"] = "|4Point:Points; de combo"
+L["CTRL_KEY"] = "CTRL"
+L["CUSTOM"] = "Personnalisé"
+L["DAMAGER"] = "Dégâts"
+L["DEFAULT"] = "Défaut"
+L["DELETE"] = "Suppr."
+L["DISABLE"] = "Désactiver"
+L["DRESSUP_FRAME"] = "Cabine d'essayage"
+L["DUNGEON_DIFFICULTY"] = "Difficulté du donjon"
+L["DUNGEONS"] = "Donjons"
+L["EMOTE"] = "Emote"
+L["ENEMY"] = "Ennemi"
+L["ENERGY"] = "Énergie"
+L["FACTION_STANDING_LABEL1"] = "Haï"
+L["FACTION_STANDING_LABEL2"] = "Hostile"
+L["FACTION_STANDING_LABEL3"] = "Inamical"
+L["FACTION_STANDING_LABEL4"] = "Neutre"
+L["FACTION_STANDING_LABEL5"] = "Amical"
+L["FACTION_STANDING_LABEL6"] = "Honoré"
+L["FACTION_STANDING_LABEL7"] = "Révéré"
+L["FACTION_STANDING_LABEL8"] = "Exalté"
+L["FILTERS"] = "Filtres"
+L["FLIGHT_MAP"] = "Carte des trajets aériens"
+L["FOCUS"] = "Focalisation"
+L["FONT_SIZE"] = "Taille de la police"
+L["FRIEND"] = "Ami"
+L["FRIENDS"] = "Contacts"
+L["GROUP"] = "Groupe"
+L["GUILD"] = "Guilde"
+L["GUILD_BANK"] = "Banque de guilde"
+L["HAPPINESS"] = "Satisfaction"
+L["HEALER"] = "Soigneur"
+L["HEALTH"] = "Vie"
+L["HIDE"] = "Cacher"
+L["INSCRIPTION"] = "Calligraphie"
+L["INSPECT"] = "Inspecter"
+L["INTERFACE_OPTIONS"] = "Options d'interface"
+L["INTERRUPTED"] = "Interrompu"
+L["ITEM_BIND_QUEST"] = "Objet de quête"
+L["ITEMS"] = "Objets"
+L["LANGUAGE"] = "Langue"
+L["LEAVE_VEHICLE"] = "Sortir du véhicule"
+L["LEVEL"] = "Niveau"
+L["LOCK_ACTIONBAR_TEXT"] = "Verr. barres d'actions"
+L["LOOT"] = "Butin"
+L["MACROS"] = "Macros"
+L["MAIL_LABEL"] = "Courrier"
+L["MANA"] = "Mana"
+L["MAP_FADE_TEXT"] = "Disparition de la carte en mouvement"
+L["MERCHANT"] = "Marchand"
+L["MINIMAP_LABEL"] = "Minicarte"
+L["MISCELLANEOUS"] = "Divers"
+L["NAME"] = "Nom"
+L["NONE"] = "Aucun"
+L["OFFICER"] = "Officier"
+L["OPACITY"] = "Opacité"
+L["OPTION_TOOLTIP_ACTION_BUTTON_USE_KEY_DOWN"] = "Les boutons d’action associés à un raccourci clavier se déclencheront au moment où la touche est enfoncée, et non relâchée."
+L["OPTION_TOOLTIP_TIMESTAMPS"] = "Sélectionner le format de l'heure dans les fenêtres de discussion."
+L["PARTY"] = "Groupe"
+L["PET"] = "Familier"
+L["PLAYER"] = "Joueur"
+L["PLAYER_DIFFICULTY1"] = "Normal"
+L["PLAYER_DIFFICULTY2"] = "Héroïque"
+L["RAGE"] = "Rage"
+L["RAID"] = "Raid"
+L["RAID_TARGET_1"] = "Étoile"
+L["RAID_TARGET_2"] = "Cercle"
+L["RAID_TARGET_3"] = "Losange"
+L["RAID_TARGET_4"] = "Triangle"
+L["RAID_TARGET_5"] = "Lune"
+L["RAID_TARGET_6"] = "Carré"
+L["RAID_TARGET_7"] = "Croix"
+L["RAID_TARGET_8"] = "Crâne"
+L["REPUTATION"] = "Réputation"
+L["ROLE"] = "Rôle"
+L["RUNIC_POWER"] = "P. runique"
+L["SAY"] = "Dire"
+L["SHIFT_KEY"] = "MAJ"
+L["SHORT"] = "Court"
+L["SHOW"] = "Afficher"
+L["SPEED"] = "Vitesse"
+L["SPELLBOOK"] = "Grimoire"
+L["TANK"] = "Tank"
+L["TARGET"] = "Cibler"
+L["TIMEMANAGER_TITLE"] = "Horloge"
+L["TIMESTAMPS_LABEL"] = "Heures des messages"
+L["TRADE"] = "Échanger"
+L["TRADESKILLS"] = "Artisanat"
+L["TUTORIAL_TITLE47"] = "Barre de totems"
+L["UI_SCALE"] = "Échelle de l’interface "
+L["UNIT_NAMEPLATES_TYPES"] = "Affichage des barres d’info"
+L["UNIT_NAMEPLATES_TYPE_1"] = "Barres d’info superposées"
+L["UNIT_NAMEPLATES_TYPE_2"] = "Barres d’info empilées"
+L["WHISPER"] = "Chuchoter"
+L["WORLD_MAP"] = "Carte"
+L["XPBAR_LABEL"] = "Barre d'expérience"
+L["YELL"] = "Crier"
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Locales/koKR.lua b/ElvUI_OptionsUI/Locales/koKR.lua
new file mode 100644
index 0000000..a2419ee
--- /dev/null
+++ b/ElvUI_OptionsUI/Locales/koKR.lua
@@ -0,0 +1,1429 @@
+-- Korean localization file for koKR.
+local L = ElvUI[1].Libs.ACL:NewLocale("ElvUI", "koKR")
+
+L["%s and then %s"] = "%s 이후 %s"
+L["2D"] = "이미지"
+L["3D"] = "3d 모델"
+L["AFK Mode"] = "자리비움 모드"
+L["ANCHOR_CURSOR"] = true
+L["ANCHOR_CURSOR_LEFT"] = true
+L["ANCHOR_CURSOR_RIGHT"] = true
+L["Abbreviation"] = true
+L["Above Chat"] = "채팅창 위에 배치"
+L["Above"] = "프레임 위로"
+L["Accept Invites"] = "지인의 초대 자동수락"
+L["Action Paging"] = "페이지 자동전환 조건"
+L["ActionBars"] = "행동단축바"
+L["Actions"] = true
+L["Add Item or Search Syntax"] = "아이템 또는 검색 구문 추가"
+L["Add Name"] = true
+L["Add Regular Filter"] = "일반 필터 추가"
+L["Add Special Filter"] = "특수 필터 추가"
+L["Add Spell ID or Name"] = "주문ID 또는 이름 추가하기"
+L["Add SpellID"] = "주문 ID 추가"
+L["Add a Name to the list."] = true
+L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."] = true
+L["Add a spell to the filter."] = "필터에 주문을 추가합니다."
+L["Add an item or search syntax to the ignored list. Items matching the search syntax will be ignored."] = "아이템 또는 검색 구문을 제외할 목록에 추가합니다. 검색 구문과 일치하는 아이템들을 제외하게 될 것입니다."
+L["Additional Power Text"] = true
+L["Additional spacing between each individual group."] = true
+L["Additive Blend"] = true
+L["Adjust the height of your right chat panel."] = "우측 패널의 세로길이를 결정합니다."
+L["Adjust the position of the threat bar to either the left or right datatext panels."] = "위협수치 바를 어느 패널의 정보문자 탭에 배치할지 결정합니다."
+L["Adjust the size of the minimap."] = "미니맵의 크기를 결정합니다."
+L["Adjust the width of the bag frame."] = "통합가방 프레임의 가로길이를 결정합니다."
+L["Adjust the width of the bank frame."] = "통합은행 프레임의 가로길이를 결정합니다."
+L["Adjust the width of your right chat panel."] = "우측 패널의 가로길이를 결정합니다."
+L["Alert Frames"] = "알림 프레임"
+L["Alerts"] = "알림"
+L["Allow LBF to handle the skinning of this element."] = "LBF가 이 요소의 스킨에 관여하도록 허용합니다."
+L["Allowed Combat Repeat"] = "전투 반복 허용수"
+L["Alpha Fading"] = true
+L["Alpha Key"] = true
+L["Alpha channel is taken from the color option."] = true
+L["Alpha"] = "투명도"
+L["Always Display"] = "항상 표시"
+L["Always Hide"] = "표시하지 않음"
+L["Always Show Realm"] = true
+L["Always Show Target Health"] = true
+L["Ammo Pouch"] = true
+L["An X offset (in pixels) to be used when anchoring new frames."] = "기준 프레임에서 가로로 얼마만큼 떨어져 있을지를 결정합니다."
+L["An Y offset (in pixels) to be used when anchoring new frames."] = "기준 프레임에서 세로로 얼마만큼 떨어져 있을지를 결정합니다."
+L["Anchor Point"] = "기준점"
+L["Announce Interrupts"] = "차단 성공시 알림"
+L["Announce when you interrupt a spell to the specified chat channel."] = "주문 차단에 성공하면 여기에서 설정한 채널로 차단성공을 알립니다."
+L["Applies the font and font size settings throughout the entire user interface. Note: Some font size settings will be skipped due to them having a smaller font size by default."] = "글씨와 글씨 크기 설정을 전체 사용자 인터페이스에 두루 적용합니다. 알림: 일부 글씨 크기 설정은 작은 글씨 크기가 기본값으로 지정되어 예외가 될 것입니다."
+L["Applies the primary texture to all statusbars."] = "주 텍스쳐를 모든 상태바에 적용합니다."
+L["Apply Font To All"] = "글씨체 전체에 적용"
+L["Apply Texture To All"] = "텍스쳐 전체에 적용"
+L["Apply this filter if a buff has remaining time greater than this. Set to zero to disable."] = "강화효과의 남은 시간이 이보다 클 때만 필터를 적용합니다. |n|n0으로 두면 비활성화 됩니다."
+L["Apply this filter if a buff has remaining time less than this. Set to zero to disable."] = "강화효과의 남은 시간이 이보다 작을 때만 필터를 적용합니다. |n|n0으로 두면 비활성화 됩니다."
+L["Apply this filter if a debuff has remaining time greater than this. Set to zero to disable."] = "약화효과의 남은 시간이 이보다 클 때만 필터를 적용합니다. |n|n0으로 두면 비활성화 됩니다."
+L["Apply this filter if a debuff has remaining time less than this. Set to zero to disable."] = "약화효과의 남은 시간이 이보다 작을 때만 필터를 적용합니다. |n|n0으로 두면 비활성화 됩니다."
+L["Are you sure you want to reset ActionBars settings?"] = true
+L["Are you sure you want to reset Auras settings?"] = true
+L["Are you sure you want to reset Bags settings?"] = true
+L["Are you sure you want to reset Chat settings?"] = true
+L["Are you sure you want to reset Cooldown settings?"] = true
+L["Are you sure you want to reset DataBars settings?"] = true
+L["Are you sure you want to reset DataTexts settings?"] = true
+L["Are you sure you want to reset General settings?"] = true
+L["Are you sure you want to reset NamePlates settings?"] = true
+L["Are you sure you want to reset Tooltip settings?"] = true
+L["Are you sure you want to reset UnitFrames settings?"] = true
+L["Arena Frame"] = true
+L["Arena Registrar"] = true
+L["Arena"] = "투기장"
+L["Ascending or Descending order."] = true
+L["Ascending"] = "오름차순"
+L["Assist Target"] = "지원공격 전담 프레임"
+L["Assist"] = true
+L["At what point should the text be displayed. Set to -1 to disable."] = "이 값보다 시간이 낮아지면 글자가 표시됩니다.|n|n-1로 설정하면 이 기능을 사용하지 않습니다."
+L["Attach Text To"] = true
+L["Attach To"] = "기준 프레임"
+L["Attempt to create URL links inside the chat."] = "대화 내역에 URL 주소가 있으면 강조하고 클릭 시 복사할 수 있게끔 합니다."
+L["Attempt to lock the left and right chat frame positions. Disabling this option will allow you to move the main chat frame anywhere you wish."] = "좌우측 패널에 채팅창 고정 여부를 결정합니다. 체크 해제 시 좌측에 고정된 기본 채팅창도 움직일 수 있습니다."
+L["Attempt to support eyefinity/nvidia surround."] = "다중모니터 기술인 아이피니티 기능이나 nvidia 서라운드 기능 지원을 적용합니다."
+L["Aura Bars"] = "클래스타이머"
+L["Aura Filters"] = "오라 필터"
+L["Auto Greed/DE"] = "자동 차비/추출 선택"
+L["Auto Hide"] = true
+L["Auto Repair"] = "자동 수리"
+L["Auto-Hide"] = "자동으로 숨기기"
+L["Automatic"] = "자동"
+L["Automatically accept invites from guild/friends."] = "길드원이나 친구가 플레이어를 파티를 초대하면 자동으로 수락합니다."
+L["Automatically hide the objetive frame during boss or arena fights."] = true
+L["Automatically repair using the following method when visiting a merchant."] = "수리가 가능한 상점을 열면 이 옵션에서 선택한 자금으로 장비를 자동 수리합니다."
+L["Automatically select greed or disenchant (when available) on green quality items. This will only work if you are the max level."] = "녹템 주사위창이 뜨면 자동으로 차비나 마력추출을 선택합니다. 이 기능은 오로지 만렙 캐릭터에서만 동작합니다."
+L["Automatically vendor gray items when visiting a vendor."] = "상점이 열리면 잡동사니를 자동으로 판매합니다."
+L["Available Tags"] = true
+L["BG Map"] = "전장 맵"
+L["BG Score"] = "전장 점수판"
+L["BINDING_HEADER_RAID_TARGET"] = "대상 표시기"
+L["BOSS"] = true
+L["Backdrop Color"] = "배경 색상"
+L["Backdrop Faded Color"] = "반투명 배경 색상"
+L["Backdrop Spacing"] = "배경 여백"
+L["Backdrop color of transparent frames"] = "ElvUI에서 생성하는 모든 반투명한 프레임의 배경 색상과 투명도를 결정합니다."
+L["Backdrop"] = "배경"
+L["Background Glow"] = "배경 밝게"
+L["Bad Color"] = "나쁨 색상"
+L["Bad Scale"] = "나쁨 범위"
+L["Bad Transition Color"] = "나쁨 전환 색상"
+L["Bad"] = "나쁨"
+L["Bag 1"] = true
+L["Bag 2"] = true
+L["Bag 3"] = true
+L["Bag 4"] = true
+L["Bag Sorting"] = "가방 정리"
+L["Bag Spacing"] = true
+L["Bag"] = true
+L["Bag-Bar"] = "가방바"
+L["Bags Only"] = "가방 안에만"
+L["Bags/Bank"] = "가방/은행"
+L["Bank 1"] = true
+L["Bank 2"] = true
+L["Bank 3"] = true
+L["Bank 4"] = true
+L["Bank 5"] = true
+L["Bank 6"] = true
+L["Bank 7"] = true
+L["Bank Only"] = "은행 안에만"
+L["Bar Direction"] = "바 방향"
+L["Bars will transition smoothly."] = "바의 증감을 부드럽게 표현합니다."
+L["Battleground Texts"] = "전장에서 표시전환"
+L["Begin a new row or column after this many auras."] = "한 줄에 아이콘이 이 값보다 많으면 다음 줄에 배치합니다."
+L["Below Chat"] = "채팅창 아래에 배치"
+L["Below"] = "프레임 아래로"
+L["Blacklist Modifier"] = true
+L["Blacklist"] = "블랙리스트"
+L["Blend Mode"] = true
+L["Blend"] = true
+L["BlizzUI Improvements"] = true
+L["Blizzard Style"] = "블리자드 기본"
+L["Blizzard"] = true
+L["Block Combat Click"] = "전투중 클릭 끄기"
+L["Block Combat Hover"] = "전투중 마우스 반응 끄기"
+L["Block Mouseover Glow"] = true
+L["Block Target Glow"] = true
+L["Blocks all click events while in combat."] = "전투중에 정보문자 클릭 관련 기능이 차단됩니다."
+L["Blocks datatext tooltip from showing in combat."] = "전투중에 정보문자 마우스 오버 툴팁이 표시되는 것을 차단합니다."
+L["Border Color"] = "테두리 색상"
+L["Border Glow"] = "테두리 밝게"
+L["Border"] = "테두리"
+L["Borders"] = "테두리"
+L["Both"] = "가방, 은행 모두"
+L["Bottom Left"] = "하단 좌측"
+L["Bottom Panel"] = "하단 패널 표시"
+L["Bottom Right"] = "하단 우측"
+L["Bottom to Top"] = "상단 아래쪽으로 이동"
+L["Bottom"] = "하단 중앙"
+L["BottomLeftMiniPanel"] = "미니맵 좌하단 (내부)"
+L["BottomMiniPanel"] = "미니맵 하단 (내부)"
+L["BottomRightMiniPanel"] = "미니맵 우하단 (내부)"
+L["Buff Indicator"] = "강화효과 알람"
+L["Button Size (Bag)"] = "슬롯 크기 (가방)"
+L["Button Size (Bank)"] = "슬롯 크기 (은행)"
+L["Button Size"] = "버튼 크기"
+L["Button Spacing"] = "버튼 간격"
+L["Buttons Per Row"] = "한 줄당 버튼 수"
+L["Buttons"] = "버튼 수"
+L["By Type"] = "종류에 따라서"
+L["Calendar Frame"] = "달력"
+L["Cast Bar"] = "시전바"
+L["Cast Color"] = "시전 색상"
+L["Cast No Interrupt Color"] = "차단 불가 시전 색상"
+L["Cast Time Format"] = "시전 시간 형식"
+L["Castbar"] = "시전바"
+L["Casting"] = "시전중"
+L["Center"] = "정 중앙"
+L["Change settings for the display of the location text that is on the minimap."] = "미니맵 상단에 있는 지역이름의 표시방법을 결정합니다."
+L["Change the alpha level of the frame."] = "해당 프레임의 투명한 수준을 결정합니다."
+L["Channel Alerts"] = true
+L["Change the width and controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Channel Time Format"] = "채널링 시간 형식"
+L["Character Frame"] = "캐릭터 창"
+L["Chat Bubble Names"] = "말풍선에 이름 표시"
+L["Chat Bubbles Style"] = "말풍선 디자인"
+L["Chat Bubbles"] = "말풍선"
+L["Chat EditBox Position"] = "대화입력창 위치"
+L["Chat Output"] = true
+L["Check these to only have the filter active in certain difficulties. If none are checked, it is active in all difficulties."] = true
+L["CheckBox Skin"] = true
+L["Choose Export Format"] = "내보낼 형태 선택"
+L["Choose UIPARENT to prevent it from hiding with the unitframe."] = true
+L["Choose What To Export"] = "내보낼 내용 선택"
+L["Choose when you want the tooltip to show in combat. If a modifer is chosen, then you need to hold that down to show the tooltip."] = true
+L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."] = "툴팁을 언제 보이게 할 지 선택합니다. 조절키를 선택하면, 해당 키를 누르고 있는 동안에만 툴팁을 표시합니다."
+L["Class Backdrop"] = "배경에 직업색상 적용"
+L["Class Castbars"] = "직업색상 사용"
+L["Class Color Mentions"] = "언급시 직업색상 표시"
+L["Class Color Override"] = "직업색 적용 여부"
+L["Class Health"] = "직업색상 사용"
+L["Class Power"] = "직업색상 사용"
+L["Class Resources"] = "직업별 특수 자원바"
+L["Class Totems"] = "직업 토템"
+L["Clear Filter"] = "필터 정리"
+L["Clear Search On Close"] = "닫으면 검색 칸 비우기"
+L["Click Through"] = "마우스 무시"
+L["Clickable Height"] = "클릭되는 높이"
+L["Clickable Size"] = true
+L["Clickable Width / Width"] = true
+L["Coding:"] = "|cff2eb7e4< 개발자 >|r"
+L["Color Keybind Text when Out of Range, instead of the button."] = "사정거리에서 벗어났을때 버튼 대신 단축키 글씨의 색상을 변경합니다."
+L["Color Keybind Text"] = "단축키 글씨만 채색"
+L["Color Override"] = true
+L["Color Turtle Buffs"] = "생존기류 따로 색상지정"
+L["Color all buffs that reduce the unit's incoming damage."] = "유닛이 입는 데미지를 줄이는 모든 생존류 기술에 이 색상을 적용합니다."
+L["Color aurabar debuffs by type."] = "약화효과 종류에 따라서 클래스타이머의 색상을 따로 입힙니다.|n|n예로 독계열 약화효과는 초록색 바로 표시되게 됩니다."
+L["Color by Value"] = true
+L["Color castbars by the class of player units."] = "시전바를 플레이어 직업색상으로 칠합니다."
+L["Color castbars by the reaction type of non-player units."] = "플레이어가 아닌 유닛의 관계 형태에 따른 시전바 색상으로 변경합니다."
+L["Color health by amount remaining."] = "기존에 설정된 색상에서 생명력이 줄어들 때 마다 점차 빨간색으로 변화합니다."
+L["Color health by classcolor or reaction."] = "생명력을 직업색상 또는 관계색으로 칠합니다."
+L["Color health by threat status."] = true
+L["Color of the actionbutton when not usable."] = "사용이 불가능할 경우 아이콘에 이 색상이 덧칠됩니다."
+L["Color of the actionbutton when out of power (Mana, Rage)."] = true
+L["Color of the actionbutton when out of range."] = "대상이 버튼에 배치된 행동에 필요한 사정거리보다 밖에 있으면 아이콘에 이 색상이 덧칠됩니다."
+L["Color of the actionbutton when usable."] = "사용 가능할 경우 아이콘이 이 색상으로 덧칠됩니다."
+L["Color power by classcolor or reaction."] = "자원을 직업색상 또는 관계색으로 칠합니다."
+L["Color power by threat status."] = true
+L["Color some texts use."] = "일부 문자나 프레임을 강조할 때 이 색상을 사용합니다."
+L["Color the health backdrop by class or reaction."] = "생명력 배경을 직석생상 또는 관계색으로 칠합니다."
+L["Color the unit healthbar if there is a debuff that can be dispelled by you."] = "플레이어가 해제할 수 있는 약화효과를 가졌다면 생명력바에 색상을 입혀 강조합니다."
+L["Color when the text is about to expire"] = "버튼에 배치된 행동의 재사용 대기시간이 초읽기 상태일 경우 글자색"
+L["Color when the text is in the days format."] = "버튼에 배치된 행동의 재사용 대기시간이 일 단위일 경우 글자색"
+L["Color when the text is in the hours format."] = "버튼에 배치된 행동의 재사용 대기시간이 시간 단위일 경우 글자색"
+L["Color when the text is in the minutes format."] = "버튼에 배치된 행동의 재사용 대기시간이 분 단위일 경우 글자색"
+L["Color when the text is in the seconds format."] = "버튼에 배치된 행동의 재사용 대기시간이 초 단위일 경우 글자색"
+L["Colored Icon"] = "색상자 아이콘"
+L["Coloring (Specific)"] = "색상 설정 (지정)"
+L["Coloring"] = "색상 설정 (공통)"
+L["Colorize Selected Text"] = true
+L["Colors the border according to the Quality of the Item."] = true
+L["Combat Icon"] = "전투 아이콘"
+L["Combat Override Key"] = true
+L["CombatText Font"] = "전투 상황 글꼴"
+L["Combo Point"] = "연계 점수"
+L["Comparison Font Size"] = "비교 글씨 크기"
+L["Condensed"] = "간략하게"
+L["Configure Auras"] = "오라 설정"
+L["Control enemy nameplates toggling on or off when in combat."] = "적군 이름표의 전투중 표시여부를 조절합니다."
+L["Control friendly nameplates toggling on or off when in combat."] = "아군 이름표의 전투중 표시여부를 조절합니다."
+L["Controls how big of an area on the screen will accept clicks to target unit."] = "해당 유닛의 표시부에서 클릭이 수용되는 영역의 크기를 조절합니다."
+L["Controls the amount of decimals used in values displayed on elements like NamePlates and UnitFrames."] = "이름표와 유닛프레임 등에 구성요소로 표시되는 수치들이 소숫점 몇 자리까지 나타낼지 조정합니다."
+L["Controls the speed at which smoothed bars will be updated."] = true
+L["Controls how many seconds of inactivity has to pass before chat is faded."] = true
+L["Cooldown Orientation"] = true
+L["Cooldown Text"] = "재사용 대기시간 설정"
+L["Cooldowns"] = "재사용 대기시간"
+L["Copy From"] = "복사해오기"
+L["Copy Settings From"] = "설정 복사해서 가져오기"
+L["Copy settings from another unit."] = "다른 부분에서 설정을 복사하여 가져옵니다."
+L["Core |cff1784d1E|r|cffe5e3e3lvUI|r options."] = true
+L["Count Font Size"] = "중첩수 글꼴 크기"
+L["Count xOffset"] = "중첩수 x 좌표"
+L["Count yOffset"] = "중첩수 y 좌표"
+L["Create Custom Text"] = "사용자 지정 문자 생성"
+L["Create Filter"] = "필터 생성"
+L["Create a filter, once created a filter can be set inside the buffs/debuffs section of each unit."] = "각 유닛의 강화/약화효과에 필터를 생성합니다."
+L["Credits"] = "제작자"
+L["Crop Icons"] = true
+L["Currency Format"] = "화폐 표시방법"
+L["Current - Max | Percent"] = true
+L["Current - Max"] = "현재값 - 최대값"
+L["Current - Percent (Remaining)"] = "현재값 - 백분율(남은값)"
+L["Current - Percent"] = "현재값 - %"
+L["Current - Remaining"] = "현재값 - 남은값"
+L["Current / Max"] = "현재값 / 최대값"
+L["Current Level"] = true
+L["Current"] = "현재값"
+L["Curse Effect"] = true
+L["Cursor Anchor Offset X"] = true
+L["Cursor Anchor Offset Y"] = true
+L["Cursor Anchor Type"] = true
+L["Cursor Anchor"] = "툴팁을 마우스에 표시"
+L["Custom Backdrop"] = true
+L["Custom Color"] = true
+L["Custom Dead Backdrop"] = "사용자지정 죽음 배경"
+L["Custom Faction Colors"] = "반응색 개인설정"
+L["Custom Texts"] = "사용자지정 문자"
+L["Custom Texture"] = "사용자 지정 텍스쳐"
+L["Custom Timestamp Color"] = "시간표시 색상 사용자 설정"
+L["Cutaway Bars"] = true
+L["DATABAR_DESC"] = true
+L["Darken Inactive"] = "킨 태세만 아이콘 표시"
+L["DataBars"] = "정보막대"
+L["DataTexts"] = "정보문자"
+L["Datatext Panel (Left)"] = "좌측 정보문자 탭 사용"
+L["Datatext Panel (Right)"] = "우측 정보문자 탭 사용"
+L["Date Format"] = true
+L["Days"] = "일 단위 색상"
+L["Debuff Highlighting"] = "해제가능한 약화효과 강조"
+L["Debug Tools"] = "오류 확인 창"
+L["Decimal Length"] = "소숫점 자릿수"
+L["Decimal Threshold"] = "소수점표시 기준"
+L["Decode Text"] = "문자 해독"
+L["Default Color"] = "기본 색상"
+L["Default Font"] = "기본 글꼴"
+L["Default Settings"] = "기본 설정"
+L["Deficit"] = "부족"
+L["Defines how the group is sorted."] = "오라를 어떤 기준으로 정렬할지를 결정합니다."
+L["Defines the sort order of the selected sort method."] = "선택한 정렬 기준으로 정렬할 순서를 지정합니다."
+L["Delete Filter"] = "필터 삭제"
+L["Delete a created filter, you cannot delete pre-existing filters, only custom ones."] = "생성된 필터를 제거합니다. 단, 추가로 생성한 필터만 제거가 가능합니다."
+L["Desaturate Cooldowns"] = "재사용 대기중일 때 흑백처리"
+L["Desaturate Junk Items"] = true
+L["Desaturated Icon"] = true
+L["Descending"] = "내림차순"
+L["Detach From Frame"] = "유닛프레임에서 분리"
+L["Detached Width"] = "분리했을 때 가로길이"
+L["Direction the bag sorting will use to allocate the items."] = "정렬기능을 실행할 때 체크 시 아이템이 가방칸의 우측하단을, 체크 해제 시 좌측상단을 기준으로 모아서 정렬됩니다."
+L["Direction the bar moves on gains/losses"] = "바의 증감방향을 결정합니다."
+L["Direction the health bar moves when gaining/losing health."] = "생명력의 증감 방향을 결정합니다. (가로/세로)"
+L["Disable Bag Sort"] = "가방 정리 비활성"
+L["Disable Bank Sort"] = "은행 정리 비활성"
+L["Disable Debuff Highlight"] = "약화효과 강조 비활성화"
+L["Disabled Blizzard Frames"] = "비활성화된 블리자드 프레임"
+L["Disabled Blizzard"] = "기본 오라창 미사용"
+L["Disables the focus and target of focus unitframes."] = "주시대상, 주시대상의 대상 프레임 비활성화"
+L["Disables the player and pet unitframes."] = "플레이어, 소환수 프레임 비활성화"
+L["Disables the target and target of target unitframes."] = "대상, 대상의 대상 프레임 비활성"
+L["Disconnected"] = "오프라인"
+L["Disease Effect"] = true
+L["Display Frames"] = "프레임 표시"
+L["Display Item Level"] = "템렙 표시"
+L["Display Player"] = "플레이어 표시"
+L["Display Target"] = "시전 목표 표시"
+L["Display Text"] = "남은시간 표시"
+L["Display a healer icon over known healers inside battlegrounds or arenas."] = "전장이나 투기장에서 유닛이 힐러인 경우 이름표에 힐러 아이콘을 표시합니다."
+L["Display a panel across the bottom of the screen. This is for cosmetic only."] = "화면 하단에 꾸미기 용도의 바를 생성합니다."
+L["Display a panel across the top of the screen. This is for cosmetic only."] = "화면 상단에 꾸미기 용도의 바를 생성합니다."
+L["Display a spark texture at the end of the castbar statusbar to help show the differance between castbar and backdrop."] = "시전바와 배경의 구분을 위해 시전바의 끝부분에 반짝임 텍스쳐를 표시합니다."
+L["Display an exclamation mark on items that starts a quest."] = true
+L["Display battleground messages in the middle of the screen."] = "화면 중간에 전장 메시지를 표시합니다."
+L["Display bind names on action buttons."] = "버튼에 지정된 단축키를 표시할지 여부를 결정합니다."
+L["Display cooldown text on anything with the cooldown spiral."] = "재사용 대기시간을 가진 모든 것에 시간을 표시합니다."
+L["Display data panels below the chat, used for datatexts."] = "패널의 하단에 정보문자 탭을 추가합니다. 이 탭에 정보문자가 있게 됩니다."
+L["Display emotion icons in chat."] = "메시지 안에 이모티콘이 있으면 그림으로 바꿔 보여줍니다."
+L["Display guild ranks if a unit is guilded."] = "길드명과 함께 길드 등급도 표시합니다."
+L["Display how many of a certain item you have in your possession."] = "현재 툴팁으로 보고있는 아이템을 여러개 갖고 있다면 갯수를 표시합니다."
+L["Display macro names on action buttons."] = "버튼에 배치된 매크로의 이름을 표시할지 여부를 결정합니다."
+L["Display minimap panels below the minimap, used for datatexts."] = "미니맵 하단에 2개의 정보문자를 추가합니다."
+L["Display player titles."] = "이름에 칭호도 표시합니다."
+L["Display reminder bar on the minimap."] = true
+L["Display the castbar icon inside the castbar."] = "시전바 내부에 시전바 아이콘을 표시합니다."
+L["Display the castbar inside the information panel, the icon will be displayed outside the main unitframe."] = "정보 패널 내부에 시전바를 표시하며, 아이콘은 주 유닛프레임 외부에 표시합니다."
+L["Display the hyperlink tooltip while hovering over a hyperlink."] = "각종 링크에 커서를 갖다 댄(마우스오버) 동안에 링크에 대한 툴팁을 표시합니다."
+L["Display the junk icon on all grey items that can be vendored."] = "판매 가능한 모든 회색 템에 아이콘을 표시합니다."
+L["Display the name of the unit on the chat bubble."] = true
+L["Display the npc ID when mousing over a npc tooltip."] = true
+L["Display the spell or item ID when mousing over a spell or item tooltip."] = "아이템과 주문 툴팁에 각각의 ID를 표시합니다."
+L["Display the target of your current cast. Useful for mouseover casts."] = "현재 캐스팅중인 기술의 목표를 기술명에 표기합니다. 마우스오버로 기술을 시전할 때 대상을 파악하기 좋습니다."
+L["Display tick marks on the castbar for channelled spells. This will adjust automatically for spells like Drain Soul and add additional ticks based on haste."] = "시전바에 시전되는 주문의 틱을 표시합니다. 영혼 흡수나 가속이 추가되는 주문에 따라 틱이 자동 조절됩니다."
+L["Displayed server time."] = true
+L["Displays a detailed report of every item sold when enabled."] = "활성화하면 판매된 모든 아이템의 상세보고를 표시합니다."
+L["Displays item level on equippable items."] = "착용 가능한 아이템의 경우 아이템 슬롯에 템렙을 표시합니다."
+L["Display Types"] = true
+L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."] = "이 값보다 긴 시간(초단위)의 효과들을 표시하지 않습니다.|n|n0으로 설정하면 이 기능을 사용하지 않습니다."
+L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."] = "이 값보다 짧은 시간(초단위)의 효과들을 표시하지 않습니다.|n|n0으로 설정하면 이 기능을 사용하지 않습니다."
+L["Donations:"] = "|cff2eb7e4< 기부자 >|r"
+L["Down"] = "아래로"
+L["Dropdown CheckBox Skin"] = true
+L["Dungeon & Raid Filter"] = "던전 & 레이드 필터"
+L["Duration Enable"] = true
+L["Duration Font Size"] = "지속시간 글씨 크기"
+L["Duration Reverse"] = "총 지속시간이 짧은 순"
+L["Duration Text"] = "지속시간 글자"
+L["Duration"] = "총 지속시간이 긴 순"
+L["Editbox History Size"] = true
+L["ELVUI_CREDITS"] = "저는 이 애드온의 유지와 개발 코딩에 도움을 주거나 기부를 한 분들께 특별히 감사하고 싶습니다. 포럼에서 저에게 개인적으로 메일을 준 분들에힌해 이름만 표기했으며만약 당신의 이름이 누락되어 있고 명단에 당신의 이름을 표기하고 하는 분들은 Elv에게 개인적인 메일을 보내주시기 바랍니다. "
+L["ENEMY_NPC"] = "Enemy NPC"
+L["ENEMY_PLAYER"] = "Enemy Player"
+L["Elite Icon"] = "정예 아이콘"
+L["Emotion Icons"] = "이모티콘 전환"
+L["Enable Custom Color"] = true
+L["Enable the use of separate size options for the right chat panel."] = "좌우 패널의 크기를 따로 설정하도록 합니다."
+L["Enable/Disable the Bag-Bar."] = "가방바를 사용할지 여부를 결정합니다."
+L["Enable/Disable the all-in-one bag."] = "통합가방 기능을 사용할지 여부를 결정합니다."
+L["Enable/Disable the loot frame."] = "주사위 굴림 및 전리품 획득 확인창의 사용 여부를 결정합니다.|n|n이 창은 |cff2eb7e4/loot|r 명령어로 볼 수 있습니다."
+L["Enable/Disable the loot roll frame."] = "ElvUI 디자인의 입찰 / 차비 / 마력추출을 선택하는 주사위 굴림창 사용 여부를 결정합니다."
+L["Enable/Disable the minimap. |cffFF0000Warning: This will prevent you from seeing the consolidated buffs bar, and prevent you from seeing the minimap datatexts.|r"] = true
+L["Enable/Disable the scaling of targetted nameplates."] = true
+L["Enables the ElvUI Raid Control panel."] = true
+L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."] = "파티가 가득 차 있지 않아도 다음 파티의 유저를 끌어와 빈칸 없이 나열합니다. 파티구별하기가 힘들다는 단점이 있습니다."
+L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."] = "유닛프레임의 배치를 역순으로 정렬합니다."
+L["Enabling this will check your health amount."] = "활성화하면 내 체력량을 점검합니다."
+L["Enabling this will check your power amount."] = "활성화하면 내 자원량을 점검합니다."
+L["Enchanting"] = true
+L["Enemy Aura Type"] = "적군일 때 표시 계열"
+L["Enemy Combat Toggle"] = "적군 전투 전환"
+L["Enemy NPC Frames"] = true
+L["Enemy Player Frames"] = true
+L["Enemy"] = "적군"
+L["Engineering"] = true
+L["Enhanced PVP Messages"] = "향상된 PVP 메시지"
+L["Equipped Item Color"] = true
+L["Equipped Item"] = true
+L["Error decoding data. Import string may be corrupted!"] = "데이터 해독에 오류. 문자열 가져오기가 오염된 것 같습니다!"
+L["Error exporting profile!"] = "프로필 내보내기 오류!"
+L["Exclude Name"] = "제외할 이름"
+L["Excluded Names"] = "제외된 이름 목록"
+L["Excluded names will not be class colored."] = "제외할 이름은 직업 색상으로 표시하지 않습니다."
+L["Expiring"] = "초읽기 색상"
+L["Export Profile"] = "프로필 내보내기"
+L["Exported"] = "내보낸 것"
+L["FRIENDLY_NPC"] = "우호적인 NPC"
+L["FRIENDLY_PLAYER"] = "우호적인 플레이어"
+L["Fade Chat Toggles"] = true
+L["Fade Out Delay"] = true
+L["Fade Out"] = true
+L["Fade Tabs No Backdrop"] = true
+L["Fade Threshold"] = "초읽기 시작 시점"
+L["Fade Undocked Tabs"] = "채팅탭 숨기기"
+L["Fade the chat text when there is no activity."] = "시간이 오래 지난 이전의 메시지를 채팅창에서 보이지 않게 합니다. 삭제하는 것은 아니니 마우스 휠링으로 안보이게 한 이전의 메시지를 다시 확인할 수 있습니다."
+L["Fader"] = true
+L["Fades the buttons that toggle chat windows when that window has been toggled off."] = true
+L["Fades the text on chat tabs that are docked in a panel where the backdrop is disabled."] = true
+L["Fades the text on chat tabs that are not docked at the left or right chat panel."] = "좌우 패널에 삽입되지 않은 다른 채팅창들의 채팅탭을 숨깁니다."
+L["Fill"] = "채우기"
+L["Filled"] = "하단에 깔기"
+L["Filter Priority"] = "필터 우선순위"
+L["Filter Search"] = true
+L["Filter Type"] = "필터 종류"
+L["Filter already exists!"] = "필터가 이미 존재합니다!"
+L["Filters Page"] = "필터 설정"
+L["Filters are not allowed to have commas in their name. Stripping commas from filter name."] = "필터는 이름에 콤마를 허용하지 않습니다. 필터 이름에서 콤마를 제거하세요."
+L["Flash"] = "반짝임"
+L["Fluid Position Buffs on Debuffs"] = "약화효과에 강화효과를 유동적으로 두기"
+L["Fluid Position Debuffs on Buffs"] = "강화효과에 약화효과를 유동적으로 두기"
+L["Flyout Direction"] = "확장 방향"
+L["Flyout Spacing"] = true
+L["Focus"] = true
+L["FocusTarget"] = true
+L["Font Outline"] = "글꼴 외곽선"
+L["Font"] = "글꼴"
+L["Fonts"] = "글꼴"
+L["Force Off"] = "적용하지 않음"
+L["Force On"] = "강제 적용"
+L["Force Reaction Color"] = "반응색 강제설정"
+L["Force the frames to show, they will act as if they are the player frame."] = "해당 프레임의 유닛이 지금 있는 것처럼 강제로 표시하게 합니다."
+L["Forces Debuff Highlight to be disabled for these frames"] = "해당 프레임에 약화효과 강조 비활성화를 강제합니다."
+L["Forces Mouseover Glow to be disabled for these frames"] = true
+L["Forces Target Glow to be disabled for these frames"] = true
+L["Forces reaction color instead of class color on units controlled by players."] = "유저에 의해 조종되는 유닛의 색을 직업색이 아닌 반응색으로 강제지정합니다."
+L["Format"] = "형식"
+L["Frame Glow"] = "프레임 발광"
+L["Frame Level"] = true
+L["Frame Orientation"] = true
+L["Frame Strata"] = true
+L["Frequent Updates"] = "자주 업데이트"
+L["Friendly Aura Type"] = "아군일 때 표시 계열"
+L["Friendly Combat Toggle"] = "아군 전투 전환"
+L["Friendly NPC Frames"] = true
+L["Friendly Player Frames"] = true
+L["Friendly"] = "아군"
+L["Full Overlay"] = true
+L["Full"] = "전체"
+L["GM Chat"] = true
+L["GPS Arrow"] = true
+L["Gems"] = true
+L["General Options"] = "일반 설정"
+L["Global (Account Settings)"] = "전역 (계정 설정)"
+L["Global Fade Transparency"] = "전역 흐려짐 투명도"
+L["Global"] = "전역"
+L["Glow"] = "후광"
+L["Gold Format"] = "골드 표시방법"
+L["Good Color"] = "좋음 색상"
+L["Good Scale"] = "좋은 범위"
+L["Good Transition Color"] = "좋음 전환 색상"
+L["Good"] = "좋음"
+L["Gossip Frame"] = "NPC 대화 창"
+L["Group By"] = "그룹짓는 방법"
+L["Group Spacing"] = "그룹 간격"
+L["Grouping & Sorting"] = "그룹/정렬 방법"
+L["Groups Per Row/Column"] = "한 줄 당 그룹 배치수"
+L["Growth Direction"] = "나열 방향"
+L["Growth X-Direction"] = true
+L["Growth Y-Direction"] = true
+L["Growth direction from the first unitframe."] = "이 그룹에 속한 유닛들이 1번을 기준으로 어느 방향을 향해 나열될지 결정합니다."
+L["Guide:"] = true
+L["Guild Ranks"] = "길드 내 등급 표시"
+L["Guild Registrar"] = "길드 등록"
+L["HH:MM Threshold"] = true
+L["HH:MM"] = true
+L["Header Font Size"] = "제목 글씨 크기"
+L["Heal Prediction"] = "예상 치유량"
+L["Healer Icon"] = "치유전담 아이콘 표시"
+L["Health Backdrop Multiplier"] = true
+L["Health Backdrop"] = "생명력 배경"
+L["Health Bar"] = "생명력막대"
+L["Health Border"] = "체력바 테두리만"
+L["Health By Value"] = "생명력에 비례한 색상"
+L["Health Color"] = "생명력 색상"
+L["Health Length"] = true
+L["Health Threshold"] = "생명력 경계"
+L["Health"] = "생명력"
+L["Height Multiplier"] = "배경 세로길이 배율"
+L["Height of the objective tracker. Increase size to be able to see more objectives."] = "퀘스트프레임의 길이를 결정합니다."
+L["Height"] = "세로 길이"
+L["Help Frame"] = "도움말"
+L["Herbalism"] = true
+L["Here you can add items or search terms that you want to be excluded from sorting. To remove an item just click on its name in the list."] = "여기에 가방 정리에서 제외할 아이템 또는 검색어를 추가할 수 있습니다. 제거할 때는 목록에서 아이템 이름을 클릭만 하시면 됩니다."
+L["Hide At Max Level"] = "만렙시 숨김"
+L["Hide Both"] = "둘 다 숨기기"
+L["Hide Error Text"] = "전투중 에러 숨기기"
+L["Hide Frame"] = "프레임 숨김"
+L["Hide In Combat"] = "전투시 숨김"
+L["Hide In Vehicle"] = "탈것사용중 숨김"
+L["Hide Spell Name"] = "주문 이름 숨김"
+L["Hide Time"] = "시간 숨김"
+L["Hide specific sections in the datatext tooltip."] = true
+L["Hide tooltip while in combat."] = "전투 중에는 툴팁을 표시하지 않게 합니다."
+L["Hides the red error text at the top of the screen while in combat."] = "화면 중앙 상단에 뜨는 여러 에러메시지(ex : 사정거리 부족)를 전투 중에는 띄우지 않게 합니다."
+L["History Size"] = true
+L["History"] = true
+L["Horizontal Spacing"] = "수평 간격"
+L["Horizontal"] = "가로"
+L["Hours"] = "시간 단위 색상"
+L["Hover Highlight"] = true
+L["Hover"] = true
+L["How long the cutaway health will take to fade out."] = true
+L["How long the cutaway power will take to fade out."] = true
+L["How many seconds the castbar should stay visible after the cast failed or was interrupted."] = "시전이 실패하거나 방해받은 후 몇 초동안 시전바를 보이게 둘지 결정합니다."
+L["How much time before the cutaway health starts to fade."] = true
+L["How much time before the cutaway power starts to fade."] = true
+L["Hyperlink Hover"] = "링크 툴팁 표시"
+L["Icon Frame"] = true
+L["Icon Inside Castbar"] = "시전바 내부 아이콘"
+L["Icon Only"] = true
+L["Icon Position"] = "아이콘 위치"
+L["Icon Size"] = "아이콘 크기"
+L["Icon"] = "아이콘 표시"
+L["Icon: BOTTOM"] = "아이콘 - 하단중앙"
+L["Icon: BOTTOMLEFT"] = "아이콘 - 좌측하단"
+L["Icon: BOTTOMRIGHT"] = "아이콘 - 우측하단"
+L["Icon: LEFT"] = "아이콘 - 좌측"
+L["Icon: RIGHT"] = "아이콘 - 우측"
+L["Icon: TOP"] = "아이콘 - 상단중앙"
+L["Icon: TOPLEFT"] = "아이콘 - 좌측상단"
+L["Icon: TOPRIGHT"] = "아이콘 - 우측상단"
+L["Icons and Text (Short)"] = "아이콘 + 문자(짧게)"
+L["Icons and Text"] = "아이콘 + 문자"
+L["If enabled then it checks if auras are missing instead of being present on the unit."] = true
+L["If enabled then it will require all auras to activate the filter. Otherwise it will only require any one of the auras to activate it."] = true
+L["If enabled then it will require all cooldowns to activate the filter. Otherwise it will only require any one of the cooldowns to activate it."] = true
+L["If enabled then the filter will activate if the unit is casting anything."] = true
+L["If enabled then the filter will activate if the unit is channeling anything."] = true
+L["If enabled then the filter will activate if the unit is not casting anything."] = true
+L["If enabled then the filter will activate if the unit is not channeling anything."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or higher than this value."] = "활성화하면 유닛의 레벨이 이 값 이상일 경우에만 필터가 작동합니다."
+L["If enabled then the filter will only activate if the level of the unit is equal to or lower than this value."] = "활성화하면 유닛의 레벨이 이 갑 이하일 경우에만 필터가 작동합니다."
+L["If enabled then the filter will only activate if the level of the unit matches this value."] = "활성화하면 유닛의 레벨이 이 값과 일치할 경우에만 필터가 작동합니다."
+L["If enabled then the filter will only activate if the level of the unit matches your own."] = "활성화하면 유닛의 레벨이 자기 자신과 일치할 경우에만 필터가 작동합니다."
+L["If enabled then the filter will only activate if the unit is casting interruptible spells."] = "활성화하면 유닛이 차단 가능한 주문을 시전하고 있을 경우에만 필터가 작동합니다."
+L["If enabled then the filter will only activate if the unit is casting not interruptible spells."] = "활성화하면 유닛이 차단 불가능한 주문을 시전하고 있을 경우에만 필터가 작동합니다."
+L["If enabled then the filter will only activate if the unit is not casting or channeling one of the selected spells."] = true
+L["If enabled then the filter will only activate when you are in combat."] = "활성화하면 자신이 전투 중일때만 필터가 작동합니다."
+L["If enabled then the filter will only activate when you are not targeting the unit."] = "활성화하면 자신이 유닛을 대상으로 잡고 있지 않을 때만 필터가 작동합니다."
+L["If enabled then the filter will only activate when you are out of combat."] = "활성화하면 자신이 비전투 중일때만 필터가 작동합니다."
+L["If enabled then the filter will only activate when you are targeting the unit."] = "활성화하면 자신이 유닛을 대상으로 잡고 있을 때만 필터가 작동합니다."
+L["If enabled then the filter will only activate when you have a target."] = true
+L["If not set to 0 then override the size of the aura icon to this."] = "아이콘의 가로세로 길이를 결정합니다.|n|n이 값이 0이면 아이콘이 유닛프레임의 가로길이에 한 줄에 표시할 갯수만큼 들어갈 정도의 크기가 됩니다."
+L["If the aura is listed with a number then you need to use that to remove it from the list."] = true
+L["If this list is empty, and if 'Interruptible' is checked, then the filter will activate on any type of cast that can be interrupted."] = true
+L["If this threshold is used then the health of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the health of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the power of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the power of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If you have a lot of 3D Portraits active then it will likely have a big impact on your FPS. Disable some portraits if you experience FPS issues."] = "3D 초상화를 다수 활성화하면 FPS가 떨어질 수 있습니다. 만약 FPS 문제를 겪으신다면 초상화를 비활성화 하십시오."
+L["If you have any plugins supporting this feature installed you can find them in the selection dropdown to the right."] = true
+L["If you unlock actionbars then trying to move a spell might instantly cast it if you cast spells on key press instead of key release."] = true
+L["Ignore UI Scale Popup"] = true
+L["Ignore mouse events."] = "아이콘이 마우스에 전혀 반응하지 않도록 합니다. 클릭 입력도 아이콘을 통과하게 됩니다."
+L["Ignored Items and Search Syntax (Global)"] = "제외된 아이템 또는 검색구문 (전역)"
+L["Ignored Items and Search Syntax (Profile)"] = "제외된 아이템 또는 검색구문 (프로필)"
+L["Import Profile"] = "프로필 가져오기"
+L["Importing"] = "가져올 것"
+L["Inactivity Timer"] = true
+L["Index"] = "종류"
+L["Indicate whether buffs you cast yourself should be separated before or after."] = "스스로 시전한 효과를 우선 나열할 것인지 여부를 지정합니다."
+L["InfoPanel Border"] = "정보패널 경계"
+L["Information Panel"] = "정보 패널"
+L["Inherit Global Fade"] = "전역 흐려짐 계승"
+L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."] = true
+L["Inset"] = "내부에 분리"
+L["Inside Information Panel"] = "내부 정보 패널"
+L["Install"] = "설치"
+L["Instance Difficulty"] = "인스 난이도"
+L["Instance Type"] = "인스턴스 종류"
+L["Interruptable"] = "차단이 가능한 기술"
+L["Interruptible"] = "차단이 가능한 기술"
+L["Invert Colors"] = true
+L["Invert Grouping Order"] = "역순정렬"
+L["Invert foreground and background colors."] = true
+L["Is Casting Anything"] = true
+L["Is Channeling Anything"] = true
+L["Is Targeted"] = true
+L["Item Count Font"] = "아이템 갯수 글씨"
+L["Item Count"] = "아이템 갯수 표시"
+L["Item Level Threshold"] = "템렙표시 커트라인"
+L["Item Level"] = "아이템 레벨"
+L["JustifyH"] = "글자 가로 정렬방법"
+L["Key Down"] = "단축키를 누를 때 실행"
+L["Keybind Mode"] = "단축키 설정 모드"
+L["Keybind Text Position"] = true
+L["Keybind Text X-Offset"] = true
+L["Keybind Text Y-Offset"] = true
+L["Keybind Text"] = "단축키 표시"
+L["Keyword Alert"] = "키워드 발견 시 소리로 알림"
+L["Keywords"] = "강조할 키워드"
+L["LBF Support"] = true
+L["LEVEL_BOSS"] = "Set level to -1 for boss units or set to 0 to disable."
+L["LFD Frame"] = true
+L["LFG Queue"] = "파티찾기 표시기"
+L["LFR Frame"] = true
+L["Latency"] = "지연 시간 표시"
+L["Leatherworking"] = true
+L["Left Only"] = "좌측 배경만 표시"
+L["Left to Right"] = "왼쪽에서 오른쪽으로"
+L["Left"] = "왼쪽"
+L["Limit the number of rows or columns."] = "표시줄 수를 제한해 최종적으로 보여줄 오라의 총 개수를 제한합니다."
+L["List of words to color in chat if found in a message. If you wish to add multiple words you must seperate the word with a comma. To search for your current name you can use %MYNAME%.\n\nExample:\n%MYNAME%, ElvUI, RBGs, Tank"] = "이 곳에 키워드를 적으면 모든 대화내용에서 해당 키워드를 발견 시 색깔을 입혀 강조합니다. 쉼표(,) 로 구분해서 작성하세요.|n|n내 이름을 강조하고 싶으면 |cff2eb7e4%MYNAME%|r 을 사용하면 됩니다."
+L["Location Text"] = "지역이름 표시 방법"
+L["Lock Positions"] = "패널에 채팅창 고정"
+L["Log Taints"] = "Taint 에러 표시"
+L["Log the main chat frames history. So when you reloadui or log in and out you see the history from your last session."] = "애드온 리로드나 로그아웃 이전의 채팅내역을 보존하여 접속했을 때 보여줍니다."
+L["Login Message"] = "로그인 메세지 표시"
+L["Loot Frames"] = "루팅 창"
+L["Loot Roll"] = "주사위 굴림창"
+L["Losing Threat"] = true
+L["Low Health Threshold"] = "낮은 생명력 임계점"
+L["Low Threat"] = true
+L["Low Threshold"] = "초읽기 시작 시점"
+L["Lower numbers mean a higher priority. Filters are processed in order from 1 to 100."] = "숫자가 작을수록 높은 우선순위를 뜻합니다. 필터는 1부터 100까지 차례로 처리됩니다."
+L["MM:SS Threshold"] = true
+L["MM:SS"] = true
+L["Macro Text"] = "매크로 이름 표시"
+L["Magic Effect"] = true
+L["Main Tanks / Main Assist"] = "방어/지원 담당자"
+L["Main backdrop color of the UI."] = "ElvUI에서 생성하는 모든 불투명한 프레임의 배경 색상을 결정합니다."
+L["Main border color of the UI."] = "UI의 주테두리 색입니다."
+L["Main statusbar texture."] = "시전바, 클래스타이머 등의 텍스쳐를 결정합니다."
+L["Make textures transparent."] = "색상을 반투명하게 합니다."
+L["Make the unitframe glow yellow when it is below this percent of health, it will glow red when the health value is half of this value."] = "생명력이 해당 수치(%) 이하의 경우 노란색, 해당 수치(%) 절반 이하일 경우 빨간색으로 빛나도록 합니다."
+L["Make the world map smaller."] = "월드맵을 작게 표시합니다."
+L["Map Opacity When Moving"] = "이동시 지도 불투명도"
+L["Maps"] = "지도"
+L["Match Frame Width"] = "프레임 너비와 맞춤"
+L["Match Player Level"] = true
+L["Max Alpha"] = true
+L["Max Bars"] = "바 최대갯수"
+L["Max Lines"] = true
+L["Max Overflow"] = true
+L["Max Wraps"] = "표시줄 최대 수"
+L["Max amount of overflow allowed to extend past the end of the health bar."] = true
+L["Maximum Duration"] = "지속시간 제한"
+L["Maximum Level"] = true
+L["Maximum Time Left"] = true
+L["Media"] = "미디어"
+L["Method to sort by."] = "정렬 방법"
+L["Middle Click - Set Focus"] = "휠클릭으로 주시 설정"
+L["Middle clicking the unit frame will cause your focus to match the unit."] = "마우스 휠로 이 프레임을 클릭하면 유닛을 주시 대상으로 잡습니다."
+L["Middle"] = "중간"
+L["Min Alpha"] = true
+L["Minimap Mouseover"] = "마우스오버 때만 표시"
+L["Minimap Panels"] = "미니맵 정보문자 사용"
+L["Minimum Duration"] = "최소 지속시간"
+L["Minimum Level"] = true
+L["Minimum Time Left"] = true
+L["Mining"] = true
+L["Minutes"] = "분 단위 색상"
+L["Mirror Timers"] = "미러 타이머"
+L["Misc Frames"] = "기타 프레임"
+L["Missing"] = true
+L["Modulating Blend"] = true
+L["Module Control"] = true
+L["Module Copy"] = true
+L["Module Reset"] = true
+L["Money Format"] = "소지금 표시방법"
+L["Mouse Over"] = "마우스오버 시 표시"
+L["Mouseover Glow"] = "마우스오버 발광"
+L["Mouseover Highlight"] = "마우스오버 강조"
+L["Mouseover"] = "마우스오버 시 표시"
+L["Multi-Monitor Support"] = "다중모니터 지원"
+L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."] = "이 값 만큼 배경의 길이가 배로 늘어납니다. 배경 하나에 여러 행동단축바를 올리고 싶은 경우에 유용합니다."
+L["NAMEPLATE_FRAMELEVEL_DESC"] = true
+L["NPC IDs"] = true
+L["Name Color"] = "이름 색상"
+L["Name Colored Glow"] = true
+L["Name Font"] = "캐릭터 이름 글꼴"
+L["Name Only"] = "이름만"
+L["Name"] = "이름"
+L["NamePlate Style Filters"] = "이름표 스타일 필터"
+L["NamePlates"] = "이름표"
+L["Nameplate"] = true
+L["Neutral"] = "중립"
+L["Never Hide"] = "항시 표시"
+L["No Alert In Combat"] = "전투 중 알리지 않기"
+L["No Duration"] = true
+L["No Sorting"] = "구분 없음"
+L["Non-Interruptable"] = "차단불가능 기술"
+L["Non-Target Alpha"] = true
+L["Not Casting Anything"] = true
+L["Not Channeling Anything"] = true
+L["Not Spell"] = true
+L["Not Targeted"] = true
+L["Not Usable"] = "사용 불가능"
+L["Not valid spell id"] = "유효한 주문 ID가 아닙니다."
+L["Num Rows"] = "최대 표시 줄 개수"
+L["Number of Groups"] = "그룹 수"
+L["Number of messages you scroll for each step."] = "한번에 스크롤 되는 메시지 줄 수"
+L["Number of repeat characters while in combat before the chat editbox is automatically closed. Set to 0 to disable."] = true
+L["Number of time in seconds to scroll down to the bottom of the chat window if you are not scrolled down completely."] = "대화창의 스크롤이 맨 아래가 아니라면 이 값 만큼 시간이 지났을 때 맨 아래로 자동 스크롤링 됩니다."
+L["Objective Frame Height"] = "퀘스트프레임 세로길이"
+L["Off Cooldown"] = true
+L["Offset of the powerbar to the healthbar, set to 0 to disable."] = "디자인 설정을 무시하고 자원바를 생명력바 뒤로 겹친 후, 드러남 정도를 결정합니다.|n|n0으로 설정하면 겹치지 않고 디자인 설정대로 배치합니다."
+L["Offset position for text."] = "위치 기준점에서부터 얼마나 떨어진 곳에 문자를 배치할지 결정합니다."
+L["Offset"] = "생명력바와 겹쳐 표시"
+L["On Cooldown"] = true
+L["Only Match SpellID"] = "일치하는 주문ID만"
+L["Only show when the unit is not in range."] = true
+L["Only show when you are mousing over a frame."] = true
+L["Other Filter"] = "기타 필터"
+L["Other's First"] = "타인 주문 우선"
+L["Others"] = "다른 유저"
+L["Out of Power"] = "자원 부족"
+L["Out of Range"] = "사정거리 밖"
+L["Over Health Threshold"] = true
+L["Over Power Threshold"] = true
+L["Overlay Alpha"] = true
+L["Overlay"] = "덮어씌우기"
+L["Overnuking"] = true
+L["Override any custom visibility setting in certain situations, EX: Only show groups 1 and 2 inside a 10 man instance."] = "현재 입던해있는 던전의 상태에 맞춰 표시할 파티수를 자동으로 제한합니다.|n|n예로 10인 인스안에 있으면 1,2파티만 표시됩니다."
+L["Override the default class color setting."] = "이 유닛프레임의 체력바에만 직업색을 적용하도록 따로 설정하는 것이 가능합니다."
+L["Owners Name"] = "주인 이름"
+L["PVP Trinket"] = "PvP 장신구"
+L["Panel Backdrop"] = "패널 배경 표시"
+L["Panel Height"] = "패널 세로길이"
+L["Panel Texture (Left)"] = "패널 텍스쳐 (왼쪽)"
+L["Panel Texture (Right)"] = "패널 텍스쳐 (오른쪽)"
+L["Panel Transparency"] = "탭을 반투명하게"
+L["Panel Width (Bags)"] = "통합가방 프레임 가로길이"
+L["Panel Width (Bank)"] = "통합은행 프레임 가로길이"
+L["Panel Width"] = "패널 가로길이"
+L["Panels"] = "패널"
+L["Parent"] = true
+L["Party / Raid"] = "파티&레이드 채널로"
+L["Party Only"] = "파티채널만"
+L["Party Pets"] = "파티원 소환수"
+L["Party Targets"] = "파티원의 대상"
+L["Per Row"] = "한 줄에 표시할 아이콘 수"
+L["Percent"] = "%"
+L["Personal"] = "플레이어"
+L["Pet Name"] = "펫 이름"
+L["Pet"] = true
+L["PetTarget"] = true
+L["Petition Frame"] = "GM 요청 창"
+L["Pick Up Action Key"] = true
+L["Player Frame Aura Bars"] = true
+L["Player Health"] = "플레이어 생명력"
+L["Player Out of Combat"] = "플레이어 전투 종료"
+L["Player Target"] = true
+L["Player Titles"] = "칭호 표시"
+L["Player in Combat"] = "플레이어 전투중"
+L["Player"] = "플레이어"
+L["Plugin"] = "플러그인"
+L["Poison Effect"] = true
+L["Portrait"] = "초상화"
+L["Position Buffs on Debuffs"] = "약화효과에 강화효과를 위치"
+L["Position Debuffs on Buffs"] = "강화효과에 약화효과를 위치"
+L["Position of the Chat EditBox, if datatexts are disabled this will be forced to be above chat."] = "대화 입력창의 위치를 결정합니다. 만약 정보문자 항목에서 패널에 정보문자를 표시하지 않게 해놨다면 위치가 채팅창 위로 고정됩니다."
+L["Position"] = "위치"
+L["Power Threshold"] = true
+L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."] = "유닛이 NPC라면 자원 글자를 숨기고 그 위치에 이름을 표시합니다."
+L["Power"] = "자원"
+L["Powers"] = "자원 (마나, 분노, 기력...)"
+L["Prevent the same messages from displaying in chat more than once within this set amount of seconds, set to zero to disable."] = "같은 내용의 메시지는 이 값만큼 정해진 시간 내에선 한번만 보여줍니다.|n|n0으로 설정하면 이 기능을 끕니다."
+L["Primary Texture"] = "주 텍스쳐"
+L["Priority"] = "우선도"
+L["Private (Character Settings)"] = "개인 (캐릭터 설정)"
+L["Profession Bags"] = true
+L["Profile Name"] = "프로필 이름"
+L["Profile Specific"] = true
+L["Profile imported successfully!"] = "프로필을 성공적으로 가져왔습니다!"
+L["Profile"] = "프로필"
+L["Progress Bar"] = true
+L["Puts coordinates on the world map."] = "세계 지도에 좌표를 넣습니다."
+L["PvP Frames"] = "PvP 창"
+L["PvP Icon"] = true
+L["PvP Queue"] = true
+L["PvP Text"] = "PVP 문자"
+L["Quest Frames"] = "퀘스트 창"
+L["Quest Starter"] = true
+L["Quiver"] = true
+L["RAID_CONTROL"] = "공격대 편성"
+L["RL / ML Icons"] = true
+L["Raid Difficulty"] = "공격대 난이도"
+L["Raid Frame"] = "공격대 프레임"
+L["Raid Icon"] = "레이드 아이콘"
+L["Raid Only"] = "레이드채널만"
+L["Raid Pet"] = "레이드 소환수 프레임"
+L["Raid-40"] = "레이드 프레임(40인)"
+L["Raid-Wide Sorting"] = "빈칸없이 나열"
+L["RaidDebuff Indicator"] = "공격대 주요 약화효과 표시기"
+L["Range"] = true
+L["Rapidly update the health, uses more memory and cpu. Only recommended for healing."] = "생명력 수치 업데이트를 평소보다 더 빠르게 하지만 메모리와 CPU점유율이 더 증가하는 기능입니다. 힐러일 경우에만 추천합니다."
+L["Reaction Castbars"] = "관계 시전바"
+L["Reaction Colors"] = "관계 색상"
+L["Reaction Type"] = "관계 형태"
+L["Reactions"] = "관계"
+L["Ready Check Icon"] = "전투준비 아이콘"
+L["Realm Time"] = true
+L["Remaining / Max"] = true
+L["Remaining Time"] = true
+L["Remaining"] = "남은 시간"
+L["Reminder"] = true
+L["Remove Backdrop"] = "표시하지 않음"
+L["Remove Name"] = true
+L["Remove Spell ID or Name"] = true
+L["Remove Spell"] = "주문 삭제"
+L["Remove SpellID"] = "주문 ID 삭제"
+L["Remove a Name from the list."] = true
+L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."] = "필터에서 주문을 제거합니다. 필터 내 주문이름의 일부로 주문ID가 보이면 주문ID를 사용하십시오."
+L["Remove a spell from the filter."] = "필터에서 주문을 제거합니다."
+L["Replace Blizzard Fonts"] = "블리자드 폰트 교체"
+L["Replaces the default Blizzard fonts on various panels and frames with the fonts chosen in the Media section of the ElvUI Options. NOTE: Any font that inherits from the fonts ElvUI usually replaces will be affected as well if you disable this. Enabled by default."] = "기본적으로 지정되는 대부분의 블리자드프레임 내 글자들의 폰트를 여기서 설정하는 폰트로 바꿉니다."
+L["Reposition Window"] = true
+L["Require All"] = true
+L["Require Target"] = true
+L["Require holding the Alt key down to move cursor or cycle through messages in the editbox."] = "입력창에서 이전대화를 순환하거나 커서를 움직이기 위해서 Alt키를 누르고 있어야 합니다."
+L["Reset Anchors"] = "위치 초기화"
+L["Reset Aura Filters"] = "오라 필터 초기화"
+L["Reset Editbox History"] = true
+L["Reset Filter"] = "필터 초기화"
+L["Reset History"] = true
+L["Reset Priority"] = "우선순위 초기화"
+L["Reset Zoom"] = "배율 초기화"
+L["Reset all frames to their original positions."] = "ElvUI 에서 움직일 수 있는 모든 프레임의 위치를 기본 위치로 초기화합니다."
+L["Reset filter priority to the default state."] = "필터 우선순위를 기본값으로 되돌립니다."
+L["Reset the size and position of this frame."] = true
+L["Rest Icon"] = "휴식 아이콘"
+L["Restore Bar"] = "기본값으로 초기화"
+L["Restore Defaults"] = "기본값 복원"
+L["Restore the actionbars default settings"] = "이 행동단축바에 대한 모든 수치를 기본값으로 되돌립니다."
+L["Resurrect Icon"] = "부활 아이콘"
+L["Return filter to its default state."] = "필터를 초기상태로 되돌리기"
+L["Reverse Bag Slots"] = true
+L["Reverse Cooldown"] = true
+L["Reverse Style"] = true
+L["Reverse Toggle will enable Cooldown Text on this module when the global setting is disabled and disable them when the global setting is enabled."] = true
+L["Reverse Toggle"] = true
+L["Right Only"] = "우측 배경만 표시"
+L["Right Panel Height"] = "우측 패널 세로길이"
+L["Right Panel Width"] = "우측 패널 가로길이"
+L["Right to Left"] = "오른쪽에서 왼쪽으로"
+L["Right"] = "오른쪽"
+L["RightClick Self-Cast"] = "우클릭으로 자기에게 시전"
+L["Role Icon"] = "역할 아이콘"
+L["Run the installation process."] = "ElvUI의 설치 프로세스를 실행합니다."
+L["Sanctuary"] = true
+L["Scale of the nameplate that is targetted."] = true
+L["Scale"] = "크기"
+L["Scroll Interval"] = "자동 스크롤링 시간"
+L["Scroll Messages"] = "스크롤 줄 수"
+L["Search Syntax"] = "아이템 검색법"
+L["Search for a spell name inside of a filter."] = true
+L["Secondary Texture"] = "보조 텍스쳐"
+L["Seconds remaining on the aura duration before the bar starts moving. Set to 0 to disable."] = true
+L["Seconds"] = "초 단위 색상"
+L["Selected Text Color"] = true
+L["Selector Color"] = true
+L["Selector Style"] = true
+L["Securely Tanking"] = true
+L["Select Filter"] = "필터 선택"
+L["Select Spell"] = "주문 선택"
+L["Select a profile to copy from/to."] = true
+L["Select a unit to copy settings from."] = "이 옵션에서 선택하는 유닛프레임의 설정을 복사하여 프레임에 적용합니다."
+L["Select the display method of the portrait."] = "초상화 표시 방법을 결정합니다."
+L["Sell Interval"] = true
+L["Send ADDON_ACTION_BLOCKED errors to the Lua Error frame. These errors are less important in most cases and will not effect your game performance. Also a lot of these errors cannot be fixed. Please only report these errors if you notice a Defect in gameplay."] = "애드온 기능이 막히는 에러도 오류확인창에 등록합니다. 이런 에러들은 중요하지 않거나 게임플레이에 영향을 미치지 않는 것들이 대부분입니다. 게다가 이런 에러들은 대부분 고칠 수 없는 것들입니다.|n|n발견되는 에러가 게임플레이에 지장이 될 경우에만 에러보고를 해주세요."
+L["Sends your current profile to your target."] = "대상에게 지금 활성화되어 있는 프로필 설정을 전송합니다."
+L["Sends your filter settings to your target."] = "대셍에게 지금 사용하고 있는 필터 설정을 전송합니다."
+L["Separate Panel Sizes"] = "좌우패널 크기 따로설정"
+L["Seperate"] = "시전자 구분 정렬"
+L["Set Settings to Default"] = "설정을 기본값으로 지정"
+L["Set the alpha level of portrait when frame is overlayed."] = true
+L["Set the filter type. Blacklist will hide any auras in the list and show all others. Whitelist will show any auras in the filter and hide all others."] = "필터 종류를 지정합니다. 블랙리스트는 목록에 있는 오라는 싸그리 숨기고 나머지는 전부 표시합니다. 화이트리스트는 목록에 있는 오라는 모조리 표시하고 나머지는 전부 숨깁니다."
+L["Set the font outline."] = "글꼴의 외곽선을 결정합니다."
+L["Set the font size for everything in UI. Note: This doesn't effect somethings that have their own seperate options (UnitFrame Font, Datatext Font, ect..)"] = "ElvUI에서 쓰이는 모든 글꼴 크기를 결정합니다.|n|n개인적으로 글꼴 크기를 지정할 수 있는 곳은 적용되지 않습니다."
+L["Set the font size for unitframes."] = "유닛프레임 내에서 쓰이는 모든 글자의 크기를 결정합니다."
+L["Set the order that the group will sort."] = "이 유닛프레임에서 그룹을 어떤 기준으로 묶을지를 결정합니다.|n|n|cffceff00해석불완전|r : 기능을 제가 아직 확인해보지 못했습니다."
+L["Set the orientation of the UnitFrame."] = "유닛프레임의 방향을 지정합니다."
+L["Set the priority order of the spell, please note that prioritys are only used for the raid debuff module, not the standard buff/debuff module. If you want to disable set to zero."] = "효과의 우선도를 결정합니다. 값이 높을 수록 우선적으로 표시하는데 이 기능은 오로지 Raid Debuff 필터에서만 동작합니다.|n|n0으로 설정하면 이 기능을 사용하지 않습니다."
+L["Set the size of the individual auras."] = "오라 아이콘의 크기를 결정합니다."
+L["Set the size of your bag buttons."] = "가방바에서 슬롯의 크기를 결정합니다."
+L["Set the type of auras to show when a unit is a foe."] = "해당 유닛이 적대적일 때 표시할 오라 형태를 결정합니다."
+L["Set the type of auras to show when a unit is friendly."] = "해당 유닛이 우호적일 때 표시할 오라 형태를 결정합니다."
+L["Set to either stack nameplates vertically or allow them to overlap."] = true
+L["Sets the font instance's horizontal text alignment style."] = "문자의 가로 정렬 방법을 결정합니다."
+L["Share Current Profile"] = "프로필설정 전송"
+L["Share Filters"] = "필터설정 전송"
+L["Short (Whole Numbers)"] = "골드만"
+L["Short Channels"] = "채널명 요약"
+L["Shortcut to 'Filters' section of the config."] = true
+L["Shortcut to global filters."] = "전역 필터로 바로가기"
+L["Shortcuts"] = "바로가기"
+L["Shorten the channel names in chat."] = "채팅창의 채널명을 간추려 표시합니다."
+L["Should tooltip be anchored to mouse cursor"] = "마우스에 툴팁을 표시합니다.|n|n체크 해제 시 프레임 이동 모드에서 툴팁 위치에 표시됩니다."
+L["Show Aura From Other Players"] = "다른 유저가 건 주문효과도 표시"
+L["Show Auras"] = "오라아이콘 표시"
+L["Show Bind on Equip/Use Text"] = true
+L["Show Both"] = "둘 다 배경 표시"
+L["Show Coins"] = "동전 이미지로 보기"
+L["Show Dispellable Debuffs"] = "해제가능한 약화효과 표시"
+L["Show Empty Buttons"] = "빈 칸 표시"
+L["Show For DPS"] = true
+L["Show For Healers"] = true
+L["Show For Tanks"] = true
+L["Show Icon"] = true
+L["Show Junk Icon"] = "잡템 아이콘 표시"
+L["Show Quality Color"] = true
+L["Show Quest Icon"] = true
+L["Show When Not Active"] = "효과가 없을 때 표시"
+L["Show an incoming heal prediction bar on the unitframe. Also display a slightly different colored bar for incoming overheals."] = "생명력바에 예상 치유량을 표시합니다."
+L["Show the castbar icon desaturated if a spell is not interruptible."] = true
+L["Show/Hide Test Frame"] = true
+L["Side Arrows"] = "양옆 화살표"
+L["Size Override"] = "아이콘 크기"
+L["Size and Positions"] = "크기와 위치 관련"
+L["Size of the indicator icon."] = "표시기 아이콘 크기"
+L["Size"] = "크기"
+L["Skin Backdrop (No Borders)"] = "반투명 스킨적용(테두리없음)"
+L["Skin Backdrop"] = "반투명 스킨적용"
+L["Skin the blizzard chat bubbles."] = "말풍선에 디자인을 변경해 스킨을 입힐지, 혹은 투명하게 하여 안보이게 할지 결정합니다."
+L["Skins"] = "스킨"
+L["Small Panels"] = "작은 패널"
+L["Smaller World Map"] = "월드맵 축소"
+L["Smart Aura Position"] = "스마트 오라 위치"
+L["Smart Raid Filter"] = "스마트 레이드 필터"
+L["Smart"] = "스마트"
+L["Smooth Bars"] = "부드러운 증감"
+L["Smooth"] = true
+L["Smoothing Amount"] = true
+L["Socket Frame"] = "보석홈 UI"
+L["Sort By"] = true
+L["Sort Direction"] = "정렬 방법"
+L["Sort Inverted"] = "아래로 정렬"
+L["Sort Method"] = "정렬 기준"
+L["Soul Bag"] = true
+L["Spaced"] = "외부에 작게 분리"
+L["Spacing"] = "간격"
+L["Spam Interval"] = "중복메시지 제한 기간"
+L["Spark"] = "반짝임"
+L["Spell/Item IDs"] = "아이템/주문 ID 표시"
+L["Split"] = true
+L["Stable"] = "소환수 보관창"
+L["Stack Counter"] = "중첩 표시"
+L["Stack Text Position"] = true
+L["Stack Text X-Offset"] = true
+L["Stack Text Y-Offset"] = true
+L["Stack Threshold"] = "중첩 기준점"
+L["Start Near Center"] = "가운데 정렬"
+L["StatusBar Texture"] = "진행막대 텍스쳐"
+L["Statusbar Fill Orientation"] = "막대 진행 방향"
+L["Statusbar"] = true
+L["Sticky Chat"] = "채널 고정"
+L["Strata and Level"] = true
+L["Style Filter"] = "스타일 필터"
+L["Style"] = "디자인"
+L["Tab Font Outline"] = "채팅탭 글꼴 외곽선"
+L["Tab Font Size"] = "채팅탭 글꼴 크기"
+L["Tab Font"] = "채팅탭 글꼴"
+L["Tab Panel Transparency"] = "탭을 반투명하게"
+L["Tab Panel"] = "패널 탭 표시"
+L["Tab Selector"] = true
+L["Tabard Frame"] = "휘장 프레임"
+L["Table"] = "테이블"
+L["Tank Target"] = "방어전담 프레임"
+L["Tank"] = "방어 전담"
+L["Tapped"] = "선점되었을 때의 색상"
+L["Target Indicator Color"] = "대상 표시기 색상"
+L["Target Info"] = "대상선택 정보"
+L["Target On Mouse-Down"] = "마우스를 누를 때 작동"
+L["Target Scale"] = true
+L["Target units on mouse down rather than mouse up. \n\n|cffFF0000Warning: If you are using the addon 'Clique' you may have to adjust your clique settings when changing this."] = "마우스를 뗄 때 대상으로 잡는 게 아니라 마우스를 누를 때에 대상으로 잡습니다.|n|n|cff2eb7e4Clique|r 애드온을 쓰고 있다면 이 설정을 바꾼 후에 Clique 설정도 다시 해야 합니다."
+L["Target/Low Health Indicator"] = "대상 표시기"
+L["TargetTarget"] = true
+L["TargetTargetTarget"] = true
+L["Targeted Glow"] = "대상선택 발광"
+L["Targeting"] = true
+L["Testing:"] = "|cff2eb7e4< 테스터 >|r"
+L["Text Fade"] = true
+L["Text Color"] = "글자 색"
+L["Text Font Size"] = "내용 글씨 크기"
+L["Text Format"] = "글자 형식"
+L["Text Position"] = "위치 기준"
+L["Text Threshold"] = "글자 표시 임계점"
+L["Text Toggle On NPC"] = "NPC면 자원에 이름표시"
+L["Text xOffset"] = "글자 x 좌표"
+L["Text yOffset"] = "글자 y 좌표"
+L["Text"] = "글자 표시"
+L["Texture"] = "텍스쳐"
+L["Textured Icon"] = "스킬이미지 아이콘"
+L["Textures"] = "텍스처"
+L["The Portrait will overlay the Healthbar. This will be automatically happen if the Frame Orientation is set to Middle."] = true
+L["The Thin Border Theme option will change the overall apperance of your UI. Using Thin Border Theme is a slight performance increase over the traditional layout."] = "얇은 경계 테마 옵션은 인터페이스의 전반적인 외형을 변경합니다. 얇은 경계 테마를 사용하는 것은 기존보다 약간 성능이 향상됩니다."
+L["The amount of buttons to display per row."] = "한 줄에 배치할 버튼의 수를 결정합니다."
+L["The amount of buttons to display."] = "표시할 버튼의 총 개수를 결정합니다."
+L["The button you must hold down in order to drag an ability to another action button."] = "이 키를 누른 상태로 아이콘을 드래그해야 행동단축바에서 기술이 빠져나와 없애거나 옮길 수 있습니다."
+L["The debuff needs to reach this amount of stacks before it is shown. Set to 0 to always show the debuff."] = "여기서 설정한 값만큼 중첩되어야 약화효과가 표시됩니다. 0으로 설정하면 항상 보이게 됩니다."
+L["The direction that the bag frames be (Horizontal or Vertical)."] = "가방바를 가로로 나열할지, 세로로 나열할지 결정합니다."
+L["The direction that the bag frames will grow from the anchor."] = "가방바의 슬롯이 시작점을 기준으로 슬롯번호순으로 나열할지, 역순으로 나열할지 결정합니다."
+L["The direction the auras will grow and then the direction they will grow after they reach the wrap after limit."] = "오라가 어느 방향으로 나열되고, 다음 줄을 어느 방향에 배치할지 결정합니다."
+L["The display format of the currency icons that get displayed below the main bag. (You have to be watching a currency for this to display)"] = "화폐의 표시방법을 결정합니다."
+L["The display format of the money text that is shown at the top of the main bag."] = "통합가방 상단에 표시되는 보유 골드의 표시 방법을 결정합니다."
+L["The display format of the money text that is shown in the gold datatext and its tooltip."] = "정보문자와 툴팁에서 표시될 골드의 형식을 결정합니다."
+L["The first button anchors itself to this point on the bar."] = "첫 번째 요소를 기준으로 나머지가 나열됩니다."
+L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."] = "체크시 그룹의 표시 설정이 설정됩니다. 필터를 추가해서 수정이 가능합니다."
+L["The font that appears on the text above players heads. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "화면상에서 캐릭터 위에 표시되는 이름, 길드, 칭호 등의 글꼴을 변경합니다.|n|n|cffff0000주의|r|n이 설정은 리로드가 아닌 캐릭터에 재접속하야 적용됩니다."
+L["The font that combat text will use. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "화면상에서 전투 상황에 관련된 글자에 적용되는 글꼴입니다.|n|n|cffff0000WARNING|r|n이 설정은 리로드가 아닌 캐릭터에 재접속하야 적용됩니다."
+L["The font that the core of the UI will use."] = "ElvUI에서 쓰이는 모든 글자의 글꼴을 결정합니다.|n|n개인적으로 글꼴을 지정할 수 있는 곳은 적용되지 않습니다."
+L["The font that the unitframes will use."] = "유닛프레임의 글꼴입니다."
+L["The frame is not shown unless you mouse over the frame."] = "커서를 갖다 댔을(마우스오버) 시에만 표시됩니다."
+L["The initial group will start near the center and grow out."] = "위치의 가운데에서부터 유닛프레임을 배치하기 시작합니다."
+L["The minimum item level required for it to be shown."] = "아이템에 표시되는 템렙의 표시기준 최저치를 결정합니다."
+L["The name you have selected is already in use by another element."] = "입력한 제목의 문자영역이 이미 있습니다. 다른 제목을 입력하세요."
+L["The object you want to attach to."] = "이 요소가 어느 프레임을 기준으로 배치될지를 결정합니다."
+L["The size of the action buttons."] = "각각의 행동단축바 버튼의 크기를 결정합니다."
+L["The size of the individual buttons on the bag frame."] = "통합가방 프레임의 슬롯크기를 결정합니다."
+L["The size of the individual buttons on the bank frame."] = "통합은행 프레임의 슬롯크기를 결정합니다."
+L["The spacing between buttons."] = "버튼 사이의 간격을 설정합니다."
+L["The spacing between the backdrop and the buttons."] = "버튼과 배경 사이에 공간을 둡니다."
+L["The texture that will be used mainly for statusbars."] = "기본적으로 상태바 같은 곳에서 입혀지는 텍스쳐입니다."
+L["The unit prefixes you want to use when values are shortened in ElvUI. This is mostly used on UnitFrames."] = "ElvUI에서 수치를 짧게 표시하고 싶을때 단위를 사용해 축약합니다. 주로 유닛프레임에서 사용됩니다."
+L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."] = true
+L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."] = true
+L["Thin Border Theme"] = "얇은 경계 테마"
+L["Thin Borders"] = "얇은 테두리"
+L["This dictates the size of the icon when it is not attached to the castbar."] = "시전바에 부착하지 않을 때의 아이콘 크기를 결정합니다."
+L["This feature will allow you to transfer settings to other characters."] = "전송 기능을 통해 대상에게 자신의 설정을 넘겨줄 수 있습니다."
+L["This is for Customized Icons in your Interface/Icons folder."] = true
+L["This opens the UnitFrames Color settings. These settings affect all unitframes."] = "유닛프레임 색상 설정을 엽니다. 이 설정은 모든 유닛프레임에 영향을 미칩니다."
+L["This option allows the overlay to span the whole health, including the background."] = true
+L["This section will allow you to copy settings to a select module from or to a different profile."] = true
+L["This section will help reset specfic settings back to default."] = true
+L["This selects the Chat Frame to use as the output of ElvUI messages."] = true
+L["This setting controls the size of text in item comparison tooltips."] = "아이템 비교 툴팁의 글씨 크기를 조정합니다."
+L["This setting will be updated upon changing stances."] = "이 설정은 태세를 바꿔야 업데이트 됩니다."
+L["This texture will get used on objects like chat windows and dropdown menus."] = "채팅창이나 메뉴 같은 프레임에 입혀지는 텍스쳐입니다."
+L["This will override the global cooldown settings."] = true
+L["This will prevent the UI Scale Popup from being shown when changing the game window size."] = true
+L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."] = true
+L["Threat Display Mode"] = "어그로획득 표시방법"
+L["Threat Health"] = true
+L["Threat Power"] = true
+L["Threat"] = "위협"
+L["Threshold (in minutes) before text is shown in the HH:MM format. Set to -1 to never change to this format."] = true
+L["Threshold (in seconds) before text is shown in the MM:SS format. Set to -1 to never change to this format."] = true
+L["Threshold before text goes into decimal form. Set to -1 to disable decimals."] = "소숫점으로 표시하게 될 기준점을 결정합니다. -1로 지정 시 작동하지 않습니다."
+L["Threshold before text turns red and is in decimal form. Set to -1 for it to never turn red"] = "이 값 이하로 시간이 내려가면 시간이 소숫점 단위 초읽기 형태로 표시됩니다.|n|n-1로 설정하면 이 기능을 사용하지 않습니다."
+L["Threshold before the icon will fade out and back in. Set to -1 to disable."] = true
+L["Ticks"] = "주문 틱 표시"
+L["Time Format"] = true
+L["Time Indicator Colors"] = true
+L["Time Remaining Reverse"] = "남은시간이 짧은 순으로"
+L["Time Remaining"] = "남은시간이 긴 순으로"
+L["Time To Hold"] = "유지하는 시간"
+L["Time xOffset"] = "시간 x 좌표"
+L["Time yOffset"] = "시간 y 좌표"
+L["Time"] = "시간"
+L["Timestamp Color"] = "시간표시 색상"
+L["Toggle Anchors"] = "프레임 이동 모드"
+L["Toggle Off While In Combat"] = "전투 중 비활성화"
+L["Toggle On While In Combat"] = "전투 중 활성화"
+L["Toggle Tutorials"] = "애드온 튜토리얼 확인"
+L["Toggle showing of the left and right chat panels."] = "패널의 배경 표시 여부를 결정합니다."
+L["Toggle the chat tab panel backdrop."] = "패널 상단에 위치한 탭 부분의 표시 여부를 결정합니다."
+L["Toggles the display of the actionbars backdrop."] = "행동단축바의 배경을 표시할지 여부를 결정합니다."
+L["Tooltip Font Settings"] = "툴팁 글씨 설정"
+L["Top Arrow"] = "상단 화살표"
+L["Top Left"] = "상단 좌측"
+L["Top Panel"] = "상단 패널 표시"
+L["Top Right"] = "상단 우측"
+L["Top to Bottom"] = "위에서 아래로"
+L["Top"] = "상단 중앙"
+L["TopLeftMiniPanel"] = "미니맵 좌상단 (내부)"
+L["TopMiniPanel"] = "미니맵 상단 (내부)"
+L["TopRightMiniPanel"] = "미니맵 우상단 (내부)"
+L["Totem"] = true
+L["Trainer Frame"] = "기술전문가 창"
+L["Transparency level when not in combat, no target exists, full health, not casting, and no focus target exists."] = true
+L["Transparent Backdrops"] = true
+L["Transparent Buttons"] = true
+L["Transparent"] = "반투명화"
+L["Triggers"] = "활성 조건"
+L["Turtle Color"] = "생존기 색상"
+L["Tutorial Frame"] = true
+L["URL Links"] = "URL 주소 강조"
+L["Under Health Threshold"] = true
+L["Under Power Threshold"] = true
+L["Uniform Threshold"] = true
+L["Unique Units"] = true
+L["Unit Prefix Style"] = "단위 축약 방식"
+L["Unit Target"] = true
+L["Unit Type"] = "유닛 종류"
+L["UnitFrames"] = "유닛프레임"
+L["Unlock various elements of the UI to be repositioned."] = "ElvUI에서 위치를 조정할 수 있는 프레임들을 움직이는 이동 모드를 실행합니다."
+L["Up"] = "위로"
+L["Usable"] = "사용 가능"
+L["Use Alt Key"] = "Alt 키 사용"
+L["Use Class Color"] = "직업 색상 사용"
+L["Use Custom Level"] = true
+L["Use Custom Strata"] = true
+L["Use Dead Backdrop"] = "죽음 배경 사용"
+L["Use Default"] = "기존 설정대로"
+L["Use Indicator Color"] = true
+L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."] = "Shift+클릭으로 우호적 또는 적대적 또는 일반 상태로 전환합니다. 일반 상태는 필터가 모든 유닛을 점검하도록 합니다. 우호적 상태는 우호적 유닛에만, 적대적 상태는 적대적 유닛에만 작동합니다."
+L["Use Target Scale"] = true
+L["Use Threat Color"] = "위협 색상 사용"
+L["Use class color for the names of players when they are mentioned."] = "사용자의 이름이 언급될 경우 직업 색상으로 표시합니다."
+L["Use coin icons instead of colored text."] = "골드 이미지를 글자가 아닌 아이콘으로 표시합니다."
+L["Use drag and drop to rearrange filter priority or right click to remove a filter."] = "끌어다 놓기로 재정렬하거나 우클릭으로 필터에서 제거합니다."
+L["Use the Name Color of the unit for the Name Glow."] = true
+L["Use the custom backdrop color instead of a multiple of the main color."] = true
+L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."] = true
+L["Use thin borders on certain unitframe elements."] = "특정 유닛프레임 요소들에 얇은 테두리를 사용합니다."
+L["Use this backdrop color for units that are dead or ghosts."] = "죽거나 유령상태인 유닛에 대해 이 배경색을 사용합니다."
+L["Used as RaidDebuff Indicator"] = true
+L["Value Color"] = "강조 색상"
+L["Value must be a number"] = "값으로 숫자만 입력할 수 있습니다."
+L["Vehicle Seat Indicator Size"] = true
+L["Vehicle"] = true
+L["Vendor Gray Detailed Report"] = "자동판매시 목록 보기"
+L["Vendor Grays"] = "잡동사니 자동판매"
+L["Version"] = "버전"
+L["Vertical Fill Direction"] = "수직 증감 방향"
+L["Vertical Spacing"] = "수직 간격"
+L["Vertical"] = "세로"
+L["Visibility State"] = "표시 자동전환 조건"
+L["Visibility"] = "표시"
+L["Watch Frame"] = true
+L["What point to anchor to the frame you set to attach to."] = "지정된 프레임에서 어디를 기준으로 나열할지 결정합니다."
+L["What to attach the buff anchor frame to."] = "강화효과를 어떤 프레임 구성요소에 부착할지 결정합니다."
+L["What to attach the debuff anchor frame to."] = "약화효과를 어떤 프레임 구성요소에 부착할지 결정합니다."
+L["When enabled active buff icons will light up instead of becoming darker, while inactive buff icons will become darker instead of being lit up."] = true
+L["When enabled it will only show spells that were added to the filter using a spell ID and not a name."] = "활성화하면 이름이 아니라 주문ID를 이용해 필터에 추가된 주문들만 표시합니다."
+L["When in a raid group display if anyone in your raid is targeting the current tooltip unit."] = "누구를 대상으로 잡고 있는지, 누가 이 유닛을 대상으로 잡았는지에 대한 정보를 툴팁에 추가합니다."
+L["When inside a battleground display personal scoreboard information on the main datatext bars."] = "전장 안에 있는 경우 주 정보문자에 자신의 각종 점수들을 표시하게 합니다."
+L["When opening the Chat Editbox to type a message having this option set means it will retain the last channel you spoke in. If this option is turned off opening the Chat Editbox should always default to the SAY channel."] = "이전에 말한 채널을 계속 유지할지 여부를 결정합니다.|n|n체크 해제 시 대화입력창을 열 때마다 일반 채널로 설정됩니다."
+L["When true, the header includes the player when not in a raid."] = "활성화시, 공격대에 속해있지 않아도 플레이어를 표시합니다."
+L["When you go AFK display the AFK screen."] = "자리비움 시 UI가 자리비움모드로 전환됩니다."
+L["Whitelist"] = "화이트리스트"
+L["Width Multiplier"] = "배경 가로길이 배율"
+L["Width"] = "가로 길이"
+L["Will attempt to sell another item in set interval after previous one was sold."] = true
+L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."] = true
+L["Word Wrap"] = true
+L["World Map Coordinates"] = "세계 지도 좌표"
+L["World State Frame"] = true
+L["Wrap After"] = "한 줄에 표시할 오라 수"
+L["X-Offset"] = "X 좌표"
+L["Y-Offset"] = "Y 좌표"
+L["You do not need to use 'Is Casting Anything' or 'Is Channeling Anything' for these spells to trigger."] = true
+L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."] = "기본 필터에 설정된 기본 주문들은 삭제할 수 없습니다. 대신 비활성화는 가능합니다."
+L["You must be targeting a player."] = "유저를 대상으로 잡은 후에 시도해야 합니다."
+L["You need to hold this modifier down in order to blacklist an aura by right-clicking the icon. Set to None to disable the blacklist functionality."] = true
+L["Your Auras First"] = "자기 주문 우선"
+L["xOffset"] = "X 좌표"
+L["yOffset"] = "Y 좌표"
+
+L["ACTIONBARS_DESC"] = "행동단축바의 설정을 변경합니다."
+L["AURAS_DESC"] = "미니맵 근처에 표시되는 강화/약화효과 아이콘에 관련된 옵션들입니다."
+L["BAGS_DESC"] = "통합가방과 가방바에 관련된 옵션들입니다."
+L["CHAT_DESC"] = "채팅과 패널에 관련된 옵션들입니다."
+L["COOLDOWN_DESC"] = "Adjust Cooldown Settings."
+L["DATATEXT_DESC"] = "정보문자에 관련된 옵션들입니다."
+L["ELVUI_DESC"] = "ElvUI는 WoW에서 지원하는 대부분의 기능을 대체하는 통합 애드온입니다."
+L["NAMEPLATE_DESC"] = "이름표에 관련된 옵션들입니다."
+L["PANEL_DESC"] = "좌우 패널의 크기를 조절합니다. 이 값에 따라 고정되어 있는 채팅창과 통합가방/은행 프레임의 크기도 변경됩니다."
+L["SKINS_DESC"] = "다른 애드온이나 게임 내 여러 프레임에 체크 시 스킨을 적용합니다."
+L["TOGGLESKIN_DESC"] = "체크 시 해당 프레임에 스킨을 사용합니다."
+L["TOOLTIP_DESC"] = "툴팁에 관련된 옵션들입니다."
+L["UNITFRAME_DESC"] = "유닛프레임 설정을 변경합니다."
+L["SEARCH_SYNTAX_DESC"] = [=[각종 가방에서 검색기능을 사용할 때, 다음의 명령어들을 활용하면
+ 자신이 원하는 조건에 맞는 아이템들만 검색하도록 할 수 있습니다.
+
+ |cff2eb7e4<< 특정형 >>|r
+ |cffceff00■|r q:등급 / quality:등급
+ - 영어로 쓴 등급을 가지는 아이템들만 검색합니다.
+ - 예) |cffceff00q:영웅|r 으로 검색하면 보라템들만 하이라이트 됩니다.
+ - 등급 키 : |cffA8A8A8일반|r, |cff15B300고급|r, |cff0091F2희귀|r, |cffC891FA영웅,|r |cffFF8000전설|r, |cffE6CC80계승|r
+
+ |cffceff00■|r l:템렙 / lvl:템렙 / level:템렙
+ - 입력한 숫자에 딱 맞는 템렙의 아이템들만 검색됩니다.
+
+ |cffceff00■|r t:아이템종류 / type:아이템종류 / slot:아이템종류
+ - 입력한 글자를 포함하는 종류인 아이템들만 표시합니다.
+ - 예) |cffceff00t:양손|r 으로 검색하면 양손 둔기, 양손 도검 등이 검색될 수 있습니다.
+
+ |cffceff00■|r n:이름 / name:이름
+ - 입력한 글자가 아이템 이름에 포함된 것들만 표시합니다.
+
+ |cffceff00■|r s:세트이름 / set:세트이름
+ - 입력한 글자가 포함됀 장비세트에 소속된 아이템들만 표시합니다.
+
+ |cffceff00■|r r:[level], reg:[level], rl:[level], regl:[level] or reqlvl:[level]
+ - For example, reqlvl:30 will find all items that require level 30.
+
+ |cffceff00■|r tt:[search], tip:[search] or tooltip:[search]
+ - For example, tt:binds will find all items that can be bound to account, on equip, or on pickup.
+
+
+ |cff2eb7e4<< 조건부여 >>|r
+ |cffceff00■|r ! (느낌표)
+ - 적은 조건을 제외하도록 합니다.
+ - 예) |cffceff00!q:영웅|r 을 사용하면 영웅등급이 아닌 모든 아이템들이 표시됩니다.
+
+ |cffceff00■|r | (백스페이스 옆 \키를 쉬프트)
+ - 여러 조건을 이어 붙였을 때, 각 조건 중 하나라도 만족하면 표시합니다.
+ - 예) |cffceff00q:영웅|t:무기|r 를 입력하면 영웅 등급인 아이템과 무기 종류인 아이템이 표시됩니다.
+
+ |cffceff00■|r & (쉬프트 7)
+ - 여러 조건을 이어 붙였을 때, 모든 조건을 만족하면 표시합니다.
+ - 예) |cffceff00q:영웅&t:무기|r 를 입력하면 영웅 등급이면서 무기 종류의 아이템만 표시됩니다.
+
+ |cffceff00■|r >, <, >=, <=
+ - 숫자 조건을 제어합니다.
+ - 예) |cffceff00lvl:>30|r 을 입력하면 템렙이 30을 초과하는 아이템들만 표시합니다.
+
+
+ |cff2eb7e4<< 예약어 >>|r
+ - soulbound, bound, bop : 획득시 귀속 아이템을 표시합니다.
+ - bou : 사용시 귀속 아이템을 표시합니다.
+ - boe : 착용 시 귀속 아이템을 표시합니다.
+ - boa : 계정 귀속 아이템을 표시합니다.
+ - quest : 퀘스트 아이템을 표시합니다.]=]
+
+L["TEXT_FORMAT_DESC"] = [=[글자가 표시되는 형식을 변경할 수 있습니다.
+
+|cff2eb7e4< 예시 >|r
+[namecolor][name] [difficultycolor][smartlevel] [shortclassification]
+[healthcolor][health:current-max]
+[powercolor][power:current]
+
+|cff2eb7e4< health(생명력) / power(자원) 형식 >|r
+|cffceff00current|r : 현재 수치
+|cffceff00percent|r : 현재 양을 %로 표시
+|cffceff00current-max|r : [현재 수치]-[최대값]
+|cffceff00current-percent|r : [현재 수치]-[%]
+|cffceff00current-max-percent|r : [현재 수치]-[최대값]-[%]
+|cffceff00deficit|r : 손실치만 표시하며 현재 수치가 최대치이면 표시하지 않음
+
+|cff2eb7e4< name(이름) 형식 >|r
+|cffceff00name:short|r : 최대 10글자
+|cffceff00name:medium|r : 최대 15글자
+|cffceff00name:long|r : 최대 20글자
+
+표시하고 싶지 않으면 빈칸으로 두면 되며, 자세한 정보는 |cff2eb7e4https://www.tukui.org/forum/viewtopic.php?t=6|r 에서 확인하세요.]=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to page differently.
+ Example: '[combat] 2;']=] ] = [=[이곳에 작성한 조건(예를 들어 전투여부)에 따라 이 행동단축바의 페이지를 자동으로 전환시킬 수 있습니다.
+
+매크로처럼 작성하세요.
+
+|cff2eb7e4< 예시 >|r
+|cffceff00[combat]2;1|r
+ : 전투에 돌입하면 2번 페이지로 변경, 전투가 끝나면 1번 페이지로 변경 ]=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to show/hide differently.
+ Example: '[combat] show;hide']=] ] = [=[이곳에 작성한 조건(예를 들어 전투여부)에 따라 이 행동단축바를 자동으로 숨기거나 표시할 수 있게 해줍니다.
+
+매크로처럼 작성하세요.
+
+|cff2eb7e4< 예시 >|r
+|cffceff00[combat]show;hide|r
+ : 전투에 돌입하면 표시, 전투가 끝나면 숨김]=]
+
+L[ [=[Specify a filename located inside the World of Warcraft directory. Textures folder that you wish to have set as a panel background.
+
+Please Note:
+-The image size recommended is 256x128
+-You must do a complete game restart after adding a file to the folder.
+-The file type must be tga format.
+
+Example: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Or for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here.]=] ] = [=[패널 배경에 그림을 입히고 싶으면 위치와 파일명를 이곳에 입력해야 합니다.
+
+|cff2eb7e4< 예시 >|r
+|cffceff00Interface/AddOns/ElvUI/Media/Textures/|cff2eb7e4TestImage|r
+- 위의 주소로 된 texture 폴더 안 TestImage.tga 그림을 불러옴
+- 위의 주소는 \ 대신 / 를 사용한 것. 직접 적을 땐 반드시 \ 로 주소구분
+
+|cff2eb7e4< 주의 >|r
+- 256 X 128 크기 권장
+- 그림을 와우 설치 폴더 안에 넣고 게임을 재시작해야 적용 가능
+- 확장자는 .tga 포맷만 가능
+
+간단히는 그림을 와우 설치 폴더에 넣은후 파일명만 적으세요.]=]
+
+-- Global Strings
+L["ACHIEVEMENTS"] = "업적"
+L["ALT_KEY_TEXT"] = "ALT"
+L["ARENA"] = "투기장"
+L["AUCTIONS"] = "경매"
+L["BAGSLOT"] = "가방"
+L["BARBERSHOP"] = "미용실"
+L["BATTLEGROUND"] = "전장"
+L["BATTLEFIELDS"] = "전장"
+L["BLOCK"] = "방패 막기"
+L["BUFFOPTIONS_LABEL"] = "강화 및 약화 효과"
+L["CLASS"] = "직업"
+L["CHANNEL"] = "채널"
+L["COLOR"] = "색상"
+L["COLORS"] = "색상"
+L["COMBAT"] = "전투"
+L["COMBAT_TEXT_RUNE_BLOOD"] = "혈기 룬"
+L["COMBAT_TEXT_RUNE_DEATH"] = "죽음의 룬"
+L["COMBAT_TEXT_RUNE_FROST"] = "냉기 룬"
+L["COMBAT_TEXT_RUNE_UNHOLY"] = "부정 룬"
+L["COMBO_POINTS"] = "연계 점수"
+L["CTRL_KEY"] = "CTRL"
+L["CUSTOM"] = "사용자 설정"
+L["DAMAGER"] = "공격 전담"
+L["DEFAULT"] = "기본"
+L["DELETE"] = "삭제"
+L["DISABLE"] = "비활성"
+L["DRESSUP_FRAME"] = "미리보기"
+L["DUNGEON_DIFFICULTY"] = "던전 난이도"
+L["DUNGEONS"] = "던전"
+L["EMOTE"] = "감정 표현"
+L["ENEMY"] = "적"
+L["ENERGY"] = "기력"
+L["FACTION_STANDING_LABEL1"] = "매우 적대적"
+L["FACTION_STANDING_LABEL2"] = "적대적"
+L["FACTION_STANDING_LABEL3"] = "약간 적대적"
+L["FACTION_STANDING_LABEL4"] = "중립적"
+L["FACTION_STANDING_LABEL5"] = "약간 우호적"
+L["FACTION_STANDING_LABEL6"] = "우호적"
+L["FACTION_STANDING_LABEL7"] = "매우 우호적"
+L["FACTION_STANDING_LABEL8"] = "확고한 동맹"
+L["FILTERS"] = "필터 설정"
+L["FLIGHT_MAP"] = "비행 지도"
+L["FOCUS"] = "집중"
+L["FONT_SIZE"] = "글자 크기"
+L["FRIEND"] = "친구"
+L["FRIENDS"] = "친구"
+L["GROUP"] = "Group"
+L["GUILD"] = "길드"
+L["GUILD_BANK"] = "길드 은행"
+L["HAPPINESS"] = "만족도"
+L["HEALER"] = "치유 전담"
+L["HEALTH"] = "생명력"
+L["HIDE"] = "숨기기"
+L["INSCRIPTION"] = "주문각인"
+L["INSPECT"] = "살펴보기"
+L["INTERFACE_OPTIONS"] = "인터페이스 설정"
+L["INTERRUPTED"] = "전장"
+L["ITEM_BIND_QUEST"] = "퀘스트 아이템"
+L["ITEMS"] = "아이템"
+L["KEY_BINDINGS"] = "단축키 설정"
+L["LANGUAGE"] = "언어"
+L["LEAVE_VEHICLE"] = "탈것 내리기"
+L["LEVEL"] = "레벨"
+L["LOCK_ACTIONBAR_TEXT"] = "행동 단축바 잠그기"
+L["LOOT"] = "전리품"
+L["MACROS"] = "매크로 설정"
+L["MAIL_LABEL"] = "우편"
+L["MANA"] = "마나"
+L["MAP_FADE_TEXT"] = "이동 시 지도 투명화"
+L["MERCHANT"] = "상품 목록"
+L["MINIMAP_LABEL"] = "미니맵"
+L["MISCELLANEOUS"] = "기타 설정"
+L["NAME"] = "이름"
+L["NONE"] = "없음"
+L["OFFICER"] = "길드관리자"
+L["OPACITY"] = "투명도"
+L["OPTION_TOOLTIP_ACTION_BUTTON_USE_KEY_DOWN"] = "단축키를 눌렀다 뗐을 때가 아니라, 누르는 즉시 선택된 행동을 실행합니다."
+L["OPTION_TOOLTIP_TIMESTAMPS"] = "대화 시각의 표시 형식을 선택합니다."
+L["PARTY"] = "파티"
+L["PET"] = "소환수"
+L["PLAYER"] = "플레이어"
+L["PLAYER_DIFFICULTY1"] = "일반"
+L["PLAYER_DIFFICULTY2"] = "영웅"
+L["RAGE"] = "분노"
+L["RAID"] = "공격대"
+L["RAID_TARGET_1"] = "별"
+L["RAID_TARGET_2"] = "동그라미"
+L["RAID_TARGET_3"] = "다이아몬드"
+L["RAID_TARGET_4"] = "세모"
+L["RAID_TARGET_5"] = "달"
+L["RAID_TARGET_6"] = "네모"
+L["RAID_TARGET_7"] = "가위표"
+L["RAID_TARGET_8"] = "해골"
+L["REPUTATION"] = "평판"
+L["ROLE"] = "역할"
+L["RUNIC_POWER"] = "룬 마력"
+L["SAY"] = "일반 대화"
+L["SHIFT_KEY"] = "SHIFT"
+L["SHORT"] = "줄이기"
+L["SHOW"] = "표시"
+L["SPEED"] = "속도"
+L["SPELLBOOK"] = "마법책"
+L["TALENTS"] = "특성"
+L["TANK"] = "방어 전담"
+L["TARGET"] = "대상"
+L["TIMEMANAGER_TITLE"] = "시계"
+L["TIMESTAMPS_LABEL"] = "대화 시각"
+L["TRADE"] = "거래 요청"
+L["TRADESKILLS"] = "전문 기술"
+L["TUTORIAL_TITLE47"] = "토템바"
+L["UI_SCALE"] = "UI 확대/축소"
+L["UNIT_NAMEPLATES_TYPES"] = "이름표 배열 방식"
+L["UNIT_NAMEPLATES_TYPE_1"] = "이름표 겹침 허용"
+L["UNIT_NAMEPLATES_TYPE_2"] = "이름표 상하 정렬"
+L["WHISPER"] = "귓속말"
+L["WORLD_MAP"] = "지도"
+L["XPBAR_LABEL"] = "경험치바"
+L["YELL"] = "외침"
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Locales/ptBR.lua b/ElvUI_OptionsUI/Locales/ptBR.lua
new file mode 100644
index 0000000..23ed4c0
--- /dev/null
+++ b/ElvUI_OptionsUI/Locales/ptBR.lua
@@ -0,0 +1,1388 @@
+-- Portuguese localization file for ptBR.
+local L = ElvUI[1].Libs.ACL:NewLocale("ElvUI", "ptBR")
+
+L["%s and then %s"] = "%s e depois %s"
+L["2D"] = "2D"
+L["3D"] = "3D"
+L["AFK Mode"] = true
+L["ANCHOR_CURSOR"] = true
+L["ANCHOR_CURSOR_LEFT"] = true
+L["ANCHOR_CURSOR_RIGHT"] = true
+L["Abbreviation"] = true
+L["Above Chat"] = "Acima do Bate-papo"
+L["Above"] = "Acima"
+L["Accept Invites"] = "Aceitar Convites"
+L["Action Paging"] = "Paginação da Barra de Ação"
+L["ActionBars"] = "Barras de Ações"
+L["Actions"] = true
+L["Add Item or Search Syntax"] = true
+L["Add Name"] = true
+L["Add Regular Filter"] = true
+L["Add Special Filter"] = true
+L["Add Spell ID or Name"] = true
+L["Add SpellID"] = "Adicionar SpellID"
+L["Add a Name to the list."] = true
+L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."] = true
+L["Add a spell to the filter."] = "Adicionar um feitiço ao filtro."
+L["Add an item or search syntax to the ignored list. Items matching the search syntax will be ignored."] = true
+L["Additional Power Text"] = true
+L["Additional spacing between each individual group."] = true
+L["Additive Blend"] = true
+L["Adjust the height of your right chat panel."] = true
+L["Adjust the position of the threat bar to either the left or right datatext panels."] = "Ajustar a posição da barra de agro para os painéis de texto informativos da esquerda ou da direita."
+L["Adjust the size of the minimap."] = "Ajustar o tamanho do minimapa."
+L["Adjust the width of the bag frame."] = "Ajusta a largura do quadro das bolsas."
+L["Adjust the width of the bank frame."] = "Ajusta a largura do quadro do banco."
+L["Adjust the width of your right chat panel."] = true
+L["Alert Frames"] = "Alertas"
+L["Alerts"] = true
+L["Allow LBF to handle the skinning of this element."] = true
+L["Allowed Combat Repeat"] = true
+L["Alpha Fading"] = true
+L["Alpha Key"] = true
+L["Alpha channel is taken from the color option."] = true
+L["Alpha"] = "Transparência"
+L["Always Display"] = "Exibir sempre"
+L["Always Hide"] = "Sempre Ocultar"
+L["Always Show Realm"] = true
+L["Always Show Target Health"] = true
+L["Ammo Pouch"] = true
+L["An X offset (in pixels) to be used when anchoring new frames."] = true
+L["An Y offset (in pixels) to be used when anchoring new frames."] = true
+L["Anchor Point"] = "Ponto de Fixação"
+L["Announce Interrupts"] = "Anunciar Interrupções"
+L["Announce when you interrupt a spell to the specified chat channel."] = "Anunciar quando interromper um feitiço para o canal de bate-papo especificado."
+L["Applies the font and font size settings throughout the entire user interface. Note: Some font size settings will be skipped due to them having a smaller font size by default."] = true
+L["Applies the primary texture to all statusbars."] = true
+L["Apply Font To All"] = true
+L["Apply Texture To All"] = true
+L["Apply this filter if a buff has remaining time greater than this. Set to zero to disable."] = true
+L["Apply this filter if a buff has remaining time less than this. Set to zero to disable."] = true
+L["Apply this filter if a debuff has remaining time greater than this. Set to zero to disable."] = true
+L["Apply this filter if a debuff has remaining time less than this. Set to zero to disable."] = true
+L["Are you sure you want to reset ActionBars settings?"] = true
+L["Are you sure you want to reset Auras settings?"] = true
+L["Are you sure you want to reset Bags settings?"] = true
+L["Are you sure you want to reset Chat settings?"] = true
+L["Are you sure you want to reset Cooldown settings?"] = true
+L["Are you sure you want to reset DataBars settings?"] = true
+L["Are you sure you want to reset DataTexts settings?"] = true
+L["Are you sure you want to reset General settings?"] = true
+L["Are you sure you want to reset NamePlates settings?"] = true
+L["Are you sure you want to reset Tooltip settings?"] = true
+L["Are you sure you want to reset UnitFrames settings?"] = true
+L["Arena Frame"] = true
+L["Arena Registrar"] = true
+L["Arena"] = true
+L["Ascending or Descending order."] = true
+L["Ascending"] = "Ascendente"
+L["Assist Target"] = "Alvo do Assistente"
+L["Assist"] = "Assistente"
+L["At what point should the text be displayed. Set to -1 to disable."] = "Em qual ponto o texto deve ser mostrado. Defina como -1 para desabilitar."
+L["Attach Text To"] = true
+L["Attach To"] = "Anexar ao"
+L["Attempt to create URL links inside the chat."] = "Tentar criar links URL dentro do bate-papo."
+L["Attempt to lock the left and right chat frame positions. Disabling this option will allow you to move the main chat frame anywhere you wish."] = "Tentar bloquear a posição dos painéis do bate-papo esquerdo e direito. Desativar esta opção permitirá mover os painéis de bate-papo para qualquer lugar que desejar."
+L["Attempt to support eyefinity/nvidia surround."] = true
+L["Aura Bars"] = "Barras de Auras"
+L["Aura Filters"] = true
+L["Auto Greed/DE"] = "Escolher Ganância/Desencantar automaticamente"
+L["Auto Hide"] = true
+L["Auto Repair"] = "Reparar automaticamente"
+L["Auto-Hide"] = "Auto-Esconder"
+L["Automatic"] = true
+L["Automatically accept invites from guild/friends."] = "Aceitar convites de pessoas da lista de amigos ou guilda automaticamente"
+L["Automatically hide the objetive frame during boss or arena fights."] = true
+L["Automatically repair using the following method when visiting a merchant."] = "Reparar automaticamente usando o seguinte método ao visitar um vendedor."
+L["Automatically select greed or disenchant (when available) on green quality items. This will only work if you are the max level."] = "Selecionar automaticamente ganância ou desencantar (quando disponível) em itens de qualidade verde. Funciona apenas se estiver no nível máximo."
+L["Automatically vendor gray items when visiting a vendor."] = "Vender itens cinzentos automaticamente quando visitar um vendedor"
+L["Available Tags"] = true
+L["BG Map"] = "Mapa do CB"
+L["BG Score"] = "Placar do CB"
+L["BINDING_HEADER_RAID_TARGET"] = "Marcadores de Alvo"
+L["BOSS"] = true
+L["Backdrop Color"] = "Cor de fundo"
+L["Backdrop Faded Color"] = "Cor de fundo desvanecida"
+L["Backdrop Spacing"] = true
+L["Backdrop color of transparent frames"] = "Cor de fundo de Painéis transparentes"
+L["Backdrop"] = "Fundo"
+L["Background Glow"] = true
+L["Bad Color"] = true
+L["Bad Scale"] = true
+L["Bad Transition Color"] = true
+L["Bad"] = "Mau"
+L["Bag 1"] = true
+L["Bag 2"] = true
+L["Bag 3"] = true
+L["Bag 4"] = true
+L["Bag Sorting"] = true
+L["Bag Spacing"] = true
+L["Bag"] = true
+L["Bag-Bar"] = "Barra das Bolsas"
+L["Bags Only"] = true
+L["Bags/Bank"] = true
+L["Bank 1"] = true
+L["Bank 2"] = true
+L["Bank 3"] = true
+L["Bank 4"] = true
+L["Bank 5"] = true
+L["Bank 6"] = true
+L["Bank 7"] = true
+L["Bank Only"] = true
+L["Bar Direction"] = "Direção da Barra"
+L["Bars will transition smoothly."] = "Barras terão transição suave."
+L["Battleground Texts"] = "Textos do Campo de Batalha"
+L["Begin a new row or column after this many auras."] = "Começar uma nova coluna ou linha depois dessa quantia de auras."
+L["Below Chat"] = "Abaixo do Bate-papo"
+L["Below"] = "Abaixo"
+L["Blacklist Modifier"] = true
+L["Blacklist"] = "Lista negra"
+L["Blend Mode"] = true
+L["Blend"] = true
+L["BlizzUI Improvements"] = true
+L["Blizzard Style"] = true
+L["Blizzard"] = true
+L["Block Combat Click"] = true
+L["Block Combat Hover"] = true
+L["Block Mouseover Glow"] = true
+L["Block Target Glow"] = true
+L["Blocks all click events while in combat."] = true
+L["Blocks datatext tooltip from showing in combat."] = true
+L["Border Color"] = "Cor da borda"
+L["Border Glow"] = true
+L["Border"] = true
+L["Borders"] = "Bordas"
+L["Both"] = true
+L["Bottom Left"] = true
+L["Bottom Panel"] = "Painel Infeior"
+L["Bottom Right"] = true
+L["Bottom to Top"] = "De baixo para cima"
+L["Bottom"] = true
+L["BottomLeftMiniPanel"] = "Minimap BottomLeft (Inside)"
+L["BottomMiniPanel"] = "Minimap Bottom (Inside)"
+L["BottomRightMiniPanel"] = "Minimap BottomRight (Inside)"
+L["Buff Indicator"] = "Indicador de Bônus"
+L["Button Size (Bag)"] = "Tamanho do Botão (Bolsas)"
+L["Button Size (Bank)"] = "Tamanho do Botão (Banco)"
+L["Button Size"] = "Tamanho do botão"
+L["Button Spacing"] = "Espaçamento do botão"
+L["Buttons Per Row"] = "Botões por linha"
+L["Buttons"] = "Botões"
+L["By Type"] = "Por tipo"
+L["Calendar Frame"] = "Calendário"
+L["Cast Bar"] = true
+L["Cast Color"] = true
+L["Cast No Interrupt Color"] = true
+L["Cast Time Format"] = true
+L["Castbar"] = "Barra de lançamento"
+L["Casting"] = true
+L["Center"] = "Centro"
+L["Change settings for the display of the location text that is on the minimap."] = "Alterar as configurações de exibição do texto de localização que está no minimapa."
+L["Change the alpha level of the frame."] = "Mudar o nível de transparência do quadro."
+L["Channel Alerts"] = true
+L["Change the width and controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Channel Time Format"] = true
+L["Character Frame"] = "Personagem"
+L["Chat Bubble Names"] = true
+L["Chat Bubbles Style"] = "Estilo dos Balões de Fala"
+L["Chat Bubbles"] = true
+L["Chat EditBox Position"] = "Posição da caixa de edição do bate-papo"
+L["Chat Output"] = true
+L["Check these to only have the filter active in certain difficulties. If none are checked, it is active in all difficulties."] = true
+L["CheckBox Skin"] = true
+L["Choose Export Format"] = true
+L["Choose UIPARENT to prevent it from hiding with the unitframe."] = true
+L["Choose What To Export"] = true
+L["Choose when you want the tooltip to show in combat. If a modifer is chosen, then you need to hold that down to show the tooltip."] = true
+L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."] = true
+L["Class Backdrop"] = "Fundo por classe"
+L["Class Castbars"] = "Barras de Lançamento da Classe"
+L["Class Color Mentions"] = true
+L["Class Color Override"] = "Sobrescrever Cor da Classe"
+L["Class Health"] = "Vida por Classe"
+L["Class Power"] = "Poder por classe"
+L["Class Resources"] = "Recursos de Classe"
+L["Class Totems"] = true
+L["Clear Filter"] = true
+L["Clear Search On Close"] = true
+L["Click Through"] = "Clicar através"
+L["Clickable Height"] = true
+L["Clickable Size"] = true
+L["Clickable Width / Width"] = true
+L["Coding:"] = "Codificação:"
+L["Color Keybind Text when Out of Range, instead of the button."] = true
+L["Color Keybind Text"] = true
+L["Color Override"] = true
+L["Color Turtle Buffs"] = "Colorir bônus de Tartaruga"
+L["Color all buffs that reduce the unit's incoming damage."] = "Colorir todos os bônus que reduzem o dano recebido pela unidade."
+L["Color aurabar debuffs by type."] = "Colorir penalidades da barra de auras por tipo."
+L["Color by Value"] = true
+L["Color castbars by the class of player units."] = true
+L["Color castbars by the reaction type of non-player units."] = true
+L["Color health by amount remaining."] = "Colorir a vida pela quantidade restante."
+L["Color health by classcolor or reaction."] = "Colorir a vida pela cor da classe ou reação."
+L["Color health by threat status."] = true
+L["Color of the actionbutton when not usable."] = true
+L["Color of the actionbutton when out of power (Mana, Rage)."] = "Cor do botão de ação quando sem poder (Mana, Raiva)."
+L["Color of the actionbutton when out of range."] = "Cor do botão de ação quando fora de alcance."
+L["Color of the actionbutton when usable."] = true
+L["Color power by classcolor or reaction."] = "Colorir poder pela cor da classe ou reação."
+L["Color power by threat status."] = true
+L["Color some texts use."] = "Cores que alguns textos usam."
+L["Color the health backdrop by class or reaction."] = "Colorir o fundo da vida pela cor da classe ou reação."
+L["Color the unit healthbar if there is a debuff that can be dispelled by you."] = "Colorir a barra de vida se existir uma penalidade que você possa dissipar."
+L["Color when the text is about to expire"] = "Cor do texto quando está quase a expirar."
+L["Color when the text is in the days format."] = "Cor do texto quando está em formato de dias."
+L["Color when the text is in the hours format."] = "Cor do texto quando está em formato de horas."
+L["Color when the text is in the minutes format."] = "Cor do texto quando está em formato de minutos."
+L["Color when the text is in the seconds format."] = "Cor do texto quando está em formato de segundos."
+L["Colored Icon"] = "Ícone Colorido"
+L["Coloring (Specific)"] = "Coloração (Específica)"
+L["Coloring"] = "Coloração"
+L["Colorize Selected Text"] = true
+L["Colors the border according to the Quality of the Item."] = true
+L["Combat Icon"] = true
+L["Combat Override Key"] = true
+L["CombatText Font"] = "Fonte do texto de Combate"
+L["Combo Point"] = true
+L["Comparison Font Size"] = true
+L["Condensed"] = true
+L["Configure Auras"] = "Configurar Auras"
+L["Control enemy nameplates toggling on or off when in combat."] = true
+L["Control friendly nameplates toggling on or off when in combat."] = true
+L["Controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Controls the amount of decimals used in values displayed on elements like NamePlates and UnitFrames."] = true
+L["Controls the speed at which smoothed bars will be updated."] = true
+L["Controls how many seconds of inactivity has to pass before chat is faded."] = true
+L["Cooldown Orientation"] = true
+L["Cooldown Text"] = "Texto do Tempo de Recarga"
+L["Cooldowns"] = true
+L["Copy From"] = "Copiar de"
+L["Copy Settings From"] = true
+L["Copy settings from another unit."] = true
+L["Core |cff1784d1E|r|cffe5e3e3lvUI|r options."] = true
+L["Count Font Size"] = "Tamanho da Fonte do Contador"
+L["Count xOffset"] = true
+L["Count yOffset"] = true
+L["Create Custom Text"] = true
+L["Create Filter"] = "Criar filtro"
+L["Create a filter, once created a filter can be set inside the buffs/debuffs section of each unit."] = "Criar um filtro, uma vez criado o filtro pode ser definido dentro da seção dos bônus/penalidades de cada unidade."
+L["Credits"] = "Créditos"
+L["Crop Icons"] = true
+L["Currency Format"] = "Formato de moeda"
+L["Current - Max | Percent"] = true
+L["Current - Max"] = "Atual - Máximo"
+L["Current - Percent (Remaining)"] = true
+L["Current - Percent"] = "Atual - Porcentagem"
+L["Current - Remaining"] = true
+L["Current / Max"] = "Atual / Máximo"
+L["Current Level"] = true
+L["Current"] = "Atual"
+L["Curse Effect"] = true
+L["Cursor Anchor Offset X"] = true
+L["Cursor Anchor Offset Y"] = true
+L["Cursor Anchor Type"] = true
+L["Cursor Anchor"] = true
+L["Custom Backdrop"] = true
+L["Custom Color"] = true
+L["Custom Dead Backdrop"] = true
+L["Custom Faction Colors"] = true
+L["Custom Texts"] = "Textos Personalizados"
+L["Custom Texture"] = true
+L["Custom Timestamp Color"] = true
+L["Cutaway Bars"] = true
+L["DATABAR_DESC"] = true
+L["Darken Inactive"] = "Escurecer Inativos"
+L["DataBars"] = true
+L["DataTexts"] = "Textos Informativos"
+L["Datatext Panel (Left)"] = "Painel de Textos Informativos (Esquerdo)"
+L["Datatext Panel (Right)"] = "Painel de Textos Informativos (Direito)"
+L["Date Format"] = true
+L["Days"] = "Dias"
+L["Debuff Highlighting"] = "Destacar Penalidades"
+L["Debug Tools"] = "Ferramentas de Depuração"
+L["Decimal Length"] = true
+L["Decimal Threshold"] = true
+L["Decode Text"] = true
+L["Default Color"] = true
+L["Default Font"] = "Fonte Padrão"
+L["Default Settings"] = true
+L["Deficit"] = "Défice"
+L["Defines how the group is sorted."] = "Define como o grupo é organizado"
+L["Defines the sort order of the selected sort method."] = "Define a ordem de organização do método escolhido"
+L["Delete Filter"] = "Apagar Filtro"
+L["Delete a created filter, you cannot delete pre-existing filters, only custom ones."] = "Excluir um filtro criado, você não pode excluir filtros pré-existentes, apenas aqueles personalizados."
+L["Desaturate Cooldowns"] = true
+L["Desaturate Junk Items"] = true
+L["Desaturated Icon"] = true
+L["Descending"] = "Descendente"
+L["Detach From Frame"] = "Destacar do Quadro"
+L["Detached Width"] = "Largura quando Destacado"
+L["Direction the bag sorting will use to allocate the items."] = "Direção que o organizador de bolsas irá usar para distribuir os itens."
+L["Direction the bar moves on gains/losses"] = true
+L["Direction the health bar moves when gaining/losing health."] = "Direção em que a barra da vida se move quando se ganha/perde vida."
+L["Disable Bag Sort"] = true
+L["Disable Bank Sort"] = true
+L["Disable Debuff Highlight"] = true
+L["Disabled Blizzard Frames"] = true
+L["Disabled Blizzard"] = true
+L["Disables the focus and target of focus unitframes."] = true
+L["Disables the player and pet unitframes."] = true
+L["Disables the target and target of target unitframes."] = true
+L["Disconnected"] = "Desconectado"
+L["Disease Effect"] = true
+L["Display Frames"] = "Exibir Quadros"
+L["Display Item Level"] = true
+L["Display Player"] = "Exibir Jogador"
+L["Display Target"] = "Mostrar Alvo"
+L["Display Text"] = "Mostrar Texto"
+L["Display a healer icon over known healers inside battlegrounds or arenas."] = "Mostra um ícone de Curandeiro sobre curandeiros conhecidosem campos de batalha ou arenas."
+L["Display a panel across the bottom of the screen. This is for cosmetic only."] = "Mostra um painel na parte inferior da tela. Apenas para efeito cosmético."
+L["Display a panel across the top of the screen. This is for cosmetic only."] = "Mostra um painel na parte superior da tela. Apenas para efeito cosmético."
+L["Display a spark texture at the end of the castbar statusbar to help show the differance between castbar and backdrop."] = "Exibir uma textura de faísca no fim da Barra de Lançamento para ajudar a diferenciar a barra de lançamento e o fundo."
+L["Display an exclamation mark on items that starts a quest."] = true
+L["Display battleground messages in the middle of the screen."] = true
+L["Display bind names on action buttons."] = "Exibir atalhos nos botões de ação."
+L["Display cooldown text on anything with the cooldown spiral."] = "Exibir texto do tempo de recarga para tudo que tenha espiral de recarga."
+L["Display data panels below the chat, used for datatexts."] = "Mostra painéis abaixo do bate-papo, usados para textos informativos."
+L["Display emotion icons in chat."] = "Exibir ícones emotivos no bate-papo."
+L["Display guild ranks if a unit is guilded."] = "Mostrar o Posto da guilda se a unidade possuir uma."
+L["Display how many of a certain item you have in your possession."] = "Mostra quantos de certo item você possui."
+L["Display macro names on action buttons."] = "Exibir nomes das macros nos botões de ação."
+L["Display minimap panels below the minimap, used for datatexts."] = "Exibir painéis abaixo do minimapa, usados para textos informativos."
+L["Display player titles."] = "Mostrar títulos dos jogadores."
+L["Display reminder bar on the minimap."] = true
+L["Display the castbar icon inside the castbar."] = true
+L["Display the castbar inside the information panel, the icon will be displayed outside the main unitframe."] = true
+L["Display the hyperlink tooltip while hovering over a hyperlink."] = "Exibir a tooltip de um hyperlink quando pairar por cima deste."
+L["Display the junk icon on all grey items that can be vendored."] = true
+L["Display the name of the unit on the chat bubble."] = true
+L["Display the npc ID when mousing over a npc tooltip."] = true
+L["Display the spell or item ID when mousing over a spell or item tooltip."] = "Quando pairar o rato (mouse) sobre Itens ou Feitiços, mostra o ID destes na tooltip."
+L["Display the target of your current cast. Useful for mouseover casts."] = "Mostra os alvos do seu lançamento atual. Útil para lançamentos mouseover."
+L["Display tick marks on the castbar for channelled spells. This will adjust automatically for spells like Drain Soul and add additional ticks based on haste."] = "Exibir marcas na barra de lançamento para feitiços canalizados. Isto irá se ajustar automaticamente para feitiços como Drenar Alma e adicionará ticks baseado na Aceleração."
+L["Displayed server time."] = true
+L["Displays a detailed report of every item sold when enabled."] = true
+L["Displays item level on equippable items."] = true
+L["Display Types"] = true
+L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."] = true
+L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."] = true
+L["Donations:"] = "Doações:"
+L["Down"] = "Baixo"
+L["Dropdown CheckBox Skin"] = true
+L["Dungeon & Raid Filter"] = true
+L["Duration Enable"] = true
+L["Duration Font Size"] = true
+L["Duration Reverse"] = "Duração Reversa"
+L["Duration Text"] = true
+L["Duration"] = "Duração"
+L["Editbox History Size"] = true
+L["ELVUI_CREDITS"] = "Gostaria de agradecer especialmente às seguintes pessoas por me ajudarem a manter este addon, quer testando, codificando, ou através de doações. Em relação às doações, esta lista contém apenas o nome das pessoas que me contataram através de mensagem privada nos forums, se o seu nome está em falta e gostaria de o ver adicionado, por favor contate-me por mensagem privada."
+L["ENEMY_NPC"] = "Enemy NPC"
+L["ENEMY_PLAYER"] = "Enemy Player"
+L["Elite Icon"] = true
+L["Emotion Icons"] = "Ícones Emotivos"
+L["Enable Custom Color"] = true
+L["Enable the use of separate size options for the right chat panel."] = true
+L["Enable/Disable the Bag-Bar."] = "Ativar/Desativar a Barra das Bolsas."
+L["Enable/Disable the all-in-one bag."] = "Ativar/Desativar a Bolsa tudo-em-um."
+L["Enable/Disable the loot frame."] = "Ativar/Desativar painel de saques."
+L["Enable/Disable the loot roll frame."] = "Ativar/Desativar painel de disputa de saques"
+L["Enable/Disable the minimap. |cffFF0000Warning: This will prevent you from seeing the consolidated buffs bar, and prevent you from seeing the minimap datatexts.|r"] = true
+L["Enable/Disable the scaling of targetted nameplates."] = true
+L["Enables the ElvUI Raid Control panel."] = true
+L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."] = true
+L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."] = true
+L["Enabling this will check your health amount."] = true
+L["Enabling this will check your power amount."] = true
+L["Enchanting"] = true
+L["Enemy Aura Type"] = "Tipo de Aura do Inimigo"
+L["Enemy Combat Toggle"] = true
+L["Enemy NPC Frames"] = true
+L["Enemy Player Frames"] = true
+L["Enemy"] = "Inimigo"
+L["Engineering"] = true
+L["Enhanced PVP Messages"] = true
+L["Equipped Item Color"] = true
+L["Equipped Item"] = true
+L["Error decoding data. Import string may be corrupted!"] = true
+L["Error exporting profile!"] = true
+L["Exclude Name"] = true
+L["Excluded Names"] = true
+L["Excluded names will not be class colored."] = true
+L["Expiring"] = "Expirando"
+L["Export Profile"] = true
+L["Exported"] = true
+L["FRIENDLY_NPC"] = "Friendly NPC"
+L["FRIENDLY_PLAYER"] = "Friendly Player"
+L["Fade Chat Toggles"] = true
+L["Fade Out Delay"] = true
+L["Fade Out"] = true
+L["Fade Tabs No Backdrop"] = true
+L["Fade Threshold"] = "Limiar para Desvanecer"
+L["Fade Undocked Tabs"] = true
+L["Fade the chat text when there is no activity."] = "Desvanece o texto do bate-papo quando não há atividade."
+L["Fader"] = true
+L["Fades the buttons that toggle chat windows when that window has been toggled off."] = true
+L["Fades the text on chat tabs that are docked in a panel where the backdrop is disabled."] = true
+L["Fades the text on chat tabs that are not docked at the left or right chat panel."] = true
+L["Fill"] = "Preencher"
+L["Filled"] = "Preenchido"
+L["Filter Priority"] = true
+L["Filter Search"] = true
+L["Filter Type"] = "Tipo de filtro"
+L["Filter already exists!"] = true
+L["Filters Page"] = true
+L["Filters are not allowed to have commas in their name. Stripping commas from filter name."] = true
+L["Flash"] = true
+L["Fluid Position Buffs on Debuffs"] = true
+L["Fluid Position Debuffs on Buffs"] = true
+L["Flyout Direction"] = true
+L["Flyout Spacing"] = true
+L["Focus"] = true
+L["FocusTarget"] = true
+L["Font Outline"] = "Contorno da Fonte"
+L["Font"] = "Fonte"
+L["Fonts"] = "Fontes"
+L["Force Off"] = "Forçado Desligado"
+L["Force On"] = "Forçado Ligado"
+L["Force Reaction Color"] = true
+L["Force the frames to show, they will act as if they are the player frame."] = "Forçar os quadros para aparecerem, irão se comportar como se fossem o quadro do jogador."
+L["Forces Debuff Highlight to be disabled for these frames"] = true
+L["Forces Mouseover Glow to be disabled for these frames"] = true
+L["Forces Target Glow to be disabled for these frames"] = true
+L["Forces reaction color instead of class color on units controlled by players."] = true
+L["Format"] = "Formato"
+L["Frame Glow"] = true
+L["Frame Level"] = true
+L["Frame Orientation"] = true
+L["Frame Strata"] = true
+L["Frequent Updates"] = "Atualizações frequentes"
+L["Friendly Aura Type"] = "Tipo de Aura para Aliado"
+L["Friendly Combat Toggle"] = true
+L["Friendly NPC Frames"] = true
+L["Friendly Player Frames"] = true
+L["Friendly"] = "Aliado"
+L["Full Overlay"] = true
+L["Full"] = true
+L["GM Chat"] = true
+L["GPS Arrow"] = true
+L["Gems"] = true
+L["General Options"] = true
+L["Global (Account Settings)"] = true
+L["Global Fade Transparency"] = true
+L["Global"] = true
+L["Glow"] = "Brilhar"
+L["Gold Format"] = true
+L["Good Color"] = true
+L["Good Scale"] = true
+L["Good Transition Color"] = true
+L["Good"] = "Bom"
+L["Gossip Frame"] = "Fofocas"
+L["Group By"] = "Agrupar por"
+L["Group Spacing"] = true
+L["Grouping & Sorting"] = true
+L["Groups Per Row/Column"] = "Grupos por Linha/Coluna"
+L["Growth Direction"] = "Direção de crescimento"
+L["Growth X-Direction"] = true
+L["Growth Y-Direction"] = true
+L["Growth direction from the first unitframe."] = "Direção de crescimento a partir do primeiro quado de unidade."
+L["Guide:"] = true
+L["Guild Ranks"] = "Posto na Guilda"
+L["Guild Registrar"] = "Registrar Guilda"
+L["HH:MM Threshold"] = true
+L["HH:MM"] = true
+L["Header Font Size"] = true
+L["Heal Prediction"] = "Curas por vir"
+L["Healer Icon"] = "Ícone de Curador"
+L["Health Backdrop Multiplier"] = true
+L["Health Backdrop"] = "Fundo da Vida"
+L["Health Bar"] = true
+L["Health Border"] = "Borda da Vida"
+L["Health By Value"] = "Vida por Valor"
+L["Health Color"] = true
+L["Health Length"] = true
+L["Health Threshold"] = true
+L["Health"] = "Vida"
+L["Height Multiplier"] = "Multiplicador de Altura"
+L["Height of the objective tracker. Increase size to be able to see more objectives."] = true
+L["Height"] = "Altura"
+L["Help Frame"] = "Ajuda"
+L["Herbalism"] = true
+L["Here you can add items or search terms that you want to be excluded from sorting. To remove an item just click on its name in the list."] = true
+L["Hide At Max Level"] = true
+L["Hide Both"] = "Esconder Ambos"
+L["Hide Error Text"] = "Esconder Texto de Erro"
+L["Hide Frame"] = true
+L["Hide In Combat"] = true
+L["Hide In Vehicle"] = true
+L["Hide Spell Name"] = true
+L["Hide Time"] = true
+L["Hide specific sections in the datatext tooltip."] = true
+L["Hide tooltip while in combat."] = "Esconder tooltip em combate"
+L["Hides the red error text at the top of the screen while in combat."] = "Esconde o texto de erro vermelho do topo da tela quando em combate."
+L["History Size"] = true
+L["History"] = true
+L["Horizontal Spacing"] = "Espamento Horizontal"
+L["Horizontal"] = "Horizontal"
+L["Hours"] = "Horas"
+L["Hover Highlight"] = true
+L["Hover"] = true
+L["How long the cutaway health will take to fade out."] = true
+L["How long the cutaway power will take to fade out."] = true
+L["How many seconds the castbar should stay visible after the cast failed or was interrupted."] = true
+L["How much time before the cutaway health starts to fade."] = true
+L["How much time before the cutaway power starts to fade."] = true
+L["Hyperlink Hover"] = "Pairar no hyperlink"
+L["Icon Frame"] = true
+L["Icon Inside Castbar"] = true
+L["Icon Only"] = true
+L["Icon Position"] = true
+L["Icon Size"] = true
+L["Icon"] = "Ícone"
+L["Icon: BOTTOM"] = "Ícone: ABAIXO"
+L["Icon: BOTTOMLEFT"] = "Ícone: ABAIXO-ESQUERDA"
+L["Icon: BOTTOMRIGHT"] = "Ícone: ABAIXO-DIREITA"
+L["Icon: LEFT"] = "Ícone: ESQUERDA"
+L["Icon: RIGHT"] = "Ícone: DIREITA"
+L["Icon: TOP"] = "Ícone: ACIMA"
+L["Icon: TOPLEFT"] = "Ícone: ACIMA-ESQUERDA"
+L["Icon: TOPRIGHT"] = "Ícone: ACIMA-DIREITA"
+L["Icons and Text (Short)"] = true
+L["Icons and Text"] = "Texto e Ícones"
+L["If enabled then it checks if auras are missing instead of being present on the unit."] = true
+L["If enabled then it will require all auras to activate the filter. Otherwise it will only require any one of the auras to activate it."] = true
+L["If enabled then it will require all cooldowns to activate the filter. Otherwise it will only require any one of the cooldowns to activate it."] = true
+L["If enabled then the filter will activate if the unit is casting anything."] = true
+L["If enabled then the filter will activate if the unit is channeling anything."] = true
+L["If enabled then the filter will activate if the unit is not casting anything."] = true
+L["If enabled then the filter will activate if the unit is not channeling anything."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or higher than this value."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or lower than this value."] = true
+L["If enabled then the filter will only activate if the level of the unit matches this value."] = true
+L["If enabled then the filter will only activate if the level of the unit matches your own."] = true
+L["If enabled then the filter will only activate if the unit is casting interruptible spells."] = true
+L["If enabled then the filter will only activate if the unit is casting not interruptible spells."] = true
+L["If enabled then the filter will only activate if the unit is not casting or channeling one of the selected spells."] = true
+L["If enabled then the filter will only activate when you are in combat."] = true
+L["If enabled then the filter will only activate when you are not targeting the unit."] = true
+L["If enabled then the filter will only activate when you are out of combat."] = true
+L["If enabled then the filter will only activate when you are targeting the unit."] = true
+L["If enabled then the filter will only activate when you have a target."] = true
+L["If not set to 0 then override the size of the aura icon to this."] = "Se não definido 0 então sobrescreve o tamanho da aura para este."
+L["If the aura is listed with a number then you need to use that to remove it from the list."] = true
+L["If this list is empty, and if 'Interruptible' is checked, then the filter will activate on any type of cast that can be interrupted."] = true
+L["If this threshold is used then the health of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the health of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the power of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If this threshold is used then the power of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = true
+L["If you have a lot of 3D Portraits active then it will likely have a big impact on your FPS. Disable some portraits if you experience FPS issues."] = true
+L["If you have any plugins supporting this feature installed you can find them in the selection dropdown to the right."] = true
+L["If you unlock actionbars then trying to move a spell might instantly cast it if you cast spells on key press instead of key release."] = true
+L["Ignore UI Scale Popup"] = true
+L["Ignore mouse events."] = "Ignorar eventos do rato (mouse)."
+L["Ignored Items and Search Syntax (Global)"] = true
+L["Ignored Items and Search Syntax (Profile)"] = true
+L["Import Profile"] = true
+L["Importing"] = true
+L["Inactivity Timer"] = true
+L["Index"] = "Índice"
+L["Indicate whether buffs you cast yourself should be separated before or after."] = "Indica se os buffs que lança em si próprio devem ser separados antes ou depois."
+L["InfoPanel Border"] = true
+L["Information Panel"] = true
+L["Inherit Global Fade"] = true
+L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."] = true
+L["Inset"] = "Margem"
+L["Inside Information Panel"] = true
+L["Install"] = "Instalação"
+L["Instance Difficulty"] = true
+L["Instance Type"] = true
+L["Interruptable"] = "Interrompível"
+L["Interruptible"] = "Interrompível"
+L["Invert Colors"] = true
+L["Invert Grouping Order"] = "Inverter a Ordem de Agrupamento"
+L["Invert foreground and background colors."] = true
+L["Is Casting Anything"] = true
+L["Is Channeling Anything"] = true
+L["Is Targeted"] = true
+L["Item Count Font"] = true
+L["Item Count"] = "Contador de Item"
+L["Item Level Threshold"] = true
+L["Item Level"] = true
+L["JustifyH"] = "JustificarH"
+L["Key Down"] = "Tecla pressionada"
+L["Keybind Mode"] = "Modo de Teclas de Atalho"
+L["Keybind Text Position"] = true
+L["Keybind Text X-Offset"] = true
+L["Keybind Text Y-Offset"] = true
+L["Keybind Text"] = "Texto das Teclas de Atalho"
+L["Keyword Alert"] = "Alerta de palavra-chave"
+L["Keywords"] = "Palavras-chave"
+L["LBF Support"] = true
+L["LEVEL_BOSS"] = "Set level to -1 for boss units or set to 0 to disable."
+L["LFD Frame"] = true
+L["LFG Queue"] = true
+L["LFR Frame"] = true
+L["Latency"] = "Latência"
+L["Leatherworking"] = true
+L["Left Only"] = "Somente Esquerda"
+L["Left to Right"] = true
+L["Left"] = "Esquerda"
+L["Limit the number of rows or columns."] = "Limitar o número de linhas ou colunas."
+L["List of words to color in chat if found in a message. If you wish to add multiple words you must seperate the word with a comma. To search for your current name you can use %MYNAME%.\n\nExample:\n%MYNAME%, ElvUI, RBGs, Tank"] = "Lista de palavras a colorir se encontrada numa mensagem. Se desejar adicionar multiplas palavras deverá separa-las com uma vírgula. Para procurar pelo seu nome actual pode usar %MYNAME%.\n\nExemplo:\n%MYNAME%, ElvUI, RBGs, Tank"
+L["Location Text"] = "Texto de Localização"
+L["Lock Positions"] = "Travar Posições"
+L["Log Taints"] = "Capturar Problemas"
+L["Log the main chat frames history. So when you reloadui or log in and out you see the history from your last session."] = "Armazenar o histórico dos quadros principais do bate-papo. Para que possa ver o histórico de sua última sessão ao relogar ou conectar e desconectar."
+L["Login Message"] = "Mensagem de Entrada"
+L["Loot Frames"] = "Saques"
+L["Loot Roll"] = "Disputa de Saques"
+L["Losing Threat"] = true
+L["Low Health Threshold"] = "Limiar de Vida Baixa"
+L["Low Threat"] = true
+L["Low Threshold"] = "Baixo Limiar"
+L["Lower numbers mean a higher priority. Filters are processed in order from 1 to 100."] = true
+L["MM:SS Threshold"] = true
+L["MM:SS"] = true
+L["Macro Text"] = "Texto das Macros"
+L["Magic Effect"] = true
+L["Main Tanks / Main Assist"] = "Tanque Principal / Assistente Princial"
+L["Main backdrop color of the UI."] = "Cor básica para fundo da interface."
+L["Main border color of the UI."] = true
+L["Main statusbar texture."] = "Textura princiapal da barra de estado."
+L["Make textures transparent."] = "Deixar as texturas transparentes."
+L["Make the unitframe glow yellow when it is below this percent of health, it will glow red when the health value is half of this value."] = true
+L["Make the world map smaller."] = true
+L["Map Opacity When Moving"] = true
+L["Maps"] = true
+L["Match Frame Width"] = "Igualar comprimento do quadro"
+L["Match Player Level"] = true
+L["Max Alpha"] = true
+L["Max Bars"] = true
+L["Max Lines"] = true
+L["Max Overflow"] = true
+L["Max Wraps"] = "Enrolamentos Máximos"
+L["Max amount of overflow allowed to extend past the end of the health bar."] = true
+L["Maximum Duration"] = true
+L["Maximum Level"] = true
+L["Maximum Time Left"] = true
+L["Media"] = "Mídia"
+L["Method to sort by."] = true
+L["Middle Click - Set Focus"] = "Clique Meio - Defenir foco"
+L["Middle clicking the unit frame will cause your focus to match the unit."] = "Clicar com o botão do meio no quadro da unidade fará o foco ser defenido para esta unidade."
+L["Middle"] = true
+L["Min Alpha"] = true
+L["Minimap Mouseover"] = "Passar com o rato(mouse) sobre o minimapa"
+L["Minimap Panels"] = "Painéis do Minimapa"
+L["Minimum Duration"] = true
+L["Minimum Level"] = true
+L["Minimum Time Left"] = true
+L["Mining"] = true
+L["Minutes"] = "Minutos"
+L["Mirror Timers"] = true
+L["Misc Frames"] = "Diversos"
+L["Missing"] = true
+L["Modulating Blend"] = true
+L["Module Control"] = true
+L["Module Copy"] = true
+L["Module Reset"] = true
+L["Money Format"] = true
+L["Mouse Over"] = "Com o Rato (Mouse) por cima"
+L["Mouseover Glow"] = true
+L["Mouseover Highlight"] = true
+L["Mouseover"] = "Mouseover"
+L["Multi-Monitor Support"] = true
+L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."] = "Multiplicar a altura ou comprimento do fundo por este valor. Muito útil se desejar ter mais que uma barra por trás de um fundo."
+L["NAMEPLATE_FRAMELEVEL_DESC"] = true
+L["NPC IDs"] = true
+L["Name Color"] = true
+L["Name Colored Glow"] = true
+L["Name Font"] = "Fonte de Nomes"
+L["Name Only"] = true
+L["Name"] = "Nome"
+L["NamePlate Style Filters"] = true
+L["NamePlates"] = "Placas de Identificação"
+L["Nameplate"] = true
+L["Neutral"] = "Neutro"
+L["Never Hide"] = "Nunca Esconder"
+L["No Alert In Combat"] = true
+L["No Duration"] = true
+L["No Sorting"] = "Não organizado"
+L["Non-Interruptable"] = "Não interrompível"
+L["Non-Target Alpha"] = true
+L["Not Casting Anything"] = true
+L["Not Channeling Anything"] = true
+L["Not Spell"] = true
+L["Not Targeted"] = true
+L["Not Usable"] = true
+L["Not valid spell id"] = "Identificação (id) do feitiço não é valida"
+L["Num Rows"] = "Número de linhas"
+L["Number of Groups"] = "Número de Grupos"
+L["Number of messages you scroll for each step."] = true
+L["Number of repeat characters while in combat before the chat editbox is automatically closed. Set to 0 to disable."] = true
+L["Number of time in seconds to scroll down to the bottom of the chat window if you are not scrolled down completely."] = "Tempo, em segundos, para rolar o bate-papo até ao fim caso nao tenha rolado completamente."
+L["Objective Frame Height"] = true
+L["Off Cooldown"] = true
+L["Offset of the powerbar to the healthbar, set to 0 to disable."] = "A distância entre barra de poder e a barra de vida, definir 0 para desactivar."
+L["Offset position for text."] = "Deslocamento da posição do texto"
+L["Offset"] = "Distância"
+L["On Cooldown"] = true
+L["Only Match SpellID"] = true
+L["Only show when the unit is not in range."] = true
+L["Only show when you are mousing over a frame."] = true
+L["Other Filter"] = true
+L["Other's First"] = "De outros primeiro"
+L["Others"] = "Outros"
+L["Out of Power"] = "Sem Poder"
+L["Out of Range"] = "Fora de Alcance"
+L["Over Health Threshold"] = true
+L["Over Power Threshold"] = true
+L["Overlay Alpha"] = true
+L["Overlay"] = "Sobrepor"
+L["Overnuking"] = true
+L["Override any custom visibility setting in certain situations, EX: Only show groups 1 and 2 inside a 10 man instance."] = "Sobrescrever qualquer visibilidade personalizada em certas situações, Ex: Mostrar apenas grupo 1 e 2 dentro de uma instância de 10 pessoas."
+L["Override the default class color setting."] = "Sobrescreve a configuração de cor de classe padrão."
+L["Owners Name"] = true
+L["PVP Trinket"] = "Berloque de JXJ"
+L["Panel Backdrop"] = "Fundo do Painel"
+L["Panel Height"] = "Altura do Painel"
+L["Panel Texture (Left)"] = "Textura do Painel (Esquerdo)"
+L["Panel Texture (Right)"] = "Textura do Painel (Direito)"
+L["Panel Transparency"] = "Transparência do Painel"
+L["Panel Width (Bags)"] = "Largura do Painel (Bolsas)"
+L["Panel Width (Bank)"] = "Largura do Painel (Banco)"
+L["Panel Width"] = "Comprimento do Painel"
+L["Panels"] = "Painéis"
+L["Parent"] = true
+L["Party / Raid"] = true
+L["Party Only"] = true
+L["Party Pets"] = "Ajudantes do Grupo"
+L["Party Targets"] = "Alvos do Grupo"
+L["Per Row"] = "Por Linha"
+L["Percent"] = "Porcentagem"
+L["Personal"] = "Pessoal"
+L["Pet Name"] = true
+L["Pet"] = true
+L["PetTarget"] = true
+L["Petition Frame"] = "Petição"
+L["Pick Up Action Key"] = true
+L["Player Frame Aura Bars"] = true
+L["Player Health"] = true
+L["Player Out of Combat"] = true
+L["Player Target"] = true
+L["Player Titles"] = "Títulos dos Jogadores"
+L["Player in Combat"] = true
+L["Player"] = "Player"
+L["Plugin"] = true
+L["Poison Effect"] = true
+L["Portrait"] = "Retrato"
+L["Position Buffs on Debuffs"] = true
+L["Position Debuffs on Buffs"] = true
+L["Position of the Chat EditBox, if datatexts are disabled this will be forced to be above chat."] = "A posição da caixa de edição do bate-papo, será forçada para cima do bate-papo se os textos informativos estiverem desativados."
+L["Position"] = "Posição"
+L["Power Threshold"] = true
+L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."] = "Em PNJs o texto de poder não será mostrado, em adição o texto de nome será reposicionado para o ponto de fixação do texto de poder."
+L["Power"] = "Poder"
+L["Powers"] = "Poderes"
+L["Prevent the same messages from displaying in chat more than once within this set amount of seconds, set to zero to disable."] = "Prevenir que as mesmas mensagens sejam exibidas no bate-papo mais que uma vez dentro desta quantidade de segundos, definir 0 para desativar."
+L["Primary Texture"] = "Textura principal"
+L["Priority"] = "prioridade"
+L["Private (Character Settings)"] = true
+L["Profession Bags"] = true
+L["Profile Name"] = true
+L["Profile Specific"] = true
+L["Profile imported successfully!"] = true
+L["Profile"] = true
+L["Progress Bar"] = true
+L["Puts coordinates on the world map."] = true
+L["PvP Frames"] = "JxJ"
+L["PvP Icon"] = true
+L["PvP Queue"] = true
+L["PvP Text"] = true
+L["Quest Frames"] = "Missões"
+L["Quest Starter"] = true
+L["Quiver"] = true
+L["RAID_CONTROL"] = "Controle de raides"
+L["RL / ML Icons"] = true
+L["Raid Difficulty"] = true
+L["Raid Frame"] = "Quadro de Raide"
+L["Raid Icon"] = "Icone de Raide"
+L["Raid Only"] = true
+L["Raid Pet"] = true
+L["Raid-40"] = true
+L["Raid-Wide Sorting"] = true
+L["RaidDebuff Indicator"] = "Indicador das Penalidades da Raide"
+L["Range"] = true
+L["Rapidly update the health, uses more memory and cpu. Only recommended for healing."] = "Atualizar rapidamente a vida, usa mais memória e CPU. Apenas recomendado para curandeiros."
+L["Reaction Castbars"] = true
+L["Reaction Colors"] = true
+L["Reaction Type"] = true
+L["Reactions"] = "Reações"
+L["Ready Check Icon"] = true
+L["Realm Time"] = true
+L["Remaining / Max"] = true
+L["Remaining Time"] = true
+L["Remaining"] = "Restante"
+L["Reminder"] = true
+L["Remove Backdrop"] = "Remover Fundo"
+L["Remove Name"] = true
+L["Remove Spell ID or Name"] = true
+L["Remove Spell"] = true
+L["Remove SpellID"] = "Remover SpellID"
+L["Remove a Name from the list."] = true
+L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."] = true
+L["Remove a spell from the filter."] = "Remover um feitiço do filtro."
+L["Replace Blizzard Fonts"] = true
+L["Replaces the default Blizzard fonts on various panels and frames with the fonts chosen in the Media section of the ElvUI Options. NOTE: Any font that inherits from the fonts ElvUI usually replaces will be affected as well if you disable this. Enabled by default."] = true
+L["Reposition Window"] = true
+L["Require All"] = true
+L["Require Target"] = true
+L["Require holding the Alt key down to move cursor or cycle through messages in the editbox."] = true
+L["Reset Anchors"] = "Restaurar Fixadores"
+L["Reset Aura Filters"] = true
+L["Reset Editbox History"] = true
+L["Reset Filter"] = true
+L["Reset History"] = true
+L["Reset Priority"] = true
+L["Reset Zoom"] = true
+L["Reset all frames to their original positions."] = "Restaurar todos os quadros para as posições originais"
+L["Reset filter priority to the default state."] = true
+L["Reset the size and position of this frame."] = true
+L["Rest Icon"] = "ìcone de descansar"
+L["Restore Bar"] = "Restaurar Barra"
+L["Restore Defaults"] = "Restaurar ao Padrão"
+L["Restore the actionbars default settings"] = "Restaurar as configurações padrões das barras de ações"
+L["Resurrect Icon"] = true
+L["Return filter to its default state."] = true
+L["Reverse Bag Slots"] = true
+L["Reverse Cooldown"] = true
+L["Reverse Style"] = true
+L["Reverse Toggle will enable Cooldown Text on this module when the global setting is disabled and disable them when the global setting is enabled."] = true
+L["Reverse Toggle"] = true
+L["Right Only"] = "Somente Direita"
+L["Right Panel Height"] = true
+L["Right Panel Width"] = true
+L["Right to Left"] = true
+L["Right"] = "Direita"
+L["RightClick Self-Cast"] = true
+L["Role Icon"] = "Ícone do papel"
+L["Run the installation process."] = "Execute o processo de instalação."
+L["Sanctuary"] = true
+L["Scale of the nameplate that is targetted."] = true
+L["Scale"] = true
+L["Scroll Interval"] = "Intervalo de Rolar"
+L["Scroll Messages"] = true
+L["Search Syntax"] = true
+L["Search for a spell name inside of a filter."] = true
+L["Secondary Texture"] = "Textura secundária"
+L["Seconds remaining on the aura duration before the bar starts moving. Set to 0 to disable."] = true
+L["Seconds"] = "Segundos"
+L["Selected Text Color"] = true
+L["Selector Color"] = true
+L["Selector Style"] = true
+L["Securely Tanking"] = true
+L["Select Filter"] = "Seleccionar filtros"
+L["Select Spell"] = "Seleccionar feitiço"
+L["Select a profile to copy from/to."] = true
+L["Select a unit to copy settings from."] = "Selecione uma unidade para que se copiem as definições!"
+L["Select the display method of the portrait."] = "Seleciona o método de exibição do retrato."
+L["Sell Interval"] = true
+L["Send ADDON_ACTION_BLOCKED errors to the Lua Error frame. These errors are less important in most cases and will not effect your game performance. Also a lot of these errors cannot be fixed. Please only report these errors if you notice a Defect in gameplay."] = "Mandar os erros de AÇÃO do ADDON BLOQUEADA para o quadro de erros de Lua. Estes erros são, na maioria das vezes, pouco importantes e não irão afetar o seu desempenho de jogo. Muitos destes erros nao podem ser reparados. Por favor denuncie estes erros apenas se notar problemas no desempenho do jogo."
+L["Sends your current profile to your target."] = "Envia seu perfil atual para seu alvo."
+L["Sends your filter settings to your target."] = "Envia as configurações de filtro para seu alvo."
+L["Separate Panel Sizes"] = true
+L["Seperate"] = "Separar"
+L["Set Settings to Default"] = true
+L["Set the alpha level of portrait when frame is overlayed."] = true
+L["Set the filter type. Blacklist will hide any auras in the list and show all others. Whitelist will show any auras in the filter and hide all others."] = true
+L["Set the font outline."] = "Definir o contorno de fonte."
+L["Set the font size for everything in UI. Note: This doesn't effect somethings that have their own seperate options (UnitFrame Font, Datatext Font, ect..)"] = "Define o tamanho da fonte para toda a Interface. Nota: Isto nao afeta coisas que tenham suas prórpias opções de fonte (Quadros de Unidade, Textos Informativos, etc..)"
+L["Set the font size for unitframes."] = "Define o tamanho da fonte para o quadro de unidades."
+L["Set the order that the group will sort."] = "Define a ordem em que o grupo vai se organizar."
+L["Set the orientation of the UnitFrame."] = true
+L["Set the priority order of the spell, please note that prioritys are only used for the raid debuff module, not the standard buff/debuff module. If you want to disable set to zero."] = "Define a ordem prioritária dos feitiços, por favor note que prioridades só são usadas o modo de Penalidades de Raide, não para o modo normal de bônus/penalidades."
+L["Set the size of the individual auras."] = "Definir o tamanho das auras individuais."
+L["Set the size of your bag buttons."] = "Define o tamanho dos botões das Bolsas"
+L["Set the type of auras to show when a unit is a foe."] = "Define o tipo de auras a serem mostradas quando a unidade é um inimigo."
+L["Set the type of auras to show when a unit is friendly."] = "Define o tipo de auras a serem mostradas quando a unidade é aliada."
+L["Set to either stack nameplates vertically or allow them to overlap."] = true
+L["Sets the font instance's horizontal text alignment style."] = "Define o estilo de alinhamento horizontal da instância da fonte."
+L["Share Current Profile"] = "Compartilhar Perfil Atual"
+L["Share Filters"] = "Compartilhar Filtros"
+L["Short (Whole Numbers)"] = true
+L["Short Channels"] = "Abreviar os Canáis"
+L["Shortcut to 'Filters' section of the config."] = true
+L["Shortcut to global filters."] = true
+L["Shortcuts"] = true
+L["Shorten the channel names in chat."] = "Abreviar o nome dos canáis no bate-papo."
+L["Should tooltip be anchored to mouse cursor"] = true
+L["Show Aura From Other Players"] = "Mostrar Auras de outros Jogadores"
+L["Show Auras"] = "Mostrar Auras"
+L["Show Bind on Equip/Use Text"] = true
+L["Show Both"] = "Mostrar Ambos"
+L["Show Coins"] = true
+L["Show Dispellable Debuffs"] = true
+L["Show Empty Buttons"] = true
+L["Show For DPS"] = true
+L["Show For Healers"] = true
+L["Show For Tanks"] = true
+L["Show Icon"] = true
+L["Show Junk Icon"] = true
+L["Show Quality Color"] = true
+L["Show Quest Icon"] = true
+L["Show When Not Active"] = "Mostrar Quando Não Ativo"
+L["Show an incoming heal prediction bar on the unitframe. Also display a slightly different colored bar for incoming overheals."] = "Mostra a barra de predicção de cura no quadro de unidade. Também exibe uma barra com uma cor ligeiramente diferente para a predicção de sobrecura."
+L["Show the castbar icon desaturated if a spell is not interruptible."] = true
+L["Show/Hide Test Frame"] = true
+L["Side Arrows"] = true
+L["Size Override"] = "Sobrescrever Tamanho"
+L["Size and Positions"] = true
+L["Size of the indicator icon."] = "Tamanho do ícone indicador."
+L["Size"] = "Tamanho"
+L["Skin Backdrop (No Borders)"] = true
+L["Skin Backdrop"] = "Redesenhar o Fundo"
+L["Skin the blizzard chat bubbles."] = "Redesenhar os balões de conversação da Blizzard"
+L["Skins"] = "Aparências"
+L["Small Panels"] = true
+L["Smaller World Map"] = true
+L["Smart Aura Position"] = true
+L["Smart Raid Filter"] = "Filtro de Raide inteligente"
+L["Smart"] = true
+L["Smooth Bars"] = "Barras suaves"
+L["Smooth"] = true
+L["Smoothing Amount"] = true
+L["Socket Frame"] = "Engaste"
+L["Sort By"] = true
+L["Sort Direction"] = "Direção de organização"
+L["Sort Inverted"] = "Oganizar Invertido"
+L["Sort Method"] = "Método de organização"
+L["Soul Bag"] = true
+L["Spaced"] = "Espaçado"
+L["Spacing"] = true
+L["Spam Interval"] = "Intervalo de Spam"
+L["Spark"] = "Faísca"
+L["Spell/Item IDs"] = "IDs de Feitiços/Itens"
+L["Split"] = true
+L["Stable"] = "Estábulo"
+L["Stack Counter"] = true
+L["Stack Text Position"] = true
+L["Stack Text X-Offset"] = true
+L["Stack Text Y-Offset"] = true
+L["Stack Threshold"] = true
+L["Start Near Center"] = "Começar perto do Centro"
+L["StatusBar Texture"] = "Textura da barra de estado"
+L["Statusbar Fill Orientation"] = true
+L["Statusbar"] = true
+L["Sticky Chat"] = "Lembrar Canal"
+L["Strata and Level"] = true
+L["Style Filter"] = true
+L["Style"] = "Estilo"
+L["TALENTS"] = "Talentos"
+L["Tab Font Outline"] = "Contorno da fonte da Guia"
+L["Tab Font Size"] = "Tamanho da fonte da Guia"
+L["Tab Font"] = "Fonte da Guia"
+L["Tab Panel Transparency"] = "Transparência do painel da Guia"
+L["Tab Panel"] = "Painel da Guia"
+L["Tab Selector"] = true
+L["Tabard Frame"] = "Tabardo"
+L["Table"] = true
+L["Tank Target"] = "Alvo do Tanque"
+L["Tank"] = "Tanque"
+L["Tapped"] = "Reservado"
+L["Target Indicator Color"] = true
+L["Target Info"] = true
+L["Target On Mouse-Down"] = "Selecionar ao Pressionar o Mouse"
+L["Target Scale"] = true
+L["Target units on mouse down rather than mouse up. \n\n|cffFF0000Warning: If you are using the addon 'Clique' you may have to adjust your clique settings when changing this."] = "Seleciona unidades ao pressionar o mouse em ves de ao soltar. \n\n|cffFF0000Atenção: Se você estiver usando o addon 'Clique' poderá ter que ajustá-lo quando alterar essa opção."
+L["Target/Low Health Indicator"] = true
+L["TargetTarget"] = true
+L["TargetTargetTarget"] = true
+L["Targeted Glow"] = true
+L["Targeting"] = true
+L["Testing:"] = "Testar:"
+L["Text Fade"] = true
+L["Text Color"] = "Cor do Texto"
+L["Text Font Size"] = true
+L["Text Format"] = "Formato de texto"
+L["Text Position"] = "Posição do Texto"
+L["Text Threshold"] = "Limiar do Texto"
+L["Text Toggle On NPC"] = "Texto ligado no PNJ"
+L["Text xOffset"] = "Distãncia X do Texto"
+L["Text yOffset"] = "Distância Y do Texto"
+L["Text"] = "Texto"
+L["Texture"] = true
+L["Textured Icon"] = "Ícone Texturizado"
+L["Textures"] = "Texturas"
+L["The Portrait will overlay the Healthbar. This will be automatically happen if the Frame Orientation is set to Middle."] = true
+L["The Thin Border Theme option will change the overall apperance of your UI. Using Thin Border Theme is a slight performance increase over the traditional layout."] = true
+L["The amount of buttons to display per row."] = "Quantidade de botões a serem exibidos por linha."
+L["The amount of buttons to display."] = "Quantidade de botões a serem exibidos"
+L["The button you must hold down in order to drag an ability to another action button."] = "Botão que deve ser pressionado para permitir o arrastar uma habilidade para outro botão de acção"
+L["The debuff needs to reach this amount of stacks before it is shown. Set to 0 to always show the debuff."] = true
+L["The direction that the bag frames be (Horizontal or Vertical)."] = "Direcção em que os quadros das bolsas são (Horizontal ou Vertical)."
+L["The direction that the bag frames will grow from the anchor."] = "Direcção para qual as barras crescerão a partir do seu Fixador."
+L["The direction the auras will grow and then the direction they will grow after they reach the wrap after limit."] = true
+L["The display format of the currency icons that get displayed below the main bag. (You have to be watching a currency for this to display)"] = "O formato de exibição dos ícones de moeda exibidos abaixo da bolsa principal. (Para isto ser exibido é necessário que selecione Mostrar na Mochila na moeda desejada na aba Moeda dentro do Quadro do Personagem)."
+L["The display format of the money text that is shown at the top of the main bag."] = true
+L["The display format of the money text that is shown in the gold datatext and its tooltip."] = true
+L["The first button anchors itself to this point on the bar."] = "O primeiro botão fixa-se a este ponto da barra"
+L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."] = "A macro seguinte tem de ser verdadeira para que o grupo seja mostrado, em adição a qualquer outro filtro que possa já estar definido."
+L["The font that appears on the text above players heads. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "A fonte do texto que aparece sobre a cabeça dos jogadores. |cffFF0000ATENÇÃO: Para esta alteração fazer efeito é necessário que o jogo seja reiniciado ou relogado.|r"
+L["The font that combat text will use. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "Fonte que o texto de combate usará. |cffFF0000AVISO: Para que as mudanças sejam efetuadas é necessário reiniciar ou relogar o jogo."
+L["The font that the core of the UI will use."] = "Fonte que o núcleo da interface usará."
+L["The font that the unitframes will use."] = "A fonte que os quadros de unidades usarão."
+L["The frame is not shown unless you mouse over the frame."] = "A não ser que passe com o rato (mouse) por cima do quadro, este não será mostrado."
+L["The initial group will start near the center and grow out."] = "O grupo inicial começara perto do centro e crescerá para fora."
+L["The minimum item level required for it to be shown."] = true
+L["The name you have selected is already in use by another element."] = "O nome que escolheu já está a ser usado noutro elemento."
+L["The object you want to attach to."] = "O objeto ao qual você quer anexar."
+L["The size of the action buttons."] = "Tamanho dos botões de ação."
+L["The size of the individual buttons on the bag frame."] = "O tamanho individual de botões dentro do quadro das bolsas."
+L["The size of the individual buttons on the bank frame."] = "O tamanho individual de botões dentro do quadro do banco."
+L["The spacing between buttons."] = "Espaçamento entre botões."
+L["The spacing between the backdrop and the buttons."] = true
+L["The texture that will be used mainly for statusbars."] = "Textura que será usada principalmente para a barras de estado."
+L["The unit prefixes you want to use when values are shortened in ElvUI. This is mostly used on UnitFrames."] = true
+L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."] = true
+L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."] = true
+L["Thin Border Theme"] = true
+L["Thin Borders"] = true
+L["This dictates the size of the icon when it is not attached to the castbar."] = true
+L["This feature will allow you to transfer settings to other characters."] = "Este recurso permite enviar sus configurações a outros personagens."
+L["This is for Customized Icons in your Interface/Icons folder."] = true
+L["This opens the UnitFrames Color settings. These settings affect all unitframes."] = true
+L["This option allows the overlay to span the whole health, including the background."] = true
+L["This section will allow you to copy settings to a select module from or to a different profile."] = true
+L["This section will help reset specfic settings back to default."] = true
+L["This selects the Chat Frame to use as the output of ElvUI messages."] = true
+L["This setting controls the size of text in item comparison tooltips."] = true
+L["This setting will be updated upon changing stances."] = "Essa configuração atualizará ao trocar posturas."
+L["This texture will get used on objects like chat windows and dropdown menus."] = "Esta textura será usada em objetos como janelas de bate-papo e menus de suspensão."
+L["This will override the global cooldown settings."] = true
+L["This will prevent the UI Scale Popup from being shown when changing the game window size."] = true
+L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."] = true
+L["Threat Display Mode"] = "Modo de Exebição de Ameaça"
+L["Threat Health"] = true
+L["Threat Power"] = true
+L["Threat"] = "Agro"
+L["Threshold (in minutes) before text is shown in the HH:MM format. Set to -1 to never change to this format."] = true
+L["Threshold (in seconds) before text is shown in the MM:SS format. Set to -1 to never change to this format."] = true
+L["Threshold before text goes into decimal form. Set to -1 to disable decimals."] = true
+L["Threshold before text turns red and is in decimal form. Set to -1 for it to never turn red"] = "Limiar antes do texto se tornar vermelho e em forma décimal. Definir -1 para nunca se tornar vermelho"
+L["Threshold before the icon will fade out and back in. Set to -1 to disable."] = true
+L["Ticks"] = "Ticks"
+L["Time Format"] = true
+L["Time Indicator Colors"] = true
+L["Time Remaining Reverse"] = "Tempo Remanescente Reverso"
+L["Time Remaining"] = "Tempo Remanescente"
+L["Time To Hold"] = true
+L["Time xOffset"] = true
+L["Time yOffset"] = true
+L["Time"] = "Tempo"
+L["Timestamp Color"] = true
+L["Toggle Anchors"] = "Mostrar/Ocultar Fixadores"
+L["Toggle Off While In Combat"] = true
+L["Toggle On While In Combat"] = true
+L["Toggle Tutorials"] = "Ativar Tutoriais"
+L["Toggle showing of the left and right chat panels."] = "Mostrar/Ocultar os painéis de conversação da esquerda e direita."
+L["Toggle the chat tab panel backdrop."] = "Mostrar/ocultar o fundo da guia do bate-papo."
+L["Toggles the display of the actionbars backdrop."] = "Mostra/Oculta o fundo das barras de acção"
+L["Tooltip Font Settings"] = true
+L["Top Arrow"] = true
+L["Top Left"] = true
+L["Top Panel"] = "Painel Superior"
+L["Top Right"] = true
+L["Top to Bottom"] = "De cima para baixo"
+L["Top"] = true
+L["TopLeftMiniPanel"] = "Minimap TopLeft (Inside)"
+L["TopMiniPanel"] = "Minimap Top (Inside)"
+L["TopRightMiniPanel"] = "Minimap TopRight (Inside)"
+L["Totem"] = true
+L["Trainer Frame"] = "Instrutores"
+L["Transparency level when not in combat, no target exists, full health, not casting, and no focus target exists."] = true
+L["Transparent Backdrops"] = true
+L["Transparent Buttons"] = true
+L["Transparent"] = "Transparente"
+L["Triggers"] = true
+L["Turtle Color"] = "Cor para Tartaruga"
+L["Tutorial Frame"] = true
+L["URL Links"] = "Links URL"
+L["Under Health Threshold"] = true
+L["Under Power Threshold"] = true
+L["Uniform Threshold"] = true
+L["Unique Units"] = true
+L["Unit Prefix Style"] = true
+L["Unit Target"] = true
+L["Unit Type"] = true
+L["UnitFrames"] = "Quadro de Unidades"
+L["Unlock various elements of the UI to be repositioned."] = "Destravar vários elementos da interface para serem reposicionados."
+L["Up"] = "Acima"
+L["Usable"] = true
+L["Use Alt Key"] = true
+L["Use Class Color"] = true
+L["Use Custom Level"] = true
+L["Use Custom Strata"] = true
+L["Use Dead Backdrop"] = true
+L["Use Default"] = "usar Padrão"
+L["Use Indicator Color"] = true
+L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."] = true
+L["Use Target Scale"] = true
+L["Use Threat Color"] = true
+L["Use class color for the names of players when they are mentioned."] = true
+L["Use coin icons instead of colored text."] = true
+L["Use drag and drop to rearrange filter priority or right click to remove a filter."] = true
+L["Use the Name Color of the unit for the Name Glow."] = true
+L["Use the custom backdrop color instead of a multiple of the main color."] = "Usar a cor de fundo da vida personalizada em vez de um multiplo da cor de vida principal."
+L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."] = true
+L["Use thin borders on certain unitframe elements."] = true
+L["Use this backdrop color for units that are dead or ghosts."] = true
+L["Used as RaidDebuff Indicator"] = true
+L["Value Color"] = "Cor dos Valores"
+L["Value must be a number"] = "O valor tem de ser um número"
+L["Vehicle Seat Indicator Size"] = true
+L["Vehicle"] = true
+L["Vendor Gray Detailed Report"] = true
+L["Vendor Grays"] = "Vender Itens Cinzentos"
+L["Version"] = "Versão"
+L["Vertical Fill Direction"] = true
+L["Vertical Spacing"] = "Espaçamento Vertical"
+L["Vertical"] = "Vertical"
+L["Visibility State"] = "Estado de Visibilidade"
+L["Visibility"] = "Visibilidade"
+L["Watch Frame"] = true
+L["What point to anchor to the frame you set to attach to."] = "Qual é o ponto a fixar ao quadro que você definiu para ser anexado."
+L["What to attach the buff anchor frame to."] = "Ao que anexar o quadro fixador dos Bônus."
+L["What to attach the debuff anchor frame to."] = "Ao que anexar o quadro fixador das Penalidades."
+L["When enabled active buff icons will light up instead of becoming darker, while inactive buff icons will become darker instead of being lit up."] = true
+L["When enabled it will only show spells that were added to the filter using a spell ID and not a name."] = true
+L["When in a raid group display if anyone in your raid is targeting the current tooltip unit."] = "Exibe se alguém em sua raide tem como alvo a unidade da tooltip."
+L["When inside a battleground display personal scoreboard information on the main datatext bars."] = "Exibir informação do placar pessoal nos textos informativos principais quando dentro de um Campo de Batalha"
+L["When opening the Chat Editbox to type a message having this option set means it will retain the last channel you spoke in. If this option is turned off opening the Chat Editbox should always default to the SAY channel."] = "Ter esta opção ativada significa que sempre que escrever algo será usado o último canal no qual escreveu. Se a opção estiver desativada escreverá sempre no canal padrão DIZER"
+L["When true, the header includes the player when not in a raid."] = "Quando verdade, o cabeçalho inclui o jogador quando não está em Raide."
+L["When you go AFK display the AFK screen."] = true
+L["Whitelist"] = "Lista Branca"
+L["Width Multiplier"] = "Multiplicador de Comprimento"
+L["Width"] = "Comprimento"
+L["Will attempt to sell another item in set interval after previous one was sold."] = true
+L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."] = true
+L["Word Wrap"] = true
+L["World Map Coordinates"] = true
+L["World State Frame"] = true
+L["Wrap After"] = "Enrolar depois"
+L["X-Offset"] = "Distância X"
+L["Y-Offset"] = "Distância Y"
+L["You do not need to use 'Is Casting Anything' or 'Is Channeling Anything' for these spells to trigger."] = true
+L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."] = "Você não pode remover um feitiço de um filtro padrão que não seja um feitiço personalizado. Em vez disso definindo feitiço para falso."
+L["You must be targeting a player."] = "É necessário ter um jogador como alvo."
+L["You need to hold this modifier down in order to blacklist an aura by right-clicking the icon. Set to None to disable the blacklist functionality."] = true
+L["Your Auras First"] = "Suas auras primeiro"
+L["xOffset"] = "Distância X"
+L["yOffset"] = "Distância Y"
+
+L["ACTIONBARS_DESC"] = "Modify the actionbar settings."
+L["AURAS_DESC"] = "Configurar os ícones das auras que aparecem perto do minimapa."
+L["BAGS_DESC"] = "Ajustar definições das bolsas para a ElvUI."
+L["CHAT_DESC"] = "Adjustar definições do bate-papo para o ElvUI."
+L["COOLDOWN_DESC"] = "Adjust Cooldown Settings."
+L["DATATEXT_DESC"] = "Configurar a exibição no ecrã (monitor) dos textos de informação."
+L["ELVUI_DESC"] = "A ElvUI é um Addon completo de substituição da interface original do World of Warcraft."
+L["NAMEPLATE_DESC"] = "Modificar as definições das Placas de Identificação."
+L["PANEL_DESC"] = "Ajustar o tamanho dos painéis da esquerda e direita, isto irá afetar suas bolsas e bate-papo."
+L["SKINS_DESC"] = "Ajustar definições de Aparências."
+L["TOGGLESKIN_DESC"] = "Ativa/Desativa a aparência deste quadro."
+L["TOOLTIP_DESC"] = "Opções de configuração para a Tooltip."
+L["UNITFRAME_DESC"] = "Modify the unitframe settings."
+L["SEARCH_SYNTAX_DESC"] = [=[With the new addition of LibItemSearch, you now have access to much more advanced item searches. The following is a documentation of the search syntax. See the full explanation at: https://github.com/Jaliborc/LibItemSearch-1.2/wiki/Search-Syntax.
+
+Specific Searching:
+ • q:[quality] or quality:[quality]. For instance, q:epic will find all epic items.
+ • l:[level], lvl:[level] or level:[level]. For example, l:30 will find all items with level 30.
+ • t:[search], type:[search] or slot:[search]. For instance, t:weapon will find all weapons.
+ • n:[name] or name:[name]. For instance, typing n:muffins will find all items with names containing "muffins".
+ • s:[set] or set:[set]. For example, s:fire will find all items in equipment sets you have with names that start with fire.
+ • r:[level], reg:[level], rl:[level], regl:[level] or reqlvl:[level]. For example, reqlvl:30 will find all items that require level 30.
+ • tt:[search], tip:[search] or tooltip:[search]. For instance, tt:binds will find all items that can be bound to account, on equip, or on pickup.
+
+
+Search Operators:
+ • ! : Negates a search. For example, !q:epic will find all items that are NOT epic.
+ • | : Joins two searches. Typing q:epic | t:weapon will find all items that are either epic OR weapons.
+ • & : Intersects two searches. For instance, q:epic & t:weapon will find all items that are epic AND weapons
+ • >, <, <=, => : Performs comparisons on numerical searches. For example, typing lvl: >30 will find all items with level HIGHER than 30.
+
+
+The following search keywords can also be used:
+ • soulbound, bound, bop : Bind on pickup items.
+ • bou : Bind on use items.
+ • boe : Bind on equip items.
+ • boa : Bind on account items.
+ • quest : Quest bound items.]=]
+
+L["TEXT_FORMAT_DESC"] = [=[Fornece uma sting para mudar o formato do texto.
+
+Examples:
+[namecolor][name] [difficultycolor][smartlevel] [shortclassification]
+[healthcolor][health:current-max]
+[powercolor][power:current]
+
+Formatos de Vida / Poder:
+'current' - Quantidade Actual
+'percent' - Quantidade de Percentagem
+'current-max' - Quantidade actual seguida pela quantidade máxima, será exibida apenas a máxima se a actual for igual à máxima
+'current-percent' - Quantidade actual seguida pela quantidade em percentagem, será exibida apenas a máxima se a actual for igual à máxima
+'current-max-percent' - Quantidade actual, quantidade máxima seguida por quantidade em percentagem, será exibida apenas a máxima se a actual for igual à máxima
+'deficit' - Exibir o valor em falta, nao será exibido nada se não houver nada em falta
+
+Formato de Nomes:
+'name:short' - Nome restringido a 10 caracteres
+'name:medium' - Nome restringido a 15 caracteres
+'name:long' - Nome restringido a 20 caracteres
+
+Para desactivar deixe o espaço em branco, se precisar de mais informações visite o site https://www.tukui.org/forum/viewtopic.php?t=6]=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to page differently.
+ Example: '[combat] 2;']=] ] = [=[Isto funciona como uma macro, você pode executar várias situações para que a barra de ação pagine de forma diferente.
+ Exemplo: '[combat] 2;']=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to show/hide differently.
+ Example: '[combat] show;hide']=] ] = [=[Isto funciona como uma macro, você pode executar várias situações para mostrar/ocultar a barra de ação de forma diferente.
+ Exemplo: '[combat] show;hide']=]
+
+L[ [=[Specify a filename located inside the World of Warcraft directory. Textures folder that you wish to have set as a panel background.
+
+Please Note:
+-The image size recommended is 256x128
+-You must do a complete game restart after adding a file to the folder.
+-The file type must be tga format.
+
+Example: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Or for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here.]=] ] = [=[Especificar o nome de um ficheiro (arquivo) localizado na diretório do WoW. Ficheiros de textura que deseje ter como fundo dos painéis.
+
+Atenção:
+-O tamanho de imagem recomendado é 256x128
+-Deve reiniciar o jogo completamente depois de adicionar um ficheiro à pasta.
+-O ficheiro tem de ser em formato tga.
+
+Example: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Para a maioria dos usuários seria mais fácil simplesmente copiar o ficheiro tga na pasta do WoW e depois escrever o nome dele aqui.]=]
+
+-- Global Strings
+L["ACHIEVEMENTS"] = "Conquistas"
+L["ALT_KEY_TEXT"] = "ALT"
+L["ARENA"] = "Arena"
+L["AUCTIONS"] = "Leilões"
+L["BAGSLOT"] = "Bolsa"
+L["BARBERSHOP"] = "Barbearia"
+L["BATTLEGROUND"] = "Campo de Batalha"
+L["BATTLEFIELDS"] = "Campos de Batalha"
+L["BLOCK"] = "Bloquear"
+L["BUFFOPTIONS_LABEL"] = "Bônus e penalidades"
+L["CLASS"] = "Classe"
+L["CHANNEL"] = "Canal"
+L["COLOR"] = "Cor"
+L["COLORS"] = "Cores"
+L["COMBAT"] = "Combate"
+L["COMBAT_TEXT_RUNE_BLOOD"] = "Runa de Sangue"
+L["COMBAT_TEXT_RUNE_DEATH"] = "Runa da Morte"
+L["COMBAT_TEXT_RUNE_FROST"] = "Runa Gélida"
+L["COMBAT_TEXT_RUNE_UNHOLY"] = "Runa Profana"
+L["COMBO_POINTS"] = "|4Ponto:Pontos; de Combo"
+L["CTRL_KEY"] = "CTRL"
+L["CUSTOM"] = "Personalizado"
+L["DAMAGER"] = "Dano"
+L["DEFAULT"] = "Padrão"
+L["DELETE"] = "Excluir"
+L["DISABLE"] = "Desativar"
+L["DRESSUP_FRAME"] = "Provador"
+L["DUNGEON_DIFFICULTY"] = "Dificuldade da masmorra"
+L["DUNGEONS"] = "Masmorras"
+L["EMOTE"] = "Expressão"
+L["ENEMY"] = "Inimigo"
+L["ENERGY"] = "Energia"
+L["FACTION_STANDING_LABEL1"] = "Odiado"
+L["FACTION_STANDING_LABEL2"] = "Hostil"
+L["FACTION_STANDING_LABEL3"] = "Ignorado"
+L["FACTION_STANDING_LABEL4"] = "Tolerado"
+L["FACTION_STANDING_LABEL5"] = "Respeitado"
+L["FACTION_STANDING_LABEL6"] = "Honrado"
+L["FACTION_STANDING_LABEL7"] = "Reverenciado"
+L["FACTION_STANDING_LABEL8"] = "Exaltado"
+L["FILTERS"] = "Filtros"
+L["FLIGHT_MAP"] = "Mapa de voo"
+L["FOCUS"] = "Concentração"
+L["FONT_SIZE"] = "Tamanho da fonte"
+L["FRIEND"] = "Amigo"
+L["FRIENDS"] = "Amigos"
+L["GROUP"] = "Grupo"
+L["GUILD"] = "Guilda"
+L["GUILD_BANK"] = "Banco da guilda"
+L["HAPPINESS"] = "Felicidade"
+L["HEALER"] = "Cura"
+L["HEALTH"] = "Vida"
+L["HIDE"] = "Ocultar"
+L["INSCRIPTION"] = "Escrivania"
+L["INSPECT"] = "Inspecionar"
+L["INTERFACE_OPTIONS"] = "Opções de interface"
+L["INTERRUPTED"] = "Interrompido"
+L["ITEM_BIND_QUEST"] = "Item de missão"
+L["ITEMS"] = "Itens"
+L["KEY_BINDINGS"] = "Teclas de atalho"
+L["LANGUAGE"] = "Idioma"
+L["LEAVE_VEHICLE"] = "Sair do veículo"
+L["LEVEL"] = "Nível"
+L["LOCK_ACTIONBAR_TEXT"] = "Travar barra de ações"
+L["LOOT"] = "Saque"
+L["MACROS"] = "Macros"
+L["MAIL_LABEL"] = "Correio"
+L["MANA"] = "Mana"
+L["MAP_FADE_TEXT"] = "Desvanecer mapa ao andar"
+L["MERCHANT"] = "Mercador"
+L["MINIMAP_LABEL"] = "Minimapa"
+L["MISCELLANEOUS"] = "Diversos"
+L["NAME"] = "Nome"
+L["NONE"] = "Nenhum"
+L["OFFICER"] = "Oficial"
+L["OPACITY"] = "Opacidade"
+L["OPTION_TOOLTIP_ACTION_BUTTON_USE_KEY_DOWN"] = "As ações dos botões serão executadas quando a tecla for pressionada, em vez de quando for solta."
+L["OPTION_TOOLTIP_TIMESTAMPS"] = "Selecione o formato dos carimbos de hora para mensagens de bate-papo."
+L["PARTY"] = "Grupo"
+L["PET"] = "Ajudante"
+L["PLAYER"] = "Jogador"
+L["PLAYER_DIFFICULTY1"] = "Normal"
+L["PLAYER_DIFFICULTY2"] = "Heroico"
+L["RAGE"] = "Raiva"
+L["RAID"] = "Raide"
+L["RAID_TARGET_1"] = "Estrela"
+L["RAID_TARGET_2"] = "Círculo"
+L["RAID_TARGET_3"] = "Diamante"
+L["RAID_TARGET_4"] = "Triângulo"
+L["RAID_TARGET_5"] = "Lua"
+L["RAID_TARGET_6"] = "Quadrado"
+L["RAID_TARGET_7"] = "Xis"
+L["RAID_TARGET_8"] = "Caveira"
+L["REPUTATION"] = "Reputação"
+L["ROLE"] = "Função"
+L["RUNIC_POWER"] = "Poder rúnico"
+L["SAY"] = "Dizer"
+L["SHIFT_KEY"] = "SHIFT"
+L["SHORT"] = "Pequeno"
+L["SHOW"] = "Exibir"
+L["SPEED"] = "Velocidade"
+L["SPELLBOOK"] = "Grimório"
+L["TANK"] = "Tanque"
+L["TARGET"] = "Alvo"
+L["TIMEMANAGER_TITLE"] = "Relógio"
+L["TIMESTAMPS_LABEL"] = "Registro de hora no bate-papo"
+L["TRADE"] = "Negociar"
+L["TRADESKILLS"] = "Perícias profissionais"
+L["TUTORIAL_TITLE47"] = "Barra de totens"
+L["UI_SCALE"] = "Escala da Interface"
+L["UNIT_NAMEPLATES_TYPES"] = "Tipo de movimento de placas de identificação"
+L["UNIT_NAMEPLATES_TYPE_1"] = "Placas de identificação sobrepostas"
+L["UNIT_NAMEPLATES_TYPE_2"] = "Placas de identificação empilhadas"
+L["WHISPER"] = "Sussurrar"
+L["WORLD_MAP"] = "Mapa"
+L["XPBAR_LABEL"] = "Barra de EXP"
+L["YELL"] = "Gritar"
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Locales/ruRU.lua b/ElvUI_OptionsUI/Locales/ruRU.lua
new file mode 100644
index 0000000..33d714b
--- /dev/null
+++ b/ElvUI_OptionsUI/Locales/ruRU.lua
@@ -0,0 +1,1393 @@
+-- Russian localization file for ruRU.
+local L = ElvUI[1].Libs.ACL:NewLocale("ElvUI", "ruRU")
+
+L["%s and then %s"] = "%s, а затем %s"
+L["2D"] = "2D"
+L["3D"] = "3D"
+L["AFK Mode"] = "Режим АФК"
+L["ANCHOR_CURSOR"] = "По центру"
+L["ANCHOR_CURSOR_LEFT"] = "Слева"
+L["ANCHOR_CURSOR_RIGHT"] = "Справа"
+L["Abbreviation"] = true
+L["Above Chat"] = "Над чатом"
+L["Above"] = "Сверху"
+L["Accept Invites"] = "Принимать приглашения"
+L["Action Paging"] = "Переключение панелей"
+L["ActionBars"] = "Панели команд"
+L["Actions"] = "Действия"
+L["Add Item or Search Syntax"] = "Добавить предмет или синтаксис поиска"
+L["Add Name"] = "Добавить имя"
+L["Add Regular Filter"] = "Добавить обычный фильтр"
+L["Add Special Filter"] = "Добавить специальный фильтр"
+L["Add Spell ID or Name"] = "Добавить ID или имя заклинания"
+L["Add SpellID"] = "Добавить ID заклинания"
+L["Add a Name to the list."] = true
+L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."] = "Добавить заклинание в фильтр. Используйте ID, если вы не хотите фильтровать все заклинания с одинаковым именем."
+L["Add a spell to the filter."] = "Добавить заклинание в фильтр"
+L["Add an item or search syntax to the ignored list. Items matching the search syntax will be ignored."] = "Добавить предмет или синтаксис поиска в список игнорируемых. Предметы, соответствующие синтаксису, буду игнорироваться."
+L["Additional Power Text"] = "Текст дополнительного ресурса"
+L["Additional spacing between each individual group."] = "дополнительный отступ между группами."
+L["Additive Blend"] = "Аддитивное сешивание"
+L["Adjust the height of your right chat panel."] = "Настроить высоту правой панели чата"
+L["Adjust the position of the threat bar to either the left or right datatext panels."] = "Изменяет позицию полосы угрозы"
+L["Adjust the size of the minimap."] = "Изменяет размер миникарты"
+L["Adjust the width of the bag frame."] = "Установить размер фрейма сумок"
+L["Adjust the width of the bank frame."] = "Установить размер фрейма банка"
+L["Adjust the width of your right chat panel."] = "Настроить ширину правой панели чата."
+L["Alert Frames"] = "Предупреждения"
+L["Alerts"] = "Оповещения"
+L["Allow LBF to handle the skinning of this element."] = "Разрешить LBF обрабатывать этот элемент."
+L["Allowed Combat Repeat"] = "Повторяющиеся символы"
+L["Alpha Fading"] = "Появление"
+L["Alpha Key"] = "По прозрачности"
+L["Alpha channel is taken from the color option."] = "Альфа канал берется из опции цвета."
+L["Alpha"] = "Прозрачность"
+L["Always Display"] = "Всегда отображать"
+L["Always Hide"] = "Всегда скрывать"
+L["Always Show Realm"] = "Всегда отображать сервер"
+L["Always Show Target Health"] = "Всегда показывать здоровье цели"
+L["Ammo Pouch"] = true
+L["An X offset (in pixels) to be used when anchoring new frames."] = "Отступ по оси X (в пикселях) при фиксации новой рамки."
+L["An Y offset (in pixels) to be used when anchoring new frames."] = "Отступ по оси Y (в пикселях) при фиксации новой рамки."
+L["Anchor Point"] = "Точка фиксации"
+L["Announce Interrupts"] = "Объявлять о прерываниях"
+L["Announce when you interrupt a spell to the specified chat channel."] = "Объявлять о прерванных Вами заклинаниях в указанный канал чата."
+L["Applies the font and font size settings throughout the entire user interface. Note: Some font size settings will be skipped due to them having a smaller font size by default."] = "Применить этот шрифт ко всем элементам интерфейса. Некоторые шрифты будут пропущены из-за более мелкого размера по умолчанию."
+L["Applies the primary texture to all statusbars."] = "Применяет основную текстуру ко всем полосам состояния."
+L["Apply Font To All"] = "Применить ко всем шрифтам"
+L["Apply Texture To All"] = "Применить ко всем текстурам"
+L["Apply this filter if a buff has remaining time greater than this. Set to zero to disable."] = "Применять фильтр, если оставшееся время баффа больше указанного. Установите на 0 для отключения."
+L["Apply this filter if a buff has remaining time less than this. Set to zero to disable."] = "Применять фильтр, если оставшееся время баффа меньше указанного. Установите на 0 для отключения."
+L["Apply this filter if a debuff has remaining time greater than this. Set to zero to disable."] = "Применять фильтр, если оставшееся время дебаффа больше указанного. Установите на 0 для отключения."
+L["Apply this filter if a debuff has remaining time less than this. Set to zero to disable."] = "Применять фильтр, если оставшееся время дебаффа меньше указанного. Установите на 0 для отключения."
+L["Are you sure you want to reset ActionBars settings?"] = "Вы уверены, что хотите сбросить настройки панелей команд?"
+L["Are you sure you want to reset Auras settings?"] = "Вы уверены, что хотите сбросить настройки аур?"
+L["Are you sure you want to reset Bags settings?"] = "Вы уверены, что хотите сбросить настройки сумок?"
+L["Are you sure you want to reset Chat settings?"] = "Вы уверены, что хотите сбросить настройки чата?"
+L["Are you sure you want to reset Cooldown settings?"] = "Вы уверены, что хотите сбросить настройки текста восстановления?"
+L["Are you sure you want to reset DataBars settings?"] = "Вы уверены, что хотите сбросить настройки инфо-полос?"
+L["Are you sure you want to reset DataTexts settings?"] = "Вы уверены, что хотите сбросить настройки инфо-текстов?"
+L["Are you sure you want to reset General settings?"] = "Вы уверены, что хотите сбросить общие настройки?"
+L["Are you sure you want to reset NamePlates settings?"] = "Вы уверены, что хотите сбросить настройки индикаторов здоровья?"
+L["Are you sure you want to reset Tooltip settings?"] = "Вы уверены, что хотите сбросить настройки подсказки?"
+L["Are you sure you want to reset UnitFrames settings?"] = "Вы уверены, что хотите сбросить настройки рамок юнитов?"
+L["Arena Frame"] = true
+L["Arena Registrar"] = true
+L["Arena"] = "Арена"
+L["Ascending or Descending order."] = "Восходящий или нисходящий порядок."
+L["Ascending"] = "Восходящее"
+L["Assist Target"] = "Цели помощников"
+L["Assist"] = "Помощники"
+L["At what point should the text be displayed. Set to -1 to disable."] = "При каком значении должен показываться текст. Установите -1 для отключения."
+L["Attach Text To"] = "Привязать текст к"
+L["Attach To"] = "Прикрепить к"
+L["Attempt to create URL links inside the chat."] = "Пытаться создавать интернет-ссылки в чате."
+L["Attempt to lock the left and right chat frame positions. Disabling this option will allow you to move the main chat frame anywhere you wish."] = "Закрепляет позиции левого и правого чата к соответственным панелям. Отключение этой опции позволит перемещать чат независимо от них."
+L["Attempt to support eyefinity/nvidia surround."] = "Пытаться поддерживать eyefinity/nvidia surround"
+L["Aura Bars"] = "Полосы аур"
+L["Aura Filters"] = "Фильтры аур"
+L["Auto Greed/DE"] = "Авто. не откажусь/распылить"
+L["Auto Hide"] = "Автоскрытие"
+L["Auto Repair"] = "Автоматический ремонт"
+L["Auto-Hide"] = "Автоматически скрывать"
+L["Automatic"] = "Автоматически"
+L["Automatically accept invites from guild/friends."] = "Автоматически принимать приглашения в группу от друзей и гильдии."
+L["Automatically hide the objetive frame during boss or arena fights."] = "Автоматически скрывать список заданий во время сражений с боссами или на арене."
+L["Automatically repair using the following method when visiting a merchant."] = "Автоматически чинить экипировку за счет выбранного источника при посещении торговца."
+L["Automatically select greed or disenchant (when available) on green quality items. This will only work if you are the max level."] = "Автоматически выбирать \"не откажусь\" или \"распылить\" (когда доступно) при розыгрыше предметов зеленого качества. Эта опция работает, только если вы максимального уровня."
+L["Automatically vendor gray items when visiting a vendor."] = "Автоматически продавать предметы серого качества при посещении торговца."
+L["Available Tags"] = "Доступные тэги"
+L["BG Map"] = "Карта ПБ"
+L["BG Score"] = "Таблица ПБ"
+L["BINDING_HEADER_RAID_TARGET"] = "Метки"
+L["Backdrop Color"] = "Цвет фона"
+L["Backdrop Faded Color"] = "Цвет прозрачного фона"
+L["Backdrop Spacing"] = "Отступ фона"
+L["Backdrop color of transparent frames"] = "Цвет фона прозрачных фреймов"
+L["Backdrop"] = "Фон"
+L["Background Glow"] = "Фоновое свечение"
+L["Bad Color"] = "Плохой цвет"
+L["Bad Scale"] = "Плохой масштаб"
+L["Bad Transition Color"] = "Цвет плохого перехода"
+L["Bad"] = "Плохое"
+L["Bag 1"] = "Сумка 1"
+L["Bag 2"] = "Сумка 2"
+L["Bag 3"] = "Сумка 3"
+L["Bag 4"] ="Сумка 4"
+L["Bag Sorting"] = "Сортировка сумок"
+L["Bag Spacing"] = true
+L["Bag"] = "Сумка"
+L["Bag-Bar"] = "Панель сумок"
+L["Bags Only"] = "Только в сумках"
+L["Bags/Bank"] = "Сумки/Банк"
+L["Bank 1"] = "Банк 1"
+L["Bank 2"] = "Банк 2"
+L["Bank 3"] = "Банк 3"
+L["Bank 4"] = "Банк 4"
+L["Bank 5"] = "Банк 5"
+L["Bank 6"] = "Банк 6"
+L["Bank 7"] = "Банк 7"
+L["Bank Only"] = "Только в банке"
+L["Bar Direction"] = "Направление панели"
+L["Bars will transition smoothly."] = "Полосы будут изменяться плавно"
+L["Battleground Texts"] = "Текст ПБ"
+L["Begin a new row or column after this many auras."] = "Начинать новый ряд/столбец после этого количества аур."
+L["Below Chat"] = "Под чатом"
+L["Below"] = "Снизу"
+L["Blacklist Modifier"] = "Модификатор черного писка"
+L["Blacklist"] = "Черный список"
+L["Blend Mode"] = "Тип смешивания" --Check back later
+L["Blend"] = "Смешивание" --Check back later
+L["BlizzUI Improvements"] = "Улучшения Blizzard UI"
+L["Blizzard Style"] = "Стиль Blizzard"
+L["Blizzard"] = true --Doesn't need translating
+L["Block Combat Click"] = "Блокировать нажатия в бою"
+L["Block Combat Hover"] = "Блокировать подсказки в бою"
+L["Block Mouseover Glow"] = "Блокировать подсветку наведения."
+L["Block Target Glow"] = "Блокировать подсветку цели."
+L["Blocks all click events while in combat."] = "Блокирует действия по клику в бою."
+L["Blocks datatext tooltip from showing in combat."] = "Скрывает подсказки инфо-текстов в бою."
+L["Border Color"] = "Цвет окантовки"
+L["Border Glow"] = "Свечение границы"
+L["Border"] = "Граница"
+L["Borders"] = "Границы"
+L["Both"] = "Оба"
+L["Bottom Left"] = "Внизу слева"
+L["Bottom Panel"] = "Нижняя панель"
+L["Bottom Right"] = "Внизу справа"
+L["Bottom to Top"] = "Снизу вверх"
+L["Bottom"] = "Внизу"
+L["BottomLeftMiniPanel"] = "Миникарта снизу слева (внутри)"
+L["BottomMiniPanel"] = "Миникарта снизу (внутри)"
+L["BottomRightMiniPanel"] = "Миникарта снизу справа (внутри)"
+L["Buff Indicator"] = "Индикатор баффов"
+L["Button Size (Bag)"] = "Размер слотов сумок"
+L["Button Size (Bank)"] = "Размер слотов банка"
+L["Button Size"] = "Размер кнопок"
+L["Button Spacing"] = "Отступ кнопок"
+L["Buttons Per Row"] = "Кнопок в ряду"
+L["Buttons"] = "Кнопок"
+L["By Type"] = "По типу"
+L["Calendar Frame"] = "Календарь"
+L["Cast Bar"] = "Полоса заклинаний"
+L["Cast Color"] = "Цвет полосы заклинаний"
+L["Cast No Interrupt Color"] = "Цвет непрерываемого"
+L["Cast Time Format"] = "Формат времени заклинания"
+L["Castbar"] = "Полоса заклинаний"
+L["Casting"] = "Заклинания"
+L["Center"] = "Центр"
+L["Change settings for the display of the location text that is on the minimap."] = "Изменяет опции отображения названия локации на миникарте"
+L["Change the alpha level of the frame."] = "Изменяет прозрачность этого элемента"
+L["Channel Alerts"] = true
+L["Change the width and controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Channel Time Format"] = "Формат времени поддерживаемого"
+L["Character Frame"] = "Окно персонажа"
+L["Chat Bubble Names"] = "Имена на облачках сообщений"
+L["Chat Bubbles Style"] = "Стиль облачков сообщений"
+L["Chat Bubbles"] = "Облачка сообщений"
+L["Chat EditBox Position"] = "Позиция поля ввода"
+L["Chat Output"] = "Вывод в чат"
+L["Check these to only have the filter active in certain difficulties. If none are checked, it is active in all difficulties."] = "Включите, если нужно применять фильтр при определенной сложности. Если не выбрано ничего, то будет активно при всех сложностях."
+L["CheckBox Skin"] = "Скин чекбоксов"
+L["Choose Export Format"] = "Выберите формат экспорта"
+L["Choose UIPARENT to prevent it from hiding with the unitframe."] = "Выберите UIPARENT, чтобы не дать полосе скрываться вместе с рамкой."
+L["Choose What To Export"] = "Выберите что экспортировать"
+L["Choose when you want the tooltip to show in combat. If a modifer is chosen, then you need to hold that down to show the tooltip."] = "Если модификатор выбран, подсказка будет отображаться в бою только при ее нажатии."
+L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."] = "Выберите, когда Вы хотите видеть подсказку. Если выбран модификатор, то подсказка будет показана только, если он зажат."
+L["Class Backdrop"] = "Фон по классу"
+L["Class Castbars"] = "Полоса заклинаний по классу"
+L["Class Color Mentions"] = "Упоминания цветом класса"
+L["Class Color Override"] = "Принудительный цвет класса"
+L["Class Health"] = "Здоровье по классу"
+L["Class Power"] = "Ресурс по классу"
+L["Class Resources"] = "Ресурсы класса"
+L["Class Totems"] = "Классовые тотемы"
+L["Clear Filter"] = "Очистить фильтр"
+L["Clear Search On Close"] = "Сбрасывать поиск при закрытии"
+L["Click Through"] = "Клик насквозь"
+L["Clickable Height"] = "Кликабельная высота"
+L["Clickable Size"] = "Кликабельный размер"
+L["Clickable Width / Width"] = "Кликабельная ширина / ширина"
+L["Coding:"] = "Написание кода:"
+L["Color Keybind Text when Out of Range, instead of the button."] = "Окрашивать текст клавиш, если юнит вне радиуса, вместо всей кнопки."
+L["Color Keybind Text"] = "Окрашивать текст клавиш"
+L["Color Override"] = "Перезапись цвета"
+L["Color Turtle Buffs"] = "Окрашивать Turtle Buffs"
+L["Color all buffs that reduce the unit's incoming damage."] = "Окрашивать все баффы, уменьшающие входящий урон по цели."
+L["Color aurabar debuffs by type."] = "Окрашивать полосы аур-дебаффов по типу"
+L["Color by Value"] = "Окраска по значению"
+L["Color castbars by the class of player units."] = "Окрашивать полосу заклинаний по цвету класса игроков."
+L["Color castbars by the reaction type of non-player units."] = "Окрашивать полосу заклинаний по цвету реакции НИП."
+L["Color health by amount remaining."] = "Окрашивает полосу здоровья в зависимости от оставшегося его количества."
+L["Color health by classcolor or reaction."] = "Окрашивает полосу здоровья по цвету класса или отношению."
+L["Color health by threat status."] = "Окрашивать здоровье по уровню угрозы."
+L["Color of the actionbutton when not usable."] = "Цвет кнопок, которые невозможно использовать."
+L["Color of the actionbutton when out of power (Mana, Rage)."] = "Цвет кнопок на панелях команд, когда не хватает ресурса (маны, ярости)"
+L["Color of the actionbutton when out of range."] = "Цвет кнопок панелей команд, когда цель вне радиуса действия"
+L["Color of the actionbutton when usable."] = "Цвет кнопок, которые можно использовать."
+L["Color power by classcolor or reaction."] = "Окрашивает полосу ресурсов по цвету класса или реакции."
+L["Color power by threat status."] = "Окрашивает полосу ресурсов по уровню угрозы."
+L["Color some texts use."] = "Цвет некоторых текстов."
+L["Color the health backdrop by class or reaction."] = "Окрасить фон полосы здоровья по цвету класса или реакции."
+L["Color the unit healthbar if there is a debuff that can be dispelled by you."] = "Изменять цвет полосы здоровья, если на юните есть дебафф, который Вы можете снять."
+L["Color when the text is about to expire"] = "Цвет текста почти завершившегося восстановления."
+L["Color when the text is in the days format."] = "Цвет текста времени восстановления в днях."
+L["Color when the text is in the hours format."] = "Цвет текста времени восстановления в часах."
+L["Color when the text is in the minutes format."] = "Цвет текста времени восстановления в минутах."
+L["Color when the text is in the seconds format."] = "Цвет текста времени восстановления в секундах."
+L["Colored Icon"] = "Окрашенная иконка"
+L["Coloring (Specific)"] = "Окрашивание конкретных"
+L["Coloring"] = "Окрашивание"
+L["Colorize Selected Text"] = true
+L["Colors the border according to the Quality of the Item."] = "Окрашивать границу в соответствии с качеством предмета."
+L["Combat Icon"] = "Иконка боя"
+L["Combat Override Key"] = "Клавиша показа в бою"
+L["CombatText Font"] = "Шрифт текста боя"
+L["Combo Point"] = "Очко серии"
+L["Comparison Font Size"] = "Размер шрифта сравнения"
+L["Condensed"] = "Через запятую"
+L["Configure Auras"] = "Настроить Ауры"
+L["Control enemy nameplates toggling on or off when in combat."] = "Контролирует показ/скрытие вражеских индикаторов в бою."
+L["Control friendly nameplates toggling on or off when in combat."] = "Контролирует показ/скрытие дружеских индикаторов в бою."
+L["Controls how big of an area on the screen will accept clicks to target unit."] = "Определяет размер области экрана, клик на которой будет считаться кликом по юниту."
+L["Controls the amount of decimals used in values displayed on elements like NamePlates and UnitFrames."] = "Задает количество десятичных долей, используемых на индикаторах здоровья и рамках юнитов."
+L["Controls the speed at which smoothed bars will be updated."] = "Задает скорость обновления плавных полос."
+L["Controls how many seconds of inactivity has to pass before chat is faded."] = true
+L["Cooldown Orientation"] = true
+L["Cooldown Text"] = "Текст восстановления"
+L["Cooldowns"] = "Восстановление"
+L["Copy From"] = "Скопировать из"
+L["Copy Settings From"] = "Скопировать из"
+L["Copy settings from another unit."] = "Скопировать настройки с другого юнита."
+L["Core |cff1784d1E|r|cffe5e3e3lvUI|r options."] = "Основные опции |cff1784d1E|r|cffe5e3e3lvUI|r"
+L["Count Font Size"] = "Размер шрифта стаков"
+L["Count xOffset"] = "Отступ стаков по X"
+L["Count yOffset"] = "Отступ стаков по Y"
+L["Create Custom Text"] = "Создать свой текст"
+L["Create Filter"] = "Создать фильтр"
+L["Create a filter, once created a filter can be set inside the buffs/debuffs section of each unit."] = "Создает фильтр. После создания он может быть установлен в секции баффов/дебаффов любого юнита."
+L["Credits"] = "Благодарности"
+L["Crop Icons"] = "Обрезка иконок"
+L["Currency Format"] = "Формат валюты"
+L["Current - Max | Percent"] = "Текущее - Максимальное | Процент"
+L["Current - Max"] = "Текущее - Максимальное"
+L["Current - Percent (Remaining)"] = "Текущий - Процент (Осталось)"
+L["Current - Percent"] = "Текущее - Процент"
+L["Current - Remaining"] = "Текущий - Осталось"
+L["Current / Max"] = "Текущее / Максимальное"
+L["Current Level"] = "Текущий уровень"
+L["Current"] = "Текущее"
+L["Curse Effect"] = true
+L["Cursor Anchor Offset X"] = "Отступ от курсора по X"
+L["Cursor Anchor Offset Y"] = "Отступ от курсора по Y"
+L["Cursor Anchor Type"] = "Тип положения у курсора"
+L["Cursor Anchor"] = "Около курсора"
+L["Custom Backdrop"] = "Свой фон"
+L["Custom Color"] = "Свой цвет"
+L["Custom Dead Backdrop"] = "Свой фон мертвого"
+L["Custom Faction Colors"] = "Свои цвета отношения"
+L["Custom Texts"] = "Свой текст"
+L["Custom Texture"] = "Своя текстура"
+L["Custom Timestamp Color"] = "Свой цвет времени"
+L["Cutaway Bars"] = "Убывающие полосы"
+L["Darken Inactive"] = "Неактивные затенены"
+L["DataBars"] = "Инфо-полосы"
+L["DataTexts"] = "Инфо-тексты"
+L["Datatext Panel (Left)"] = "Панель информации (левая)"
+L["Datatext Panel (Right)"] = "Панель информации (правая)"
+L["Date Format"] = "Формат даты"
+L["Days"] = "Дни"
+L["Debuff Highlighting"] = "Подсветка дебаффов"
+L["Debug Tools"] = "Инструменты отладки"
+L["Decimal Length"] = "Десятичные доли"
+L["Decimal Threshold"] = "Десятые доли после..."
+L["Decode Text"] = "Декодировать"
+L["Default Color"] = "Цвет по умолчанию"
+L["Default Font"] = "Шрифт по умолчанию"
+L["Default Settings"] = "Умолчания"
+L["Deficit"] = "Дефицит"
+L["Defines how the group is sorted."] = "Определяет условия сортировки"
+L["Defines the sort order of the selected sort method."] = "Определяет порядок в выбранном методе сортировки."
+L["Delete Filter"] = "Удалить фильтр"
+L["Delete a created filter, you cannot delete pre-existing filters, only custom ones."] = "Удалить созданный фильтр. Вы не можете удалять фильтры по умолчанию, только созданные вручную."
+L["Desaturate Cooldowns"] = "Обесцветить при кулдауне"
+L["Desaturate Junk Items"] = "Обесцветить хлам"
+L["Desaturated Icon"] = "Бесцветная иконка"
+L["Descending"] = "Нисходящее"
+L["Detach From Frame"] = "Открепить от рамки"
+L["Detached Width"] = "Ширина при откреплении"
+L["Direction the bag sorting will use to allocate the items."] = "Направление расположения предметов при сортировке."
+L["Direction the bar moves on gains/losses"] = "направление заполнения полосы"
+L["Direction the health bar moves when gaining/losing health."] = "Направление, в котором заполняется полоса при потере/восполнении здоровья."
+L["Disable Bag Sort"] = "Отключить сортировку сумок"
+L["Disable Bank Sort"] = "Отключить сортировку банка"
+L["Disable Debuff Highlight"] = "Отключить подсветку дебаффов"
+L["Disabled Blizzard Frames"] = "Отключить фреймы Blizzard"
+L["Disabled Blizzard"] = "Отключить ауры Blizzard"
+L["Disables the focus and target of focus unitframes."] = "Отключает фреймы фокуса и цели фокуса."
+L["Disables the player and pet unitframes."] = "Отключает фреймы игрока и питомца."
+L["Disables the target and target of target unitframes."] = "Отключает фреймы цели и цели цели."
+L["Disconnected"] = "Не в сети"
+L["Disease Effect"] = true
+L["Display Frames"] = "Показать рамки"
+L["Display Item Level"] = "Отображать уровень предметов"
+L["Display Player"] = "Показывать себя"
+L["Display Target"] = "Показывать цель"
+L["Display Text"] = "Показывать текст"
+L["Display a healer icon over known healers inside battlegrounds or arenas."] = "Отображать иконки лекаря над известными целителями на полях боя и аренах"
+L["Display a panel across the bottom of the screen. This is for cosmetic only."] = "Отображать панель на нижней границе экрана. Это косметический элемент."
+L["Display a panel across the top of the screen. This is for cosmetic only."] = "Отображать панель на верхней границе экрана. Это косметический элемент."
+L["Display a spark texture at the end of the castbar statusbar to help show the differance between castbar and backdrop."] = "Отображать свечение на краю полосы заклинаний для более четкого отделения ее от фона."
+L["Display an exclamation mark on items that starts a quest."] = true
+L["Display battleground messages in the middle of the screen."] = "Отображать сообщения полей боя в центре экрана."
+L["Display bind names on action buttons."] = "Отображать назначенные клавиши на кнопках."
+L["Display cooldown text on anything with the cooldown spiral."] = "Отображать время восстановления на кнопках/предметах."
+L["Display data panels below the chat, used for datatexts."] = "Отображать панели под чатом, используется для инфо-текстов"
+L["Display emotion icons in chat."] = "Показывать смайлы в чате"
+L["Display guild ranks if a unit is guilded."] = "Отображать ранг в гильдии."
+L["Display how many of a certain item you have in your possession."] = "Отображать количество предметов в сумках"
+L["Display macro names on action buttons."] = "Отображать названия макросов на кнопках."
+L["Display minimap panels below the minimap, used for datatexts."] = "Отображать панели информационных текстов под миникартой."
+L["Display player titles."] = "Отображать звания"
+L["Display reminder bar on the minimap."] = true
+L["Display the castbar icon inside the castbar."] = "Отображать иконку на полосе заклинаний."
+L["Display the castbar inside the information panel, the icon will be displayed outside the main unitframe."] = "Отображать полосу заклинаний на информационной панели, иконка будет отображаться рядом с рамкой."
+L["Display the hyperlink tooltip while hovering over a hyperlink."] = "Отображать подсказку ссылки на при наведении на нее мыши. Действует на предметы, достижения, сохранения подземелий и тд."
+L["Display the junk icon on all grey items that can be vendored."] = "Показывать иконку монетки на серых предметах, которые можно продать."
+L["Display the name of the unit on the chat bubble."] = "Отображать имя юнита на облачках сообщений."
+L["Display the npc ID when mousing over a npc tooltip."] = "Отображать ID НИПов в подсказке."
+L["Display the spell or item ID when mousing over a spell or item tooltip."] = "Отображать ID заклинания или предмета в подсказке при наведении мыши."
+L["Display the target of your current cast. Useful for mouseover casts."] = "Отображать имя цели заклинания на полосе."
+L["Display tick marks on the castbar for channelled spells. This will adjust automatically for spells like Drain Soul and add additional ticks based on haste."] = "Отображать метки тиков на полосе заклинаний для поддерживаемых заклинаний. Они будут автоматически масштабироваться для заклинаний вроде Похищения души и добавлять новые тики, основываясь на показателе скорости."
+L["Displayed server time."] = true
+L["Displays a detailed report of every item sold when enabled."] = "Показывать подробный отчет по каждому проданному серому предмету."
+L["Displays item level on equippable items."] = "Отображает уровень предметов, которые можно надеть."
+L["Display Types"] = true
+L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."] = "Не отображать ауры длительностью более этого значения (в секундах). Установите на 0 для отключения."
+L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."] = "Не отображать ауры длительностью менее этого значения (в секундах). Установите на 0 для отключения."
+L["Donations:"] = "Финансовая поддержка:"
+L["Down"] = "Вниз"
+L["Dropdown CheckBox Skin"] = true
+L["Dungeon & Raid Filter"] = "Фильтр подземелий и рейдов"
+L["Duration Enable"] = "Показывать время"
+L["Duration Font Size"] = "Размер шрифта длительности"
+L["Duration Reverse"] = "Длительность, обратное"
+L["Duration Text"] = "Текст длительности"
+L["Duration"] = "Длительность"
+L["Editbox History Size"] = true
+L["ELVUI_CREDITS"] = "Я бы хотел выделить следующих людей, которые помогли мне в разработке аддона тестированием, кодингом и поддержкой при помощи донаций. Пожалуйста, отметьте, что в разделе донаций я написал имена людей, написавших мне в ЛС на форуме. Если Ваше имя пропущено, и Вы хотите его видеть, отправьте мне сообщение."
+L["ENEMY_NPC"] = "Враждебный НИП"
+L["ENEMY_PLAYER"] = "Враждебный игрок"
+L["Elite Icon"] = "Иконки элиты"
+L["Emotion Icons"] = "Иконки эмоций"
+L["Enable Custom Color"] = "Использовать свой цвет"
+L["Enable the use of separate size options for the right chat panel."] = "Включить использование отдельных настроек ширины и высоты для правой панели чата."
+L["Enable/Disable the Bag-Bar."] = "Включить/выключить панель сумок"
+L["Enable/Disable the all-in-one bag."] = "Включить/выключить режим сумки все в одной."
+L["Enable/Disable the loot frame."] = "Включить/выключить окно добычи ElvUI."
+L["Enable/Disable the loot roll frame."] = "Включить/выключить фрейм распределения добычи ElvUI."
+L["Enable/Disable the minimap. |cffFF0000Warning: This will prevent you from seeing the consolidated buffs bar, and prevent you from seeing the minimap datatexts.|r"] = 'Включить/выключить миникарту. |cffFF0000ВНИМАНИЕ: Отключив карту, вы более не сможете видеть полосу объедененных эффектов и информационные тексты, привязанные к миникарте.|r'
+L["Enable/Disable the scaling of targetted nameplates."] = "Включить/выключить масштабирование индикатора цели."
+L["Enables the ElvUI Raid Control panel."] = "Включает панель управления рейдом ElvUI."
+L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."] = "Включение опции позволит Вам проводить сортировку в пределах всего рейда, но взамен Вы не сможете понять кто в какой группе."
+L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."] = "Включение опции инвертирует порядок группировки в неполном рейде, она изменит направление роста и точку его начала."
+L["Enabling this will check your health amount."] = "Если включено, будет проверять значение вашего здоровья."
+L["Enabling this will check your power amount."] = "Если включено, будет проверять значение вашего ресурса."
+L["Enchanting"] = "Зачарование"
+L["Enemy Aura Type"] = "Тип аур врага"
+L["Enemy Combat Toggle"] = "Переключение в бою (враги)"
+L["Enemy NPC Frames"] = true
+L["Enemy Player Frames"] = true
+L["Enemy"] = "Враг"
+L["Engineering"] = "Инженерия"
+L["Enhanced PVP Messages"] = "Улучшенные PvP сообщения"
+L["Equipped Item Color"] = true
+L["Equipped Item"] = true
+L["Error decoding data. Import string may be corrupted!"] = "Ошибка при кодировании. Импортируемая строка может быть повреждена!"
+L["Error exporting profile!"] = "Ошибка при экспорте профиля!"
+L["Exclude Name"] = "Исключить имя"
+L["Excluded Names"] = "Исключенные имена"
+L["Excluded names will not be class colored."] = "Исключенные имена не окрашиваются в цвет класса"
+L["Expiring"] = "Завершение"
+L["Export Profile"] = "Экспорт профиля"
+L["Exported"] = "Экспортировано"
+L["FRIENDLY_NPC"] = "Дружественный НИП"
+L["FRIENDLY_PLAYER"] = "Дружественный игрок"
+L["Fade Chat Toggles"] = true
+L["Fade Out Delay"] = "Задержка изчезновения"
+L["Fade Out"] = "Исчезновение"
+L["Fade Tabs No Backdrop"] = "Затухание без фона"
+L["Fade Threshold"] = "Значение мерцания"
+L["Fade Undocked Tabs"] = "Затухание незакрепленных"
+L["Fade the chat text when there is no activity."] = "Исчезновение строк чата при отсутствии активности"
+L["Fader"] = "Затухание"
+L["Fades the buttons that toggle chat windows when that window has been toggled off."] = true
+L["Fades the text on chat tabs that are docked in a panel where the backdrop is disabled."] = "Исчезновение текста на вкладках, закрепленных на какой-либо из панелей чата, при отключенном фоне."
+L["Fades the text on chat tabs that are not docked at the left or right chat panel."] = "Заставляет текст на вкладках, не закрепленных на правой или левой панелях чата, исчезать до наведения курсора."
+L["Fill"] = "Заполнение"
+L["Filled"] = "По ширине рамки"
+L["Filter Priority"] = "Приоритет фильтров"
+L["Filter Search"] = "Поиск по фильтру"
+L["Filter Type"] = "Тип фильтра"
+L["Filter already exists!"] = "Фильтр уже существует!"
+L["Filters Page"] = "Фильтры"
+L["Filters are not allowed to have commas in their name. Stripping commas from filter name."] = "Фильтры не могут иметь запятые в имени, удаляю запятые."
+L["Flash"] = "Мерцание"
+L["Fluid Position Buffs on Debuffs"] = "Переменная позиция баффов над дебаффами"
+L["Fluid Position Debuffs on Buffs"] = "Переменная позиция дебаффов над баффами"
+L["Flyout Direction"] = "Направление раскрытия"
+L["Flyout Spacing"] = true
+L["Focus"] = "Фокус"
+L["FocusTarget"] = "Цель фокуса"
+L["Font Outline"] = "Граница шрифта"
+L["Font"] = "Шрифт"
+L["Fonts"] = "Шрифты"
+L["Force Off"] = "Постоянно выключен"
+L["Force On"] = "Постоянно включен"
+L["Force Reaction Color"] = "Принудительная реакция"
+L["Force the frames to show, they will act as if they are the player frame."] = "Принудительно показать рамки, они будут вести себя как рамка игрока."
+L["Forces Debuff Highlight to be disabled for these frames"] = "Принудительно не отображает подсветку дебаффов на этих рамках."
+L["Forces Mouseover Glow to be disabled for these frames"] = "Отключает свечение при наведении курсора на эту рамку."
+L["Forces Target Glow to be disabled for these frames"] = "Отключает свечение при взятии в цель этого юнита."
+L["Forces reaction color instead of class color on units controlled by players."] = "Принудительно окрашивает полосу здоровья по цвету реакции для рамок игроков."
+L["Format"] = "Формат"
+L["Frame Glow"] = "Свечение рамки"
+L["Frame Level"] = "Уровень рамки"
+L["Frame Orientation"] = "Направление рамки"
+L["Frame Strata"] = "Слой рамки"
+L["Frequent Updates"] = "Частое обновление"
+L["Friendly Aura Type"] = "Тип аур друга"
+L["Friendly Combat Toggle"] = "Переключение в бою (друзья)"
+L["Friendly NPC Frames"] = true
+L["Friendly Player Frames"] = true
+L["Friendly"] = "Дружественный"
+L["Full Overlay"] = "Полное наложение"
+L["Full"] = "Полный"
+L["GM Chat"] = "Чат с ГМ"
+L["GPS Arrow"] = "Стрелка направления"
+L["Gems"] = "Самоцветы"
+L["General Options"] = "Общие"
+L["Global (Account Settings)"] = "Глобальные (настройки аккаунта)"
+L["Global Fade Transparency"] = "Глобальная прозрачность"
+L["Global"] = "Глобальный"
+L["Glow"] = "Свечение"
+L["Gold Format"] = "Формат золота"
+L["Good Color"] = "Хороший цвет"
+L["Good Scale"] = "Хороший масштаб"
+L["Good Transition Color"] = "Цвет хорошего перехода"
+L["Good"] = "Хорошее"
+L["Gossip Frame"] = "Диалоги"
+L["Group By"] = "Группировать по"
+L["Group Spacing"] = "Отступ групп"
+L["Grouping & Sorting"] = "Группировка и сортировка"
+L["Groups Per Row/Column"] = "Групп на ряд/столбец"
+L["Growth Direction"] = "Направление роста"
+L["Growth X-Direction"] = "Рост по Х"
+L["Growth Y-Direction"] = "Рост по Y"
+L["Growth direction from the first unitframe."] = "Направление роста от первого фрейма."
+L["Guide:"] = "Гайд:"
+L["Guild Ranks"] = "Ранги гильдии"
+L["Guild Registrar"] = "Регистратор гильдий"
+L["HH:MM Threshold"] = "Граница ЧЧ:ММ"
+L["HH:MM"] = "ЧЧ:ММ"
+L["Header Font Size"] = "Размер шрифта заголовка"
+L["Heal Prediction"] = "Входящее исцеление"
+L["Healer Icon"] = "Иконки лекарей"
+L["Health Backdrop Multiplier"] = "Множитель фона здоровья"
+L["Health Backdrop"] = "Фон полосы здоровья"
+L["Health Bar"] = "Полоса здоровья"
+L["Health Border"] = "Граница здоровья"
+L["Health By Value"] = "Здоровье по значению"
+L["Health Color"] = "Цвет здоровья"
+L["Health Length"] = "Длительность здоровья"
+L["Health Threshold"] = "Значение здоровья"
+L["Health"] = "Здоровье"
+L["Height Multiplier"] = "Множитель высоты"
+L["Height of the objective tracker. Increase size to be able to see more objectives."] = "Высота списка заданий. Увеличение размера позволить видеть большее количество."
+L["Height"] = "Высота"
+L["Help Frame"] = "Помощь"
+L["Herbalism"] = "Травы"
+L["Here you can add items or search terms that you want to be excluded from sorting. To remove an item just click on its name in the list."] = "Здесь вы можете добавить предметы или запросы поиска, которые вы хотите исключить из сортировки. Для удаления предмета просто кликните на его имени в списке."
+L["Hide At Max Level"] = "Прятать на максимальном уровне"
+L["Hide Both"] = "Скрыть оба"
+L["Hide Error Text"] = "Прятать сообщения об ошибках"
+L["Hide Frame"] = "Скрыть рамку"
+L["Hide In Combat"] = "Скрывать в бою"
+L["Hide In Vehicle"] = "Прятать в транспорте"
+L["Hide Spell Name"] = "Скрыть название заклинания"
+L["Hide Time"] = "Скрыть время"
+L["Hide specific sections in the datatext tooltip."] = "Скрывать определенные части подсказки инфо-текста."
+L["Hide tooltip while in combat."] = "Скрывать подсказку в бою"
+L["Hides the red error text at the top of the screen while in combat."] = "Скрывать красный текст ошибок вверху экрана в бою."
+L["History Size"] = true
+L["History"] = true
+L["Horizontal Spacing"] = "Отступ по горизонтали"
+L["Horizontal"] = "Горизонтально"
+L["Hours"] = "Часы"
+L["Hover Highlight"] = "Подсветка при наведении"
+L["Hover"] = "Наведение"
+L["How long the cutaway health will take to fade out."] = "Время на исчезновение убывающего здоровья."
+L["How long the cutaway power will take to fade out."] = "Время на исчезновение убывающего ресурса."
+L["How many seconds the castbar should stay visible after the cast failed or was interrupted."] = "После прерывания или отмены, полоса заклинаний будет оставаться видимой указаное количество секунд."
+L["How much time before the cutaway health starts to fade."] = "Время до начала исчезновения убывающего здоровья."
+L["How much time before the cutaway power starts to fade."] = "Время до начала исчезновения убывающего ресурса."
+L["Hyperlink Hover"] = "Подсказка над ссылками"
+L["Icon Frame"] = true
+L["Icon Inside Castbar"] = "Иконка на полосе"
+L["Icon Only"] = true
+L["Icon Position"] = "Позиция иконки"
+L["Icon Size"] = "Размер иконки"
+L["Icon"] = "Иконка"
+L["Icon: BOTTOM"] = "Иконка: внизу"
+L["Icon: BOTTOMLEFT"] = "Иконка: внизу слева"
+L["Icon: BOTTOMRIGHT"] = "Иконка: внизу справа"
+L["Icon: LEFT"] = "Иконка: слева"
+L["Icon: RIGHT"] = "Иконка: справа"
+L["Icon: TOP"] = "Иконка: вверху"
+L["Icon: TOPLEFT"] = "Иконка: вверху слева"
+L["Icon: TOPRIGHT"] = "Иконка: вверху справа"
+L["Icons and Text (Short)"] = "Иконки и текст (короткий)"
+L["Icons and Text"] = "Иконки и текст"
+L["If enabled then it checks if auras are missing instead of being present on the unit."] = "Если включено, то будет проверять отсутствие ауры вместо ее наличия."
+L["If enabled then it will require all auras to activate the filter. Otherwise it will only require any one of the auras to activate it."] = "Если включено, то для активации фильтра потребуется наличие всех аур. В противном случае наличия любой из списка."
+L["If enabled then it will require all cooldowns to activate the filter. Otherwise it will only require any one of the cooldowns to activate it."] = "Если включено, то для активации фильтра потребуется наличие всех кулдаунов. В противном случае наличия любой из списка."
+L["If enabled then the filter will activate if the unit is casting anything."] = true
+L["If enabled then the filter will activate if the unit is channeling anything."] = true
+L["If enabled then the filter will activate if the unit is not casting anything."] = true
+L["If enabled then the filter will activate if the unit is not channeling anything."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or higher than this value."] = "Если включено, то фильтр будет активирован, когда уровень юнита больше либо равен этому числу."
+L["If enabled then the filter will only activate if the level of the unit is equal to or lower than this value."] = "Если включено, то фильтр будет активирован, когда уровень юнита меньше либо равен этому числу."
+L["If enabled then the filter will only activate if the level of the unit matches this value."] = "Если включено, то фильтр будет активирован, когда уровень юнита равен этому числу."
+L["If enabled then the filter will only activate if the level of the unit matches your own."] = "Если включено, то фильтр будет активирован, когда уровень юнита равен вашему."
+L["If enabled then the filter will only activate if the unit is casting interruptible spells."] = "Если включено, то фильтр будет активирован, когда юнит произносит прерываемое заклинание."
+L["If enabled then the filter will only activate if the unit is casting not interruptible spells."] = "Если включено, то фильтр будет активирован, когда юнит произносит не прерываемое заклинание."
+L["If enabled then the filter will only activate if the unit is not casting or channeling one of the selected spells."] = "Если включено, то фильтр будет активирован, когда юнит не произносит или поддерживает одно из выбранных заклинаний."
+L["If enabled then the filter will only activate when you are in combat."] = "Если включено, фильтр будет активирован только когда вы в бою."
+L["If enabled then the filter will only activate when you are not targeting the unit."] = "Если включено, фильтр будет активирован только когда юнит не является вашей целью."
+L["If enabled then the filter will only activate when you are out of combat."] = "Если включено, фильтр будет активирован только когда вы вне боя."
+L["If enabled then the filter will only activate when you are targeting the unit."] = "Если включено, фильтр будет активирован только когда юнит является вашей целью."
+L["If enabled then the filter will only activate when you have a target."] = true
+L["If not set to 0 then override the size of the aura icon to this."] = "Если установлено не на 0, то устанавливать размер иконок аур на заданное число."
+L["If the aura is listed with a number then you need to use that to remove it from the list."] = "Если аура добавлена номером, то для удаления потребуется номер."
+L["If this list is empty, and if 'Interruptible' is checked, then the filter will activate on any type of cast that can be interrupted."] = 'Если список пуст и "Прерываемые" включено, то фильтр будет активирован при произнесении люблго прерываемого заклинания.'
+L["If this threshold is used then the health of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = "Если используется, то уровень здоровья юнита должен быть выше указанного, чтобы фильтр активировался."
+L["If this threshold is used then the health of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = "Если используется, то уровень здоровья юнита должен быть ниже указанного, чтобы фильтр активировался."
+L["If this threshold is used then the power of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = "Если используется, то уровень ресурса юнита должен быть выше указанного, чтобы фильтр активировался."
+L["If this threshold is used then the power of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = "Если используется, то уровень ресурса юнита должен быть ниже указанного, чтобы фильтр активировался."
+L["If you have a lot of 3D Portraits active then it will likely have a big impact on your FPS. Disable some portraits if you experience FPS issues."] = "Если у вас активно много 3D портретов, то это может сказаться на производительности. Отключите их на каких-нибудь фреймах, если заметите проблемы."
+L["If you have any plugins supporting this feature installed you can find them in the selection dropdown to the right."] = "Если у вас установлены плагины, которые поддерживают этот функционал, вы можете найти их в выпадающем списке справа."
+L["If you unlock actionbars then trying to move a spell might instantly cast it if you cast spells on key press instead of key release."] = "Если вы разблокируете панели, а затем попытаетесь переместить заклинание, оно может быть применено мгновенно, если включено применение при нажатии."
+L["Ignore UI Scale Popup"] = "Игнорировать уведомление масштаба"
+L["Ignore mouse events."] = "Игнорировать мышь"
+L["Ignored Items and Search Syntax (Global)"] = "Игнорируемые предметы и синтаксис (Глобальный)"
+L["Ignored Items and Search Syntax (Profile)"] = "Игнорируемые предметы и синтаксис (Профиль)"
+L["Import Profile"] = "Импорт профиля"
+L["Importing"] = "Импортирую"
+L["Inactivity Timer"] = true
+L["Index"] = "Порядок наложения"
+L["Indicate whether buffs you cast yourself should be separated before or after."] = "Определяет должны ли Ваши баффы находиться отдельно перед или после остальных."
+L["InfoPanel Border"] = "Граница инфо панели"
+L["Information Panel"] = "Информационная панель"
+L["Inherit Global Fade"] = "Использовать глобальную прозрачность"
+L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."] = "Использовать глобальную прозрачность. Наведение мыши, наличие цели, фокуса, потеря здоровья и вступление в бой уберут прозрачность. В остальных случаях будет использоваться уровень прозрачности из общих настроек панелей команд."
+L["Inset"] = "Внутри"
+L["Inside Information Panel"] = "На инфо панели"
+L["Install"] = "Установка"
+L["Instance Difficulty"] = "Сложность подземелья"
+L["Instance Type"] = "Тип подземелья"
+L["Interruptable"] = "Прерываемые"
+L["Interruptible"] = "Прерываемые"
+L["Invert Colors"] = "Обратить цвета"
+L["Invert Grouping Order"] = "Инвертировать порядок группировки"
+L["Invert foreground and background colors."] = "Обратить цвета переднего и заднего планов."
+L["Is Casting Anything"] = "Произносит заклинание"
+L["Is Channeling Anything"] = "Поддерживает заклинание"
+L["Is Targeted"] = "Взят в цель"
+L["Item Count Font"] = "Шрифт кол-ва предметов"
+L["Item Count"] = "Кол-во предметов"
+L["Item Level Threshold"] = "Ограничение уровня предметов"
+L["Item Level"] = "Уровень предметов"
+L["JustifyH"] = "Выравнивание"
+L["Key Down"] = "При нажатии клавиши"
+L["Keybind Mode"] = "Назначить клавиши"
+L["Keybind Text Position"] = "Позиция текста клавиш"
+L["Keybind Text X-Offset"] = "Отступ текста клавиш по X"
+L["Keybind Text Y-Offset"] = "Отступ текста клавиш по Y"
+L["Keybind Text"] = "Текст клавиш"
+L["Keyword Alert"] = "Звук ключевых слов"
+L["Keywords"] = "Ключевые слова"
+L["LBF Support"] = true
+L["LEVEL_BOSS"] = "Установите на -1 для боссов или 0 для отключения."
+L["LFD Frame"] = true
+L["LFG Queue"] = "Очередь"
+L["LFR Frame"] = true
+L["Latency"] = "Задержка"
+L["Leatherworking"] = "Кожа"
+L["Left Only"] = "Только левый"
+L["Left to Right"] = "Слева направо"
+L["Left"] = "Левый"
+L["Limit the number of rows or columns."] = "Определяет максимальное количество рядов/столбцов."
+L["List of words to color in chat if found in a message. If you wish to add multiple words you must seperate the word with a comma. To search for your current name you can use %MYNAME%.\n\nExample:\n%MYNAME%, ElvUI, RBGs, Tank"] = "Список слов для окрашивания, если они обнаружены в чате. Если Вы хотите добавить несколько слов, то разделяйте их запятыми. Для поиска имени Вашего текущего персонажа используйте %MYNAME%.\n\nПример:\n%MYNAME%, ElvUI, РБГ, Танк"
+L["Location Text"] = "Текст локации"
+L["Lock Positions"] = "Закрепить"
+L["Log Taints"] = "Отслеживать недочеты"
+L["Log the main chat frames history. So when you reloadui or log in and out you see the history from your last session."] = "Записывать содержимое основных чатов. Таким образом, после перезагрузки интерфейса или входа/выхода из игры, Вы увидите сообщения из прошлой сессии."
+L["Login Message"] = "Сообщение загрузки"
+L["Loot Frames"] = "Добыча"
+L["Loot Roll"] = "Раздел добычи"
+L["Losing Threat"] = "Потеря угрозы"
+L["Low Health Threshold"] = "Пороговое значение здоровья"
+L["Low Threat"] = "Низкая угроза"
+L["Low Threshold"] = "Минимальное значение"
+L["Lower numbers mean a higher priority. Filters are processed in order from 1 to 100."] = "Меньшее значение = большему приоритету. Фильтры обрабатываются в порядке от 1 к 100."
+L["MM:SS Threshold"] = "Граница ММ:СС"
+L["MM:SS"] = "ММ:СС"
+L["Macro Text"] = "Названия макросов"
+L["Magic Effect"] = true
+L["Main Tanks / Main Assist"] = "Танки/помощники"
+L["Main backdrop color of the UI."] = "Основной цвет фона интерфейса."
+L["Main border color of the UI."] = "Основной цвет границ интерфейса"
+L["Main statusbar texture."] = "Основная текстура полос состояния (здоровье, ресурс и тд)."
+L["Make textures transparent."] = "Сделать текстуры прозрачными"
+L["Make the unitframe glow yellow when it is below this percent of health, it will glow red when the health value is half of this value."] = "Заставляет индикатор подсвечиваться желтым при установленном проценте здоровья. При достижении половины этого значения свечение станет красным."
+L["Make the world map smaller."] = "Сделать карту мира меньше. Она больше не будет занимать весь экран в увеличенном варианте."
+L["Map Opacity When Moving"] = "Прозрачность карты в движении"
+L["Maps"] = "Карты"
+L["Match Frame Width"] = "По ширине рамки"
+L["Match Player Level"] = "Соответствие уровню игрока"
+L["Max Alpha"] = "Максимальная видимость"
+L["Max Bars"] = "Максимум полос"
+L["Max Lines"] = true
+L["Max Overflow"] = "Макс. переполнение"
+L["Max Wraps"] = "Максимум рядов"
+L["Max amount of overflow allowed to extend past the end of the health bar."] = "Максимальное значение переполнения, которое может отображаться за пределами полосы здоровья."
+L["Maximum Duration"] = "Максимальная длительность"
+L["Maximum Level"] = "Максимальный уровень"
+L["Maximum Time Left"] = "Максимум оставшегося времени"
+L["Media"] = "Медиа"
+L["Method to sort by."] = "Метод сортировки."
+L["Middle Click - Set Focus"] = "Средний клик - фокус"
+L["Middle clicking the unit frame will cause your focus to match the unit."] = "Нажатие средней кнопкой мыши на фрейм юнита запомнит его в фокус."
+L["Middle"] = "Центр"
+L["Min Alpha"] = "Минимальная видимость"
+L["Minimap Mouseover"] = "При наведении мыши"
+L["Minimap Panels"] = "Информация у миникарты"
+L["Minimum Duration"] = "Минимальная длительность"
+L["Minimum Level"] = "Минимальный уровень"
+L["Minimum Time Left"] = "Минимум оставшегося времени"
+L["Mining"] = "Горное дело"
+L["Minutes"] = "Минуты"
+L["Mirror Timers"] = "Таймеры"
+L["Misc Frames"] = "Прочие фреймы"
+L["Missing"] = "Отсутствует"
+L["Modulating Blend"] = "Модулирующие смешивание" --Check back later
+L["Module Control"] = "Управление модулями"
+L["Module Copy"] = "Копирование модуля"
+L["Module Reset"] = "Сброс модуля"
+L["Money Format"] = "Формат денег"
+L["Mouse Over"] = "При наведении"
+L["Mouseover Glow"] = "Свечение при наведении"
+L["Mouseover Highlight"] = "Подсветка при наведении"
+L["Mouseover"] = "При наведении"
+L["Multi-Monitor Support"] = "Поддержка нескольких мониторов"
+L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."] = "Умножает высоту или ширину фона панели на это значение. Это полезно, когда Вы хотите иметь более одной панели на данном фоне."
+L["NPC IDs"] = "ID НИПов"
+L["Name Color"] = "Цвет имени"
+L["Name Colored Glow"] = "Свечение цвета имени"
+L["Name Font"] = "Шрифт имени"
+L["Name Only"] = "Только имя"
+L["Name"] = "Имя"
+L["NamePlate Style Filters"] = "Фильтры стилей индикаторов здоровья"
+L["NamePlates"] = "Индикаторы здоровья"
+L["Nameplate"] = "Индикатор здоровья"
+L["Neutral"] = "Нейтральный"
+L["Never Hide"] = "Никогда не скрывать"
+L["No Alert In Combat"] = "Без оповещений в бою"
+L["No Duration"] = true
+L["No Sorting"] = "Без сортировки"
+L["Non-Interruptable"] = "Непрерываемые"
+L["Non-Target Alpha"] = "Прозрачность не цели"
+L["Not Casting Anything"] = "Не произносит заклинаний"
+L["Not Channeling Anything"] = "Не поддерживает заклинаний"
+L["Not Spell"] = "Не кастует"
+L["Not Targeted"] = "Не взят в цель"
+L["Not Usable"] = "Нельзя использовать"
+L["Not valid spell id"] = "Неверный ID заклинания"
+L["Num Rows"] = "Рядов"
+L["Number of Groups"] = "Количество групп"
+L["Number of messages you scroll for each step."] = "Количество сообщений, прокручивающихся за шаг."
+L["Number of repeat characters while in combat before the chat editbox is automatically closed. Set to 0 to disable."] = "Кол-во одинаковых символов введенных в бою, после которого поле ввода автоматически закроется. Установите на 0 для отключения."
+L["Number of time in seconds to scroll down to the bottom of the chat window if you are not scrolled down completely."] = "Время в секундах, через которое чат автоматически покрутится вниз до конца, если Вы не сделаете это вручную."
+L["Objective Frame Height"] = "Высота списка заданий"
+L["Off Cooldown"] = "не восстанавливается"
+L["Offset of the powerbar to the healthbar, set to 0 to disable."] = "Смещение полосы ресурсов относительно полосы здоровья. Установите на 0 для отключения."
+L["Offset position for text."] = "Отступ для текста."
+L["Offset"] = "Смещение"
+L["On Cooldown"] = "Восстанавливается"
+L["Only Match SpellID"] = "Сопостовлять только ID заклинаний"
+L["Only show when the unit is not in range."] = "Отображать только когда юнит вне радиуса."
+L["Only show when you are mousing over a frame."] = "Отображать только при наведении курсора на фрейм."
+L["Other Filter"] = "Другой фильтр"
+L["Other's First"] = "Сначала чужие"
+L["Others"] = "Чужое"
+L["Out of Power"] = "Мало ресурса"
+L["Out of Range"] = "Вне радиуса"
+L["Over Health Threshold"] = "Более значения здоровья"
+L["Over Power Threshold"] = "Более значения ресурса"
+L["Overlay Alpha"] = "Прозрачность наложения"
+L["Overlay"] = "Наложение"
+L["Overnuking"] = "Срываем агро!"
+L["Override any custom visibility setting in certain situations, EX: Only show groups 1 and 2 inside a 10 man instance."] = "Игнорировать пользовательские настройки отображения в определенных ситуациях. Пример: показывать только группы 1 и 2 в подземелье на 10 человек."
+L["Override the default class color setting."] = "Перекрывает установки цвета класса по умолчанию."
+L["Owners Name"] = "Имя хозяина"
+L["PVP Trinket"] = "ПвП Аксессуар"
+L["Panel Backdrop"] = "Фон панелей"
+L["Panel Height"] = "Высота панели"
+L["Panel Texture (Left)"] = "Текстура левой панели"
+L["Panel Texture (Right)"] = "Текстура правой панели"
+L["Panel Transparency"] = "Прозрачность панели"
+L["Panel Width (Bags)"] = "Ширина сумок"
+L["Panel Width (Bank)"] = "Ширина банка"
+L["Panel Width"] = "Ширина панели"
+L["Panels"] = "Панели"
+L["Parent"] = "Родитель"
+L["Party / Raid"] = "Группа / Рейд"
+L["Party Only"] = "Только группа"
+L["Party Pets"] = "Питомцы группы"
+L["Party Targets"] = "Цели группы"
+L["Per Row"] = "Кол-во в ряду"
+L["Percent"] = "Процент"
+L["Personal"] = "Личные"
+L["Pet Name"] = "Имя питомца"
+L["Pet"] = "Питомец"
+L["PetTarget"] = "Цель питомца"
+L["Petition Frame"] = "Хартия гильдии"
+L["Pick Up Action Key"] = true
+L["Player Frame Aura Bars"] = "Полосы аур рамки игрока"
+L["Player Health"] = "Здоровье игрока"
+L["Player Out of Combat"] = "Игрок вне боя"
+L["Player Target"] = "Цель игрока"
+L["Player Titles"] = "Звания игроков"
+L["Player in Combat"] = "Игрок в бою"
+L["Player"] = "Игрок"
+L["Plugin"] = "Плагин"
+L["Poison Effect"] = true
+L["Portrait"] = "Портрет"
+L["Position Buffs on Debuffs"] = "Баффы на месте дебаффов"
+L["Position Debuffs on Buffs"] = "Дебаффы на месте баффов"
+L["Position of the Chat EditBox, if datatexts are disabled this will be forced to be above chat."] = "Позиция поля ввода для чата. Если инфо-тексты отключены, оно всегда будет над чатом."
+L["Position"] = "Позиция"
+L["Power Threshold"] = "Лимит ресурса"
+L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."] = "Текст ресурса будет спрятан для НИП. Также текст имени будет смещен в точку расположения текста ресурса."
+L["Power"] = "Ресурс"
+L["Powers"] = "Ресурсы"
+L["Prevent the same messages from displaying in chat more than once within this set amount of seconds, set to zero to disable."] = "Предотвращает появление одинаковых сообщения в чате чаще указанного количества секунд. Установите на нуль для отключения."
+L["Primary Texture"] = "Основная текстура"
+L["Priority"] = "Приоритет"
+L["Private (Character Settings)"] = "Private (Настройки персонажа)"
+L["Profession Bags"] = "Сумки профессий"
+L["Profile Name"] = "Имя профиля"
+L["Profile Specific"] = "По профилю"
+L["Profile imported successfully!"] = "Профиль успешно импортирован!"
+L["Profile"] = "Профиль"
+L["Progress Bar"] = "Полоса прогресса"
+L["Puts coordinates on the world map."] = "Добавляет координаты на карту мира."
+L["PvP Frames"] = "ПвП фреймы"
+L["PvP Icon"] = "Иконка PvP"
+L["PvP Queue"] = true
+L["PvP Text"] = "Текст PvP"
+L["Quest Frames"] = "Задания"
+L["Quest Starter"] = "Начинает задание"
+L["Quiver"] = true
+L["RAID_CONTROL"] = "Управление рейдом"
+L["RL / ML Icons"] = "Иконки лидера/ответственного"
+L["Raid Difficulty"] = "Сложность рейда"
+L["Raid Frame"] = "Рейд"
+L["Raid Icon"] = "Рейдовая иконка"
+L["Raid Only"] = "Только рейд"
+L["Raid Pet"] = "Питомцы рейда"
+L["Raid-40"] = "Рейд 40"
+L["Raid-Wide Sorting"] = "Общерейдовая сортировка"
+L["RaidDebuff Indicator"] = "Индикатор рейдовых дебаффов"
+L["Range"] = "Радиус"
+L["Rapidly update the health, uses more memory and cpu. Only recommended for healing."] = "Более частое обновление состояния здоровья, использует больше памяти и ресурсов процессора. Рекомендуется только для целителей."
+L["Reaction Castbars"] = "Полоса заклинаний по реакции"
+L["Reaction Colors"] = "Цвета отношений"
+L["Reaction Type"] = "Тип реакции"
+L["Reactions"] = "Отношение"
+L["Ready Check Icon"] = "Иконка готовности"
+L["Realm Time"] = true
+L["Remaining / Max"] = "Оставшееся / Максимальное"
+L["Remaining Time"] = true
+L["Remaining"] = "Оставшееся"
+L["Reminder"] = true
+L["Remove Backdrop"] = "Скрыть фон"
+L["Remove Name"] = "Удалить имя"
+L["Remove Spell ID or Name"] = "Удалить ID заклинания или имя"
+L["Remove Spell"] = "Удалить заклинание"
+L["Remove SpellID"] = "Удалить ID заклинания"
+L["Remove a Name from the list."] = "Удалить имя из списка."
+L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."] = "Удалить заклинание из фильтра. Используйте ID, если в фильтре имя удаляемого заклинания содержит ID."
+L["Remove a spell from the filter."] = "Удалить заклинание из фильтра."
+L["Replace Blizzard Fonts"] = "Заменять шрифты Blizzard"
+L["Replaces the default Blizzard fonts on various panels and frames with the fonts chosen in the Media section of the ElvUI Options. NOTE: Any font that inherits from the fonts ElvUI usually replaces will be affected as well if you disable this. Enabled by default."] = "Заменяет шрифты, используемые Blizzard по умолчанию на различных панелях и фреймах, шрифтами, установленными в секции \"Медиа\" (этой секции). Любые дочерние шрифты к заменяемым, также будут изменены. Включено по умолчанию."
+L["Reposition Window"] = "Восстановить окно"
+L["Require All"] = "Все"
+L["Require Target"] = true
+L["Require holding the Alt key down to move cursor or cycle through messages in the editbox."] = "Требовать зажатой клавиши Alt для перемещения курсора или переключения между предыдущими отправленными сообщениями."
+L["Reset Anchors"] = "Сбросить позиции"
+L["Reset Aura Filters"] = "Сбросить фильтры аур"
+L["Reset Editbox History"] = true
+L["Reset Filter"] = "Сбросить фильтр"
+L["Reset History"] = true
+L["Reset Priority"] = "Сбросить приоритеты"
+L["Reset Zoom"] = "Сброс приближения"
+L["Reset all frames to their original positions."] = "Установить все фреймы на позиции по умолчанию"
+L["Reset filter priority to the default state."] = "Сбросить приоритеты фильтров на значение по умолчанию."
+L["Reset the size and position of this frame."] = "Сбросить размер и положение этого окна."
+L["Rest Icon"] = "Иконка отдыха"
+L["Restore Bar"] = "Восстановить панель"
+L["Restore Defaults"] = "Восстановить умолчания"
+L["Restore the actionbars default settings"] = "Восстанавливает настройки панели по умолчанию."
+L["Resurrect Icon"] = "Иконка воскрешения"
+L["Return filter to its default state."] = "Вернуть фильтры к значениям по умолчанию."
+L["Reverse Bag Slots"] = "Обратный порядок слотов"
+L["Reverse Cooldown"] = true
+L["Reverse Style"] = "Обратное затенение"
+L["Reverse Toggle will enable Cooldown Text on this module when the global setting is disabled and disable them when the global setting is enabled."] = "Включает текст восстановления в этом модуле, когда глобальная опция отключена, и отключает, когда включена."
+L["Reverse Toggle"] = "Обратное включение"
+L["Right Only"] = "Только правый"
+L["Right Panel Height"] = "Высота правого чата"
+L["Right Panel Width"] = "Ширина правого чата"
+L["Right to Left"] = "Справа налево"
+L["Right"] = "Правый"
+L["RightClick Self-Cast"] = "Применить к себе через ПКМ"
+L["Role Icon"] = "Иконка роли"
+L["Run the installation process."] = "Запустить процесс установки"
+L["Sanctuary"] = true
+L["Scale of the nameplate that is targetted."] = "Масштаб индикатора цели."
+L["Scale"] = "Масштаб"
+L["Scroll Interval"] = "Интервал прокрутки"
+L["Scroll Messages"] = "Прокручивание сообщений"
+L["Search Syntax"] = "Синтаксис поиска"
+L["Search for a spell name inside of a filter."] = "Искать заклинание в выбранном фильтре"
+L["Secondary Texture"] = "Вторичная текстура"
+L["Seconds remaining on the aura duration before the bar starts moving. Set to 0 to disable."] = "Полоса начнет убывать, когда оставшееся время ауры упадет ниже этого значения в секундах. Установите на 0 для отключения."
+L["Seconds"] = "Секунды"
+L["Selected Text Color"] = true
+L["Selector Color"] = true
+L["Selector Style"] = true
+L["Securely Tanking"] = "Уверено танчим"
+L["Select Filter"] = "Выбрать фильтр"
+L["Select Spell"] = "Выбрать заклинание"
+L["Select a profile to copy from/to."] = "Выберите профиль, из/в который вы хотите копировать настройки."
+L["Select a unit to copy settings from."] = "Выберите юнит, установки которого Вы хотите скопировать."
+L["Select the display method of the portrait."] = "Выбирите метод отображения портрета"
+L["Sell Interval"] = "Интервал продажи"
+L["Send ADDON_ACTION_BLOCKED errors to the Lua Error frame. These errors are less important in most cases and will not effect your game performance. Also a lot of these errors cannot be fixed. Please only report these errors if you notice a Defect in gameplay."] = "Отображать ошибки типа ADDON_ACTION_BLOCKED в фрейме ошибок lua. Эти ошибки в большинстве случаев не сильно важны и не влияют на производительность. Также многие из этих ошибок не могут быть исправлены. Пожалуйста, сообщайте об этих ошибках только если Вы заметите дефект в игре."
+L["Sends your current profile to your target."] = "Отправить текущий профиль цели."
+L["Sends your filter settings to your target."] = "Отправить Ваши фильтры цели."
+L["Separate Panel Sizes"] = "Разные размеры панелей"
+L["Seperate"] = "Разделение"
+L["Set Settings to Default"] = "Сбросить настройки на умолчания"
+L["Set the alpha level of portrait when frame is overlayed."] = "Установить уровень прозрачности портрета, когда включен режим наложения"
+L["Set the filter type. Blacklist will hide any auras in the list and show all others. Whitelist will show any auras in the filter and hide all others."] = "Выберите тип фильтра. Черный список будет скрывать содержащиеся заклинания и отображать остальные. Белый список будет показывать включенные заклинания и скрывать все остальные."
+L["Set the font outline."] = "Устанавливает границу шрифта."
+L["Set the font size for everything in UI. Note: This doesn't effect somethings that have their own seperate options (UnitFrame Font, Datatext Font, ect..)"] = "Установите размер шрифта для всего интерфейса. Это не действует на элементы с собственными настройками шрифтов (например, рамки юнитов)."
+L["Set the font size for unitframes."] = "Устанавливает шрифт для рамок юнитов."
+L["Set the order that the group will sort."] = "Устанавливает метод сортировки в группе."
+L["Set the orientation of the UnitFrame."] = "Устанавливает ориентацию рамки."
+L["Set the priority order of the spell, please note that prioritys are only used for the raid debuff module, not the standard buff/debuff module. If you want to disable set to zero."] = "Устанавливает порядок заклинания. Заметьте, что приоритеты используются только для модуля рейдовых дебаффов, а не для стандартных баффов/дебаффов. Для отключения приоритетности установите на 0."
+L["Set the size of the individual auras."] = "Устанавливает размер аур"
+L["Set the size of your bag buttons."] = "Установите размер кнопок на панели."
+L["Set the type of auras to show when a unit is a foe."] = "Устанавливает тип аур для отображения, когда юнит враг."
+L["Set the type of auras to show when a unit is friendly."] = "Устанавливает тип аур для отображения, когда юнит друг."
+L["Set to either stack nameplates vertically or allow them to overlap."] = "Выстраивать индикаторы в столбик или позволить им накладываться друг на друга."
+L["Sets the font instance's horizontal text alignment style."] = "Устанавливает выравнивание текста по горизонтали"
+L["Share Current Profile"] = "Передать текущий профиль"
+L["Share Filters"] = "Передать фильтры"
+L["Short (Whole Numbers)"] = "Короткий (целые)"
+L["Short Channels"] = "Короткие каналы"
+L["Shortcut to 'Filters' section of the config."] = "Ярлык для секции фильтров в настройках."
+L["Shortcut to global filters."] = "Ярлык для глобальных фильтров"
+L["Shortcuts"] = "Ярлыки"
+L["Shorten the channel names in chat."] = "Сокращать названия каналов чата."
+L["Should tooltip be anchored to mouse cursor"] = "Привязывает подсказку к курсору мыши."
+L["Show Aura From Other Players"] = "Отображать чужие"
+L["Show Auras"] = "Показать ауры"
+L["Show Bind on Equip/Use Text"] = "Отображать текст ПпН/ПпИ"
+L["Show Both"] = "Показать оба"
+L["Show Coins"] = "Показывать монеты"
+L["Show Dispellable Debuffs"] = "Показывать развеиваемые дебаффы"
+L["Show Empty Buttons"] = "Показывать пустые кнопки"
+L["Show For DPS"] = "Показывать для бойцов"
+L["Show For Healers"] = "Показывать для лекарей"
+L["Show For Tanks"] = "Показывать для танков"
+L["Show Icon"] = "Отображать иконку"
+L["Show Junk Icon"] = "Иконки мусора"
+L["Show Quality Color"] = "Показывать цвет качества"
+L["Show Quest Icon"] = true
+L["Show When Not Active"] = "Показывать при отсутствии"
+L["Show an incoming heal prediction bar on the unitframe. Also display a slightly different colored bar for incoming overheals."] = "Отображать объем входящего исцеления на рамках. Также отображает немного иначе окрашенную полосу для избыточного исцеления."
+L["Show the castbar icon desaturated if a spell is not interruptible."] = "Показывать иконку полосы заклинания обесцвеченой, если заклинание нельзя прервать."
+L["Show/Hide Test Frame"] = "Показать / Скерыть тестовый фрейм"
+L["Side Arrows"] = "Стрелки по сторонам"
+L["Size Override"] = "Свой размер"
+L["Size and Positions"] = "Размер и позиция"
+L["Size of the indicator icon."] = "Размер иконки индикатора"
+L["Size"] = "Размер"
+L["Skin Backdrop (No Borders)"] = "Стилизовать фон (без границ)"
+L["Skin Backdrop"] = "Стилизовать фон"
+L["Skin the blizzard chat bubbles."] = "Стилизовать облачка сообщения Blizzard"
+L["Skins"] = "Скины"
+L["Small Panels"] = "Малые панели"
+L["Smaller World Map"] = "Маленькая карта мира"
+L["Smart Aura Position"] = "Умная позиция аур"
+L["Smart Raid Filter"] = "Умный фильтр рейда"
+L["Smart"] = "Умный"
+L["Smooth Bars"] = "Плавные полосы"
+L["Smooth"] = "Плавность"
+L["Smoothing Amount"] = "Значение плавности"
+L["Socket Frame"] = "Инкрустирование"
+L["Sort By"] = "Сортировать по"
+L["Sort Direction"] = "Направление сортировки"
+L["Sort Inverted"] = "Инвертированная сортировка"
+L["Sort Method"] = "Метод сортировки"
+L["Soul Bag"] = true
+L["Spaced"] = "Раздельно"
+L["Spacing"] = "Отступ"
+L["Spam Interval"] = "Интервал спама"
+L["Spark"] = "Искра"
+L["Spell/Item IDs"] = "ID заклинаний/предметов"
+L["Split"] = "Разделить"
+L["Stable"] = "Стойла"
+L["Stack Counter"] = "Количество стаков"
+L["Stack Text Position"] = "Позиция текста стаков"
+L["Stack Text X-Offset"] = "Отступ текста стаков по X"
+L["Stack Text Y-Offset"] = "Отступ текста стаков по X"
+L["Stack Threshold"] = "Стаки"
+L["Start Near Center"] = "Начинать от центра"
+L["StatusBar Texture"] = "Текстура полос состояния"
+L["Statusbar Fill Orientation"] = "Направление заполнения полосы"
+L["Statusbar"] = true
+L["Sticky Chat"] = "Клейкий чат"
+L["Strata and Level"] = "Слой и уровень"
+L["Style Filter"] = "Фильтры стиля"
+L["Style"] = "Стиль"
+L["Tab Font Outline"] = "Граница шрифта вкладок"
+L["Tab Font Size"] = "Размер шрифта вкладок"
+L["Tab Font"] = "Шрифт вкладок"
+L["Tab Panel Transparency"] = "Прозрачность панели вкладок"
+L["Tab Panel"] = "Панель вкладок"
+L["Tab Selector"] = true
+L["Tabard Frame"] = "Создание накидки"
+L["Table"] = "Таблица"
+L["Tank Target"] = "Цели танков"
+L["Tank"] = "Танк"
+L["Tapped"] = "Чужой"
+L["Target Indicator Color"] = "Цвет индикатора цели"
+L["Target Info"] = "Информация о цели"
+L["Target On Mouse-Down"] = "Выделение при нажатии"
+L["Target Scale"] = "Масштаб цели"
+L["Target units on mouse down rather than mouse up. \n\n|cffFF0000Warning: If you are using the addon 'Clique' you may have to adjust your clique settings when changing this."] = "Выделять при нажатии кнопки мыши, а не при ее отпускании.\n\n|cffFF0000Внимание: Если Вы используете аддон 'Clique', то Вы также должны изменить его настройки при изменении этой."
+L["Target/Low Health Indicator"] = "Индикатор цели"
+L["TargetTarget"] = "Цель цели"
+L["TargetTargetTarget"] = "Цель цели цели"
+L["Targeted Glow"] = "Свечение цели"
+L["Targeting"] = "Цели"
+L["Testing:"] = "Тестирование:"
+L["Text Fade"] = true
+L["Text Color"] = "Цвет текста"
+L["Text Font Size"] = "Размер шрифта текста"
+L["Text Format"] = "Формат текста"
+L["Text Position"] = "Позиция текста"
+L["Text Threshold"] = "Значение текста"
+L["Text Toggle On NPC"] = "Переключение текста для НИП"
+L["Text xOffset"] = "Отступ текста по Х"
+L["Text yOffset"] = "Отступ текста по Y"
+L["Text"] = "Текст"
+L["Texture"] = "Текстура"
+L["Textured Icon"] = "Иконка с текстурой"
+L["Textures"] = "Текстуры"
+L["The Portrait will overlay the Healthbar. This will be automatically happen if the Frame Orientation is set to Middle."] = "Портрет будет находится на полосе здоровья. Автоматически активируется, если направление выставлено на Центр."
+L["The Thin Border Theme option will change the overall apperance of your UI. Using Thin Border Theme is a slight performance increase over the traditional layout."] = "Тонкие границы изменят общий вид интерфейса. Это небольшое улучшение производительности относительно традиционного вида."
+L["The amount of buttons to display per row."] = "Количество кнопок в каждом ряду"
+L["The amount of buttons to display."] = "Количество отображаемых кнопок."
+L["The button you must hold down in order to drag an ability to another action button."] = "Кнопка, которую вы должны держать нажатой для перемещения способностей на панелях команд."
+L["The debuff needs to reach this amount of stacks before it is shown. Set to 0 to always show the debuff."] = "Для показа этого дебаффа, он должен надрать указанное количество стаков. Пи установке на 0, показывается всегда."
+L["The direction that the bag frames be (Horizontal or Vertical)."] = "Расположение сумок (горизонтально или вертикально)"
+L["The direction that the bag frames will grow from the anchor."] = "Направление, в котором будут расположены кнопки сумок относительно фиксатора."
+L["The direction the auras will grow and then the direction they will grow after they reach the wrap after limit."] = "Направление роста аур и сторона с которой будет добавляться новый ряд."
+L["The display format of the currency icons that get displayed below the main bag. (You have to be watching a currency for this to display)"] = "Формат отображения валюты в сумках. (У вас должна быть выбрана валюта для отслеживания, чтобы видеть результат)"
+L["The display format of the money text that is shown at the top of the main bag."] = "Формат отображения текста золота в верхней части основной сумки."
+L["The display format of the money text that is shown in the gold datatext and its tooltip."] = "Формат отображения золота на инфо-тексте золота и его подсказке."
+L["The first button anchors itself to this point on the bar."] = "Первая кнопка прикрепляется к этой точке панели"
+L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."] = "Следующий фильтр должен быть верен для отображения группы в дополнение к любому другому уже установленному фильтру."
+L["The font that appears on the text above players heads. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "Шрифт, которым будет написан текст над головами игроков. |cffFF0000ВНИМАНИЕ: Необходим перезапуск игры или релог для начала действия этой настройки.|r"
+L["The font that combat text will use. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "Шрифт текста боя. |cffFF0000ВНИМАНИЕ: это действие потребует перезапуска игры или повторного входа в мир.|r"
+L["The font that the core of the UI will use."] = "Шрифт для основного интерфейса."
+L["The font that the unitframes will use."] = "Шрифт рамок юнитов"
+L["The frame is not shown unless you mouse over the frame."] = "Отображать только при наведении мыши."
+L["The initial group will start near the center and grow out."] = "Первая группа появится в центре и будет расти наружу."
+L["The minimum item level required for it to be shown."] = "Минимальный уровень предмета, который будет показан в сумках."
+L["The name you have selected is already in use by another element."] = "Выбранное вами имя уже используется другим элементом"
+L["The object you want to attach to."] = "Объект, к которому Вы хотите прикрепить полосы"
+L["The size of the action buttons."] = "Размер кнопок панели команд."
+L["The size of the individual buttons on the bag frame."] = "Размер каждого слота в сумок"
+L["The size of the individual buttons on the bank frame."] = "Размер каждого слота в банке"
+L["The spacing between buttons."] = "Расстояние между кнопками"
+L["The spacing between the backdrop and the buttons."] = "Расстояние между фоном панели и кнопками."
+L["The texture that will be used mainly for statusbars."] = "Эта текстура будет использоваться в основном для полос состояния."
+L["The unit prefixes you want to use when values are shortened in ElvUI. This is mostly used on UnitFrames."] = "Сокращения для значений, показываемых ElvUI. В большинстве своем используются для рамок юнитов."
+L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."] = "Эти фильтры не используют список заклинаний, в отличие от обычных фильтров. Вместо этого они используют WoW API и логические операции для определения отображения аур."
+L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."] = "Эти фильтры используют списки заклинаний для определения стоит ли блокировать ауру. Их можно изменить в разделе 'Фильтры' окна настроек."
+L["Thin Border Theme"] = "Тонкие границы"
+L["Thin Borders"] = "Тонкие границы"
+L["This dictates the size of the icon when it is not attached to the castbar."] = "Определяет размер иконки, когда она не привязана к инфо панели."
+L["This feature will allow you to transfer settings to other characters."] = "Эта функция позволит Вам передавать свои настройки другим персонажам."
+L["This is for Customized Icons in your Interface/Icons folder."] = "Используется для кастомных иконок в папке Interface/Icons"
+L["This opens the UnitFrames Color settings. These settings affect all unitframes."] = "Открывает опции окрашивания рамок юнитов. Эти настройки влияют на все рамки."
+L["This option allows the overlay to span the whole health, including the background."] = "Позволяет портрету растягиваться на все здоровье, включая фон."
+L["This section will allow you to copy settings to a select module from or to a different profile."] = "Эта секция позволит вам копировать настройки выбранного модуля в или из другого профиля."
+L["This section will help reset specfic settings back to default."] = "Эта секция поможет вернуть настройки конкретного модуля на умолчания."
+L["This selects the Chat Frame to use as the output of ElvUI messages."] = "В какой чат отправлять сообщения от ElvUI."
+L["This setting controls the size of text in item comparison tooltips."] = "Эта опция контролирует размер текста подсказок сравнения предметов."
+L["This setting will be updated upon changing stances."] = "Эта настройка вступит в силу при смене стойки."
+L["This texture will get used on objects like chat windows and dropdown menus."] = "Эта текстура будет использоваться для таких объектов как окно чата и выпадающие меню."
+L["This will override the global cooldown settings."] = "Это перезапишет глобальные настройки времени восстановления."
+L["This will prevent the UI Scale Popup from being shown when changing the game window size."] = "Не даст появляться окну оповещения об измененияя масштаба при смене размера окна."
+L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."] = "Это сбросит фильтр на умолчания. Любые заклинания, добавленные в этот фильтр, будут удалены."
+L["Threat Display Mode"] = "Режим отображения угрозы"
+L["Threat Health"] = "Здоровье по угрозе"
+L["Threat Power"] = "Ресурс по угрозе"
+L["Threat"] = "Угроза"
+L["Threshold (in minutes) before text is shown in the HH:MM format. Set to -1 to never change to this format."] = "Значение (в минутах), после которого текст восстановления перейдет в формат ЧЧ:ММ. Установите на -1, чтобы никогда не использовать данный формат."
+L["Threshold (in seconds) before text is shown in the MM:SS format. Set to -1 to never change to this format."] = "Значение (в секундах), после которого текст восстановления перейдет в формат ММ:СС. Установите на -1, чтобы никогда не использовать данный формат."
+L["Threshold before text goes into decimal form. Set to -1 to disable decimals."] = "Граница, после которых текст будет показывать десятые доли. Установите на -1 для отключения."
+L["Threshold before text turns red and is in decimal form. Set to -1 for it to never turn red"] = "Время, после которого текст станет красным и начнет отображать доли секунды. Установите -1, чтобы не отображать текст в такой форме."
+L["Threshold before the icon will fade out and back in. Set to -1 to disable."] = "Значение, при котором иконка начнем мерцать. Установите на -1 для отключения."
+L["Ticks"] = "Тики"
+L["Time Format"] = "Формат времяни"
+L["Time Indicator Colors"] = "Цвета индикаторов времени"
+L["Time Remaining Reverse"] = "Оставшееся время, обратное"
+L["Time Remaining"] = "Оставшееся время"
+L["Time To Hold"] = "Время задержки"
+L["Time xOffset"] = "Отступ времени по X"
+L["Time yOffset"] = "Отступ времени по Y"
+L["Time"] = "Время"
+L["Timestamp Color"] = "Цвет времени"
+L["Toggle Anchors"] = "Показать фиксаторы"
+L["Toggle Off While In Combat"] = "Включать в бою"
+L["Toggle On While In Combat"] = "Отключить в бою"
+L["Toggle Tutorials"] = "Показать помощь"
+L["Toggle showing of the left and right chat panels."] = "Переключить отображение панелей чата."
+L["Toggle the chat tab panel backdrop."] = "Показать/скрыть фон панели под вкладками чата"
+L["Toggles the display of the actionbars backdrop."] = "Включить отображение фона панели команд."
+L["Tooltip Font Settings"] = "Шрифты подсказок"
+L["Top Arrow"] = "Стрелка сверху"
+L["Top Left"] = "Вверху слева"
+L["Top Panel"] = "Верхняя панель"
+L["Top Right"] = "Вверху справа"
+L["Top to Bottom"] = "Сверху вниз"
+L["Top"] = "Вверху"
+L["TopLeftMiniPanel"] = "Миникарта сверху слева (внутри)"
+L["TopMiniPanel"] = "Миникарта сверху (внутри)"
+L["TopRightMiniPanel"] = "Миникарта сверху справа (внутри)"
+L["Totem"] = true
+L["Trainer Frame"] = "Тренер"
+L["Transparency level when not in combat, no target exists, full health, not casting, and no focus target exists."] = "Уровень прозрачности вне боя, без цели, без фокуса, с полным здоровьем и без произношения заклинаний."
+L["Transparent Backdrops"] = true
+L["Transparent Buttons"] = true
+L["Transparent"] = "Прозрачный"
+L["Triggers"] = "Триггеры"
+L["Turtle Color"] = "Цвет Turtle Buffs"
+L["Tutorial Frame"] = "Обучение"
+L["URL Links"] = "Интернет-ссылки"
+L["Under Health Threshold"] = "Менее значения здоровья"
+L["Under Power Threshold"] = "Менее значения ресурса"
+L["Uniform Threshold"] = "Граница убывания"
+L["Unique Units"] = true
+L["Unit Prefix Style"] = "Стиль сокращений"
+L["Unit Target"] = "Цель юнита"
+L["Unit Type"] = "Тип юнита"
+L["UnitFrames"] = "Рамки юнитов"
+L["Unlock various elements of the UI to be repositioned."] = "Разблокировать элементы интерфейса для их перемещения."
+L["Up"] = "Вверх"
+L["Usable"] = "Можно использовать"
+L["Use Alt Key"] = "Использовать Alt"
+L["Use Class Color"] = "Использовать цвет класса"
+L["Use Custom Level"] = "Свой уровень"
+L["Use Custom Strata"] = "Свой слой"
+L["Use Dead Backdrop"] = "Фон мертвого"
+L["Use Default"] = "Использовать умолчания"
+L["Use Indicator Color"] = "Использовать цвет индикатора"
+L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."] = "Используйте Shift+ЛКМ для переключения между дружественным, враждебным или нормальным режимами. В нормальном режиме фильтр будет проверять все юниты. В дружеском только дружественные, во враждебном только враждебные."
+L["Use Target Scale"] = "Масштабирование цели"
+L["Use Threat Color"] = "Использовать цвет угрозы"
+L["Use class color for the names of players when they are mentioned."] = "Окрашивать имена игроков цветом их класса."
+L["Use coin icons instead of colored text."] = "Использовать иконки монет вместо окрашенного текста."
+L["Use drag and drop to rearrange filter priority or right click to remove a filter."] = "Используйте перетаскивание для смены приоритета или ПКМ для удаления фильтра."
+L["Use the Name Color of the unit for the Name Glow."] = "Использовать цвет имени юнита для свечения имени."
+L["Use the custom backdrop color instead of a multiple of the main color."] = "Использовать свой цвет фона вместо вариации основного цвета."
+L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."] = "Использовать фильтр \"Buff Indicator (Profile)\", привязанный к профилю вместо глобального."
+L["Use thin borders on certain unitframe elements."] = "Использовать тонкие границы на некоторых элементах рамок юнитов."
+L["Use this backdrop color for units that are dead or ghosts."] = "Использовать этот цвет фона для юнитов, которые мертвы или бегут с кладбища."
+L["Used as RaidDebuff Indicator"] = "Использовать как индикатор рейдовых дебаффов"
+L["Value Color"] = "Цвет значений"
+L["Value must be a number"] = "Значение должно быть числом"
+L["Vehicle Seat Indicator Size"] = "Размер индикатора транспорта"
+L["Vehicle"] = "Техника"
+L["Vendor Gray Detailed Report"] = "Подробности продажи"
+L["Vendor Grays"] = "Продавать серые предметы"
+L["Version"] = "Версия"
+L["Vertical Fill Direction"] = "Вертикальное заполнение"
+L["Vertical Spacing"] = "Отступ по вертикали"
+L["Vertical"] = "Вертикально"
+L["Visibility State"] = "Статус отображения"
+L["Visibility"] = "Видимость"
+L["Watch Frame"] = true
+L["What point to anchor to the frame you set to attach to."] = "К какой точке выбранного фиксатора прикрепить ауры."
+L["What to attach the buff anchor frame to."] = "К чему прикреплять баффы."
+L["What to attach the debuff anchor frame to."] = "К чему прикреплять дебаффы."
+L["When enabled active buff icons will light up instead of becoming darker, while inactive buff icons will become darker instead of being lit up."] = "Если активно, то иконки имеющихся баффов будут яркими, а отсутствующих затемненными."
+L["When enabled it will only show spells that were added to the filter using a spell ID and not a name."] = "Если включено, то будет отображать только заклинания, добавленные в фильтр по ID."
+L["When in a raid group display if anyone in your raid is targeting the current tooltip unit."] = "В рейдовой группе отображать выбравших в цель юнит, для которого показана подсказка"
+L["When inside a battleground display personal scoreboard information on the main datatext bars."] = "На полях боя отображать личную информацию на основных полосах инфо-текстов"
+L["When opening the Chat Editbox to type a message having this option set means it will retain the last channel you spoke in. If this option is turned off opening the Chat Editbox should always default to the SAY channel."] = "При открытии строки ввода сообщения, если эта опция включена, будет выбран последний канал, в который Вы писали. В противном случае всегда будет установлен канал сказать."
+L["When true, the header includes the player when not in a raid."] = "Отображать игрока в группе."
+L["When you go AFK display the AFK screen."] = "Отображать специальный экран, когда вы переходите в состояние \"Отсутствует\"."
+L["Whitelist"] = "Белый список"
+L["Width Multiplier"] = "Множитель ширины"
+L["Width"] = "Ширина"
+L["Will attempt to sell another item in set interval after previous one was sold."] = "Будет пытаться продать следующий предмет через установленный интервал после предыдущего."
+L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."] = "При отсутствии дебаффов, будет показывать баффы на их месте или наоборот."
+L["Word Wrap"] = "Перенос слов"
+L["World Map Coordinates"] = "Координаты карты мира"
+L["World State Frame"] = true
+L["Wrap After"] = "Размер ряда"
+L["X-Offset"] = "Отступ по X"
+L["Y-Offset"] = "Отступ по Y"
+L["You do not need to use 'Is Casting Anything' or 'Is Channeling Anything' for these spells to trigger."] = "Вам не нужно использовать \"Произносит заклинание\" или \"Поддерживает заклинание\" для срабатывания этих заклинаний."
+L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."] = "Вы не можете удалить заклинание из фильтра по умолчанию, которое не было добавлено в него вручную. Отключаю использование в фильтре этого заклинания."
+L["You must be targeting a player."] = "Целью должен быть игрок."
+L["You need to hold this modifier down in order to blacklist an aura by right-clicking the icon. Set to None to disable the blacklist functionality."] = "Вам нужно будет удерживать этот модификатор для занесения ауры в черный список при нажатии ПКМ. Установите на \"Нет\" для отключения возможности заносить их туда."
+L["Your Auras First"] = "Сначала свои"
+L["xOffset"] = "Отступ по X"
+L["yOffset"] = "Отступ по Y"
+
+L["ACTIONBARS_DESC"] = "Изменение настроек панелей команд."
+L["AURAS_DESC"] = "Настройка иконок эффектов, находящихся у миникарты."
+L["BAGS_DESC"] = "Настройки сумок ElvUI"
+L["CHAT_DESC"] = "Настройте отображение чата ElvUI."
+L["COOLDOWN_DESC"] = "Изменение настроек времени восстановления."
+L["DATABAR_DESC"] = "Контролирует отображение информационных полос."
+L["DATATEXT_DESC"] = "Установка отображения информационных текстов."
+L["ELVUI_DESC"] = "ElvUI это аддон для полной замены пользовательского интерфейса World of Warcraft."
+L["NAMEPLATE_DESC"] = "Настройки индикаторов здоровья."
+L["PANEL_DESC"] = "Регулирование размеров левой и правой панелей. Это окажет эффект на чат и сумки."
+L["SKINS_DESC"] = "Установки скинов"
+L["TOGGLESKIN_DESC"] = "Включить/выключить этот скин."
+L["TOOLTIP_DESC"] = "Опций подсказки"
+L["UNITFRAME_DESC"] = "Изменение настроек рамок юнитов."
+L["SEARCH_SYNTAX_DESC"] = [=[С добавлением библиотеки LibItemSearch, у вас появился доступ к большему количеству поисковых запросов. Здесь представлена документация по синтаксису поисковых запросов. Полная инструкция доступна по адресу: https://github.com/Jaliborc/LibItemSearch-1.2/wiki/Search-Syntax.
+
+Специфический поик:
+ • q:[качество] или quality:[качество]. Например, q:эпическое покажет все предметы эпического качества (слово "эпическое" не обязательно вводить до конца).
+ • l:[уровень], lvl:[уровень] or level:[уровень]. Например, l:30 покажет все предметы с уровнем 30. Это относитя именно к уровню предметов, а не требуемому уровню персонажа.
+ • t:[запрос], type:[запрос] or slot:[запрос]. Например, t:оружие покажет все предметы, являющиеся оружием.
+ • n:[имя] or name:[имя]. Например, n:muffins покажет все предметы, в имени которых соержится "muffins".
+ • s:[набор] or set:[набор]. Например, s:fire покажет предметы из наборов экипировки, название которых начинается с "fire".
+ • r:[level], reg:[level], rl:[level], regl:[level] or reqlvl:[level]. For example, reqlvl:30 will find all items that require level 30.
+ • tt:[запрос], tip:[запрос] or tooltip:[запрос]. Например, tt:уникальный покажет все предметы, которые являются уникальными или уникальными использующимися.
+
+
+Операторы поиска:
+ • ! : Обращает результат поиска. Например, !q:эпическое покажет все НЕ эпические предметы.
+ • | : Объединет запросы. Например, "q:эпическое | t:оружие" отобразит все предметы эпического качества ИЛИ являющиеся оружием.
+ • & : Суммирует запросы. Например, "q:эпическое & t:оружие" отобразит все оружие эпического качества.
+ • >, <, <=, => : сразнения для численных запросов. Например, запрос "lvl: >30" покажет все предметы с уровнем выше 30.
+
+
+Также могут быть использованы следующие параметры:
+ • soulbound, bound, bop : персональные при поднятии.
+ • bou : персональные при использовании.
+ • boe : персональные при одевании.
+ • boa : привязоные к учетной записи.
+ • quest : специальные предметы для заданий.]=]
+L["TEXT_FORMAT_DESC"] = [=[Строка для изменения вида текста.
+
+Примеры:
+[namecolor][name] [difficultycolor][smartlevel] [shortclassification]
+[healthcolor][health:current-max]
+[powercolor][power:current]
+
+Форматы здоровья/резурсов:
+"current" - текущее значение
+"percent" - значение в процентах
+"current-max" - текущее значение, за которым идет максимальное значение. Будет отображать только максимальное значение, если текущее равно ему.
+"current-percent" - текущее значение, за которым идет значение в процентах.Будет отображать только максимальное значение, если текущее равно ему.
+"current-max-percent" - текущее значение, максимальное значение, за которым идет значение в процентах, Будет отображать только максимальное значение, если текущее равно ему.
+"deficit" - отображает значение недостающего до максимума здоровья/ресурса. Не будет отображать ничего, если текущее значение равно максимальному.
+
+Форматы имени:
+"name:veryshort" - Name restricted to 5 characters
+"name:short" - Имя с ограничением длины в 10 символов
+"name:medium" - Имя с ограничением длины в 15 символов
+"name:long" - Имя с ограничением длины в 20 символов
+"name:short:translit" - Name restricted to 10 characters with transliteration
+
+Для отключения оставьте поле пустым, для дополнительной информации посетите https://www.tukui.org/forum/viewtopic.php?t=6]=]
+L["NAMEPLATE_FRAMELEVEL_DESC"] = [=[If you set this to 1 then all plates triggered by this style filter will be above any of the non-triggered plates.
+
+If you set this to 2 in another style filter then all plates triggered by that filter will be above plates with frame level set to 1 and all non-triggered plates, and so on.
+
+NOTE: This setting will NOT fix the issue with clicking or mousing over nameplates that are overlapped. That issue is due to us not being able to manipulate the frame level of the clickable area for nameplates.]=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to page differently.
+ Example: '[combat] 2;']=] ] = [=[Работает как макрос. Вы можете задать различные условия для отображения разных панелей.
+ Пример: '[combat] 2;']=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to show/hide differently.
+ Example: '[combat] show;hide']=] ] = [=[Работает как макрос. Вы можете задать различные условия для показа/скрытия панели.
+ Пример: '[combat] show;hide']=]
+
+L[ [=[Specify a filename located inside the World of Warcraft directory. Textures folder that you wish to have set as a panel background.
+
+Please Note:
+-The image size recommended is 256x128
+-You must do a complete game restart after adding a file to the folder.
+-The file type must be tga format.
+
+Example: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Or for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here.]=] ] = [=[Укажите имя файла в папке World of Warcraft, который Вы хотите использовать в качестве фона панелей.
+
+Пожалуйста, учтите:
+-Рекомендованный размер изображения 256x128
+-Вы должны полностью перезапустить игру после добавления нового файла в папку.
+-Тип файла должен быть tga.
+
+Пример: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Для большинства пользователей будет легче просто положить tga файл в папку игры, а затем написать имя файла здесь.]=]
+
+-- Global Strings
+L["ACHIEVEMENTS"] = "Достижения"
+L["ALT_KEY_TEXT"] = "ALT"
+L["ARENA"] = "Арена"
+L["AUCTIONS"] = "Лоты"
+L["BAGSLOT"] = "Сумка"
+L["BARBERSHOP"] = "Парикмахерская"
+L["BATTLEGROUND"] = "Поле боя"
+L["BATTLEFIELDS"] = "Поля боя"
+L["BLOCK"] = "Блок"
+L["BOSS"] = "Босс"
+L["BUFFOPTIONS_LABEL"] = "Эффекты и ауры"
+L["CLASS"] = "Клас"
+L["CHANNEL"] = "Канал"
+L["COLOR"] = "Цвет"
+L["COLORS"] = "Цвета"
+L["COMBAT"] = "Бой"
+L["COMBAT_TEXT_RUNE_BLOOD"] = "Руна крови"
+L["COMBAT_TEXT_RUNE_DEATH"] = "Руна смерти"
+L["COMBAT_TEXT_RUNE_FROST"] = "Руна льда"
+L["COMBAT_TEXT_RUNE_UNHOLY"] = "Руна нечестивости"
+L["COMBO_POINTS"] = "Длина серии приемов"
+L["CTRL_KEY"] = "CTRL"
+L["CUSTOM"] = "Вручную"
+L["DAMAGER"] = "Боец"
+L["DEFAULT"] = "По умолчанию"
+L["DELETE"] = "Удалить"
+L["DISABLE"] = "Отключить"
+L["DRESSUP_FRAME"] = "Примерочная"
+L["DUNGEON_DIFFICULTY"] = "Сложность подземелья"
+L["DUNGEONS"] = "Подземелья"
+L["EMOTE"] = "Эмоции"
+L["ENEMY"] = "Противник"
+L["ENERGY"] = "Энергия"
+L["FACTION_STANDING_LABEL1"] = "Ненависть"
+L["FACTION_STANDING_LABEL2"] = "Враждебность"
+L["FACTION_STANDING_LABEL3"] = "Неприязнь"
+L["FACTION_STANDING_LABEL4"] = "Равнодушие"
+L["FACTION_STANDING_LABEL5"] = "Дружелюбие"
+L["FACTION_STANDING_LABEL6"] = "Уважение"
+L["FACTION_STANDING_LABEL7"] = "Почтение"
+L["FACTION_STANDING_LABEL8"] = "Превознесение"
+L["FILTERS"] = "Фильтры"
+L["FLIGHT_MAP"] = "Карта полетов"
+L["FOCUS"] = "Концентрация"
+L["FONT_SIZE"] = "Размер шрифта"
+L["FRIEND"] = "Друг"
+L["FRIENDS"] = "Друзья"
+L["GROUP"] = "Группа"
+L["GUILD"] = "Гильдия"
+L["GUILD_BANK"] = "Банк гильдии"
+L["HAPPINESS"] = "Настроение"
+L["HEALER"] = "Лекарь"
+L["HEALTH"] = "Здоровье"
+L["HIDE"] = "Скрыть"
+L["INSCRIPTION"] = "Начертание"
+L["INSPECT"] = "Осмотреть"
+L["INTERFACE_OPTIONS"] = "Интерфейс"
+L["INTERRUPTED"] = "Прервано"
+L["ITEM_BIND_QUEST"] = "Требуется для задания"
+L["ITEMS"] = "Предметы"
+L["KEY_BINDINGS"] = "Назначение клавиш"
+L["LANGUAGE"] = "Язык"
+L["LEAVE_VEHICLE"] = "Спрыгнуть"
+L["LEVEL"] = "Уровень"
+L["LOCK_ACTIONBAR_TEXT"] = "Закрепить панели команд"
+L["LOOT"] = "Добыча"
+L["MACROS"] = "Макросы"
+L["MAIL_LABEL"] = "Письмо"
+L["MANA"] = "Мана"
+L["MAP_FADE_TEXT"] = "Прозрачность карты в движении"
+L["MERCHANT"] = "Торговец"
+L["MINIMAP_LABEL"] = "Мини-карта"
+L["MISCELLANEOUS"] = "Разное"
+L["NAME"] = "Имя"
+L["NONE"] = "Нет"
+L["OFFICER"] = "Офицер"
+L["OPACITY"] = "Видимость"
+L["OPTION_TOOLTIP_ACTION_BUTTON_USE_KEY_DOWN"] = "Способности будут задействоваться, когда пользователь нажимает, а не отпускает клавишу."
+L["OPTION_TOOLTIP_TIMESTAMPS"] = "Выберите формат времени для сообщений чата."
+L["PARTY"] = "Группа"
+L["PET"] = "Питомец"
+L["PLAYER"] = "игрок"
+L["PLAYER_DIFFICULTY1"] = "Обычный"
+L["PLAYER_DIFFICULTY2"] = "Героический"
+L["RAGE"] = "Ярость"
+L["RAID"] = "Рейд"
+L["RAID_TARGET_1"] = "Звезда"
+L["RAID_TARGET_2"] = "Круг"
+L["RAID_TARGET_3"] = "Ромб"
+L["RAID_TARGET_4"] = "Треугольник"
+L["RAID_TARGET_5"] = "Полумесяц"
+L["RAID_TARGET_6"] = "Квадрат"
+L["RAID_TARGET_7"] = "Крест"
+L["RAID_TARGET_8"] = "Череп"
+L["REPUTATION"] = "Репутация"
+L["ROLE"] = "Роль"
+L["RUNIC_POWER"] = "Сила рун"
+L["SAY"] = "Речь"
+L["SHIFT_KEY"] = "SHIFT"
+L["SHORT"] = "Ниже"
+L["SHOW"] = "Показать"
+L["SPEED"] = "Скорость"
+L["SPELLBOOK"] = "Способности"
+L["TALENTS"] = "Таланты"
+L["TANK"] = "Танк"
+L["TARGET"] = "Цель"
+L["TIMEMANAGER_TITLE"] = "Часы"
+L["TIMESTAMPS_LABEL"] = "Время в чате"
+L["TRADE"] = "Обмен"
+L["TRADESKILLS"] = "Ремесла"
+L["TUTORIAL_TITLE47"] = "Панель тотемов"
+L["UI_SCALE"] = "Масштаб интерфейса"
+L["UNIT_NAMEPLATES_TYPES"] = "Размещение индикаторов здоровья"
+L["UNIT_NAMEPLATES_TYPE_1"] = "Наложение"
+L["UNIT_NAMEPLATES_TYPE_2"] = "Друг над другом"
+L["WHISPER"] = "Шепот"
+L["WORLD_MAP"] = "Карта"
+L["XPBAR_LABEL"] = "Индикатор опыта"
+L["YELL"] = "Крик"
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Locales/zhCN.lua b/ElvUI_OptionsUI/Locales/zhCN.lua
new file mode 100644
index 0000000..fad248b
--- /dev/null
+++ b/ElvUI_OptionsUI/Locales/zhCN.lua
@@ -0,0 +1,1391 @@
+-- Simplified Chinese localization file for zhCN.
+local L = ElvUI[1].Libs.ACL:NewLocale("ElvUI", "zhCN")
+
+L["%s and then %s"] = "%s 于 %s"
+L["2D"] = "2D"
+L["3D"] = "3D"
+L["AFK Mode"] = "离开模式"
+L["ANCHOR_CURSOR"] = "鼠标指针"
+L["ANCHOR_CURSOR_LEFT"] = "鼠标指针左侧"
+L["ANCHOR_CURSOR_RIGHT"] = "鼠标指针右侧"
+L["Abbreviation"] = true
+L["Above Chat"] = "聊天框上方"
+L["Above"] = "向上"
+L["Accept Invites"] = "自动接受邀请"
+L["Action Paging"] = "动作条翻页"
+L["ActionBars"] = "动作条"
+L["Actions"] = "动作"
+L["Add Item or Search Syntax"] = "添加物品或者匹配语法"
+L["Add Name"] = true
+L["Add Regular Filter"] = "添加常规过滤器"
+L["Add Special Filter"] = "添加特殊过滤器"
+L["Add Spell ID or Name"] = "添加技能ID或者名字"
+L["Add SpellID"] = "添加技能ID"
+L["Add a Name to the list."] = true
+L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."] = "添加一个技能到过滤器.使用法术ID以避免匹配到同名的光环"
+L["Add a spell to the filter."] = "添加一个技能到过滤器"
+L["Add an item or search syntax to the ignored list. Items matching the search syntax will be ignored."] = "添加一个物品或者匹配语法到屏蔽列表.符合匹配语法的物品将被忽略"
+L["Additional Power Text"] = "额外能量文字"
+L["Additional spacing between each individual group."] = "各小队之间的额外间隔"
+L["Additive Blend"] = "覆盖混合"
+L["Adjust the height of your right chat panel."] = "调整右聊天框的高度"
+L["Adjust the position of the threat bar to either the left or right datatext panels."] = "调整仇恨条的位置于左侧或右侧信息面板"
+L["Adjust the size of the minimap."] = "调整小地图尺寸"
+L["Adjust the width of the bag frame."] = "调整背包框架宽度"
+L["Adjust the width of the bank frame."] = "调整银行框架宽度"
+L["Adjust the width of your right chat panel."] = "调整右聊天框的宽度"
+L["Alert Frames"] = "警报"
+L["Alerts"] = "提醒"
+L["Allow LBF to handle the skinning of this element."] = "允许LBF来处理这个元素的皮肤"
+L["Allowed Combat Repeat"] = "战斗连续按键修复"
+L["Alpha Fading"] = "透明度渐隐"
+L["Alpha Key"] = "Alpha通道"
+L["Alpha channel is taken from the color option."] = "Alpha通道由颜色选项决定"
+L["Alpha"] = "透明度"
+L["Always Display"] = "总是显示"
+L["Always Hide"] = "总是隐藏"
+L["Always Show Realm"] = "总是显示服务器"
+L["Always Show Target Health"] = true
+L["Ammo Pouch"] = true
+L["An X offset (in pixels) to be used when anchoring new frames."] = "锚定新框架时的X偏移(像素)"
+L["An Y offset (in pixels) to be used when anchoring new frames."] = "锚定新框架时的Y偏移(像素)"
+L["Anchor Point"] = "定位方向"
+L["Announce Interrupts"] = "打断通告"
+L["Announce when you interrupt a spell to the specified chat channel."] = "在指定聊天频道通知打断信息"
+L["Applies the font and font size settings throughout the entire user interface. Note: Some font size settings will be skipped due to them having a smaller font size by default."] = "把该字体设置应用到所有ElvUI设置中去,但是某些设置并不会被改变"
+L["Applies the primary texture to all statusbars."] = "将主要材质应用到所有状态条"
+L["Apply Font To All"] = "应用字体到所有"
+L["Apply Texture To All"] = "应用材质到所有"
+L["Apply this filter if a buff has remaining time greater than this. Set to zero to disable."] = "当增益剩余时间大于该值时应用该过滤器. 设为0以禁用."
+L["Apply this filter if a buff has remaining time less than this. Set to zero to disable."] = "当增益剩余时间小于该值时应用该过滤器. 设为0以禁用."
+L["Apply this filter if a debuff has remaining time greater than this. Set to zero to disable."] = "当减益剩余时间大于该值时应用该过滤器. 设为0以禁用."
+L["Apply this filter if a debuff has remaining time less than this. Set to zero to disable."] = "当减益剩余时间小于该值时应用该过滤器. 设为0以禁用."
+L["Are you sure you want to reset ActionBars settings?"] = "你确定要重置‘动作条’的设置吗?"
+L["Are you sure you want to reset Auras settings?"] = "你确定要重置‘光环’的设置吗?"
+L["Are you sure you want to reset Bags settings?"] = "你确定要重置‘背包’的设置吗?"
+L["Are you sure you want to reset Chat settings?"] = "你确定要重置‘聊天框’的设置吗?"
+L["Are you sure you want to reset Cooldown settings?"] = "你确定要重置‘冷却文字’的设置吗?"
+L["Are you sure you want to reset DataBars settings?"] = "你确定要重置‘数据条’的设置吗?"
+L["Are you sure you want to reset DataTexts settings?"] = "你确定要重置‘信息文字’的设置吗?"
+L["Are you sure you want to reset General settings?"] = "你确定要重置‘一般’的设置吗?"
+L["Are you sure you want to reset NamePlates settings?"] = "你确定要重置‘姓名板’的设置吗?"
+L["Are you sure you want to reset Tooltip settings?"] = "你确定要重置‘鼠标提示’的设置吗?"
+L["Are you sure you want to reset UnitFrames settings?"] = "你确定要重置‘单位框架’的设置吗?"
+L["Arena Frame"] = true
+L["Arena Registrar"] = true
+L["Arena"] = "竞技场"
+L["Ascending or Descending order."] = "升序或降序"
+L["Ascending"] = "升序"
+L["Assist Target"] = "助理目标"
+L["Assist"] = "助理框架"
+L["At what point should the text be displayed. Set to -1 to disable."] = "在何时显示文本. 设为-1以禁用此功能"
+L["Attach Text To"] = "文字附着于"
+L["Attach To"] = "附加到"
+L["Attempt to create URL links inside the chat."] = "在聊天框中创建超链接"
+L["Attempt to lock the left and right chat frame positions. Disabling this option will allow you to move the main chat frame anywhere you wish."] = "锁定左右聊天框架的位置.禁用此选项将允许你移动聊天框架到任意位置"
+L["Attempt to support eyefinity/nvidia surround."] = "尝试支持eyefinity/nvidia surround"
+L["Aura Bars"] = "光环条"
+L["Aura Filters"] = "光环过滤器"
+L["Auto Greed/DE"] = "自动贪婪/分解"
+L["Auto Hide"] = "自动隐藏"
+L["Auto Repair"] = "自动修理"
+L["Auto-Hide"] = "自动隐藏"
+L["Automatic"] = "自动"
+L["Automatically accept invites from guild/friends."] = "自动接受工会或好友的邀请"
+L["Automatically hide the objetive frame during boss or arena fights."] = "在首领战/竞技场中自动隐藏任务框体"
+L["Automatically repair using the following method when visiting a merchant."] = "使用以下方式来自动修理装备"
+L["Automatically select greed or disenchant (when available) on green quality items. This will only work if you are the max level."] = "当你满级时, 自动选择贪婪或分解绿色物品"
+L["Automatically vendor gray items when visiting a vendor."] = "当访问商人时自动出售灰色物品"
+L["Available Tags"] = "可用的文字格式"
+L["BG Map"] = "战场地图"
+L["BG Score"] = "战场记分"
+L["BINDING_HEADER_RAID_TARGET"] = "队伍标记"
+L["Backdrop Color"] = "背景颜色"
+L["Backdrop Faded Color"] = "背景透明色"
+L["Backdrop Spacing"] = "背景间距"
+L["Backdrop color of transparent frames"] = "透明框架的背景颜色"
+L["Backdrop"] = "背景"
+L["Background Glow"] = "背景发光"
+L["Bad Color"] = "危险颜色"
+L["Bad Scale"] = "危险缩放"
+L["Bad Transition Color"] = "危险过渡颜色"
+L["Bad"] = "危险"
+L["Bag 1"] = "背包1"
+L["Bag 2"] = "背包2"
+L["Bag 3"] = "背包3"
+L["Bag 4"] = "背包4"
+L["Bag Sorting"] = "背包排序"
+L["Bag Spacing"] = true
+L["Bag"] = "背包"
+L["Bag-Bar"] = "背包条"
+L["Bags Only"] = "仅背包"
+L["Bags/Bank"] = "背包/银行"
+L["Bank 1"] = "银行1"
+L["Bank 2"] = "银行2"
+L["Bank 3"] = "银行3"
+L["Bank 4"] = "银行4"
+L["Bank 5"] = "银行5"
+L["Bank 6"] = "银行6"
+L["Bank 7"] = "银行7"
+L["Bank Only"] = "仅银行"
+L["Bar Direction"] = "背包条排序方向"
+L["Bars will transition smoothly."] = "状态条平滑增减"
+L["Battleground Texts"] = "战场信息"
+L["Begin a new row or column after this many auras."] = "在这些光环旁开始新的行或列"
+L["Below Chat"] = "聊天框下方"
+L["Below"] = "向下"
+L["Blacklist Modifier"] = "黑名单功能键"
+L["Blacklist"] = "黑名单"
+L["Blend Mode"] = "混合模式"
+L["Blend"] = "混合"
+L["BlizzUI Improvements"] = "暴雪界面优化"
+L["Blizzard Style"] = "暴雪样式"
+L["Blizzard"] = "暴雪原生"
+L["Block Combat Click"] = "战斗中屏蔽点击"
+L["Block Combat Hover"] = "战斗中屏蔽提示"
+L["Block Mouseover Glow"] = "屏蔽鼠标指向高亮"
+L["Block Target Glow"] = "屏蔽目标高亮"
+L["Blocks all click events while in combat."] = "战斗中禁用点击事件"
+L["Blocks datatext tooltip from showing in combat."] = "战斗中禁用鼠标提示"
+L["Border Color"] = "边框颜色"
+L["Border Glow"] = "边框发光"
+L["Border"] = "边框"
+L["Borders"] = "边框"
+L["Both"] = "两者"
+L["Bottom Left"] = "左下"
+L["Bottom Panel"] = "底部面板"
+L["Bottom Right"] = "右下"
+L["Bottom to Top"] = "底部到顶部"
+L["Bottom"] = "下"
+L["BottomLeftMiniPanel"] = "小地图左下内侧"
+L["BottomMiniPanel"] = "小地图底部内侧"
+L["BottomRightMiniPanel"] = "小地图右下内侧"
+L["Buff Indicator"] = "增益指示器"
+L["Button Size (Bag)"] = "背包格子尺寸"
+L["Button Size (Bank)"] = "银行格子尺寸"
+L["Button Size"] = "按钮大小"
+L["Button Spacing"] = "按钮间距"
+L["Buttons Per Row"] = "每行按钮数"
+L["Buttons"] = "按钮数"
+L["By Type"] = "类型"
+L["Calendar Frame"] = "日历框架"
+L["Cast Bar"] = "施法条"
+L["Cast Color"] = "施法条颜色"
+L["Cast No Interrupt Color"] = "无法打断的颜色"
+L["Cast Time Format"] = "施法时间格式"
+L["Castbar"] = "施法条"
+L["Casting"] = "施法"
+L["Center"] = "居中"
+L["Change settings for the display of the location text that is on the minimap."] = "改变小地图所在位置文字的显示设置"
+L["Change the alpha level of the frame."] = "改变框架透明度"
+L["Channel Alerts"] = true
+L["Change the width and controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Channel Time Format"] = "引导法术时间格式"
+L["Character Frame"] = "角色"
+L["Chat Bubble Names"] = "聊天气泡名字"
+L["Chat Bubbles Style"] = "聊天气泡样式"
+L["Chat Bubbles"] = "聊天气泡"
+L["Chat EditBox Position"] = "聊天输入框位置"
+L["Chat Output"] = "聊天输出"
+L["Check these to only have the filter active in certain difficulties. If none are checked, it is active in all difficulties."] = "勾选这些来让过滤器仅在对应难度激活, 如果没有勾选则将在所有难度激活"
+L["CheckBox Skin"] = "勾选框皮肤"
+L["Choose Export Format"] = "选择导出格式"
+L["Choose UIPARENT to prevent it from hiding with the unitframe."] = "使用UIPARENT来防止它随框体隐藏"
+L["Choose What To Export"] = "选择导出内容"
+L["Choose when you want the tooltip to show in combat. If a modifer is chosen, then you need to hold that down to show the tooltip."] = "战斗中如何显示鼠标提示. 如果选择了修饰键,你需要按住它来显示鼠标提示."
+L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."] = "如何显示鼠标提示. 如果选择了修饰键, 你需要按住它来显示鼠标提示."
+L["Class Backdrop"] = "生命条背景职业色"
+L["Class Castbars"] = "施法条职业色"
+L["Class Color Mentions"] = "职业颜色提示"
+L["Class Color Override"] = "职业色覆盖"
+L["Class Health"] = "生命条职业色"
+L["Class Power"] = "能量条职业色"
+L["Class Resources"] = "职业能量"
+L["Class Totems"] = "职业图腾"
+L["Clear Filter"] = "清空过滤器"
+L["Clear Search On Close"] = "关闭时清除搜索"
+L["Click Through"] = "点击穿透"
+L["Clickable Height"] = "可点击高度"
+L["Clickable Size"] = "可点击尺寸"
+L["Clickable Width / Width"] = "可点击宽度 / 姓名板宽度"
+L["Coding:"] = "编码:"
+L["Color Keybind Text when Out of Range, instead of the button."] = "当你超过射程时对键位文字着色而不是对按钮着色"
+L["Color Keybind Text"] = "键位文字着色"
+L["Color Override"] = "颜色覆盖"
+L["Color Turtle Buffs"] = "减伤类Buff的颜色"
+L["Color all buffs that reduce the unit's incoming damage."] = "减少目标受到伤害的所有增益的颜色"
+L["Color aurabar debuffs by type."] = "按类型显示光环条颜色"
+L["Color by Value"] = "根据数值染色"
+L["Color castbars by the class of player units."] = "按职业显示施法条颜色"
+L["Color castbars by the reaction type of non-player units."] = "按非玩家单位的声望显示施法条颜色"
+L["Color health by amount remaining."] = "按数值变化血量"
+L["Color health by classcolor or reaction."] = "按职业色显示血量"
+L["Color health by threat status."] = "按仇恨状态显示血量"
+L["Color of the actionbutton when not usable."] = "动作条按键不可用时的颜色"
+L["Color of the actionbutton when out of power (Mana, Rage)."] = true
+L["Color of the actionbutton when out of range."] = "当超出距离时动作条按键的颜色"
+L["Color of the actionbutton when usable."] = "动作条按键可用时的颜色"
+L["Color power by classcolor or reaction."] = "按职业色显示能量"
+L["Color power by threat status."] = "按仇恨状态显示能量"
+L["Color some texts use."] = "数值(非文字)使用的颜色"
+L["Color the health backdrop by class or reaction."] = "生命条背景色以职业色显示"
+L["Color the unit healthbar if there is a debuff that can be dispelled by you."] = "如果单位目标的减益光环可被驱散, 加亮显示其生命值"
+L["Color when the text is about to expire"] = "即将冷却完毕的数字颜色"
+L["Color when the text is in the days format."] = "以天显示的文字颜色"
+L["Color when the text is in the hours format."] = "以小时显示的文字颜色"
+L["Color when the text is in the minutes format."] = "以分显示的文字颜色"
+L["Color when the text is in the seconds format."] = "以秒显示的文字颜色"
+L["Colored Icon"] = "色块"
+L["Coloring (Specific)"] = "着色(具体)"
+L["Coloring"] = "着色"
+L["Colorize Selected Text"] = true
+L["Colors the border according to the Quality of the Item."] = "根据物品的稀有度对边框着色"
+L["Combat Icon"] = "战斗图标"
+L["Combat Override Key"] = "战斗中显示按键"
+L["CombatText Font"] = "战斗文字字体"
+L["Combo Point"] = "连击点"
+L["Comparison Font Size"] = "比较字体大小"
+L["Condensed"] = "紧凑"
+L["Configure Auras"] = "设置光环"
+L["Control enemy nameplates toggling on or off when in combat."] = "控制战斗中敌对姓名板的开启和关闭"
+L["Control friendly nameplates toggling on or off when in combat."] = "控制战斗中友方姓名板的开启和关闭"
+L["Controls how big of an area on the screen will accept clicks to target unit."] = "决定屏幕上一个多大的光环才允许通过点击选定到目标框体上"
+L["Controls the amount of decimals used in values displayed on elements like NamePlates and UnitFrames."] = "控制像姓名板和团队框架中各数值的小数位数"
+L["Controls the speed at which smoothed bars will be updated."] = "控制状态条平滑增减的速度."
+L["Controls how many seconds of inactivity has to pass before chat is faded."] = "控制聊天淡出前不活动时间(秒)"
+L["Cooldown Orientation"] = true
+L["Cooldown Text"] = "冷却文字"
+L["Cooldowns"] = "冷却"
+L["Copy From"] = "复制自"
+L["Copy Settings From"] = "复制设置"
+L["Copy settings from another unit."] = "从其他框架中复制设置"
+L["Core |cff1784d1E|r|cffe5e3e3lvUI|r options."] = "核心|cff1784d1E|r|cffe5e3e3lvUI|r配置"
+L["Count Font Size"] = "计数字体尺寸"
+L["Count xOffset"] = "计数X偏移"
+L["Count yOffset"] = "计数Y偏移"
+L["Create Custom Text"] = "创建自定义文字"
+L["Create Filter"] = "新建过滤器"
+L["Create a filter, once created a filter can be set inside the buffs/debuffs section of each unit."] = "新建一个过滤器, 一旦新建, 每个单位的增益/减益都能使用"
+L["Credits"] = "呜谢"
+L["Crop Icons"] = "裁剪图标"
+L["Currency Format"] = "货币格式"
+L["Current - Max | Percent"] = "当前值 - 最大值 | 百分比"
+L["Current - Max"] = "当前值 - 最大值"
+L["Current - Percent (Remaining)"] = "当前值 - 百分比(剩余)"
+L["Current - Percent"] = "当前值 - 百分比"
+L["Current - Remaining"] = "当前值 - 剩余值"
+L["Current / Max"] = "当前值 / 最大值"
+L["Current Level"] = "当前等级"
+L["Current"] = "当前值"
+L["Curse Effect"] = true
+L["Cursor Anchor Offset X"] = "鼠标锚点X偏移"
+L["Cursor Anchor Offset Y"] = "鼠标锚点Y偏移"
+L["Cursor Anchor Type"] = "鼠标锚点类型"
+L["Cursor Anchor"] = "鼠标锚点"
+L["Custom Backdrop"] = "自定义背景"
+L["Custom Color"] = "自定义颜色"
+L["Custom Dead Backdrop"] = "自定义死亡背景"
+L["Custom Faction Colors"] = "自定义声望颜色"
+L["Custom Texts"] = "自定义字体"
+L["Custom Texture"] = "自定义材质"
+L["Custom Timestamp Color"] = "自定义时间戳颜色"
+L["Cutaway Bars"] = "掉血动画"
+L["Darken Inactive"] = "未激活时暗化"
+L["DataBars"] = "数据条"
+L["DataTexts"] = "信息文字"
+L["Datatext Panel (Left)"] = "左侧信息框"
+L["Datatext Panel (Right)"] = "右侧信息框"
+L["Date Format"] = true
+L["Days"] = "天"
+L["Debuff Highlighting"] = "减益光环加亮显示"
+L["Debug Tools"] = "除错工具"
+L["Decimal Length"] = "小数位数"
+L["Decimal Threshold"] = "小数阈值"
+L["Decode Text"] = "解码文字"
+L["Default Color"] = "默认颜色"
+L["Default Font"] = "预设字体"
+L["Default Settings"] = "默认设置"
+L["Deficit"] = "亏损值"
+L["Defines how the group is sorted."] = "定义组排序方式"
+L["Defines the sort order of the selected sort method."] = "定义排序方式的排序方向"
+L["Delete Filter"] = "删除过滤器"
+L["Delete a created filter, you cannot delete pre-existing filters, only custom ones."] = "删除一个创建的过滤器, 你不能删除内建的过滤器, 只能删除你自已创建的"
+L["Desaturate Cooldowns"] = "冷却中褪色"
+L["Desaturate Junk Items"] = "垃圾物品褪色"
+L["Desaturated Icon"] = "图标褪色"
+L["Descending"] = "降序"
+L["Detach From Frame"] = "从框架分离"
+L["Detached Width"] = "分离宽度"
+L["Direction the bag sorting will use to allocate the items."] = "整理背包时物品排序方向"
+L["Direction the bar moves on gains/losses"] = "条增加/减少时的方向"
+L["Direction the health bar moves when gaining/losing health."] = "生命条的增减方向"
+L["Disable Bag Sort"] = "禁用背包排序"
+L["Disable Bank Sort"] = "禁用银行排序"
+L["Disable Debuff Highlight"] = "禁用减益高亮"
+L["Disabled Blizzard Frames"] = "禁用暴雪框架"
+L["Disabled Blizzard"] = "禁用暴雪框架"
+L["Disables the focus and target of focus unitframes."] = "禁用焦点和目标的焦点框架"
+L["Disables the player and pet unitframes."] = "禁用玩家和宠物框架"
+L["Disables the target and target of target unitframes."] = "禁用目标和目标的目标框架"
+L["Disconnected"] = "离线"
+L["Disease Effect"] = true
+L["Display Frames"] = "显示框架"
+L["Display Item Level"] = "显示物品等级"
+L["Display Player"] = "显示玩家"
+L["Display Target"] = "显示目标"
+L["Display Text"] = "显示文本"
+L["Display a healer icon over known healers inside battlegrounds or arenas."] = "战场或竞技场中, 为已确认为治疗的玩家标上补职图标"
+L["Display a panel across the bottom of the screen. This is for cosmetic only."] = "显示跨越屏幕底部的面板,仅仅是用于装饰."
+L["Display a panel across the top of the screen. This is for cosmetic only."] = "显示跨越屏幕顶部的面板,仅仅是用于装饰."
+L["Display a spark texture at the end of the castbar statusbar to help show the differance between castbar and backdrop."] = "在施法状态条的末端显示一个火花材质来区分施法条和背景条"
+L["Display an exclamation mark on items that starts a quest."] = true
+L["Display battleground messages in the middle of the screen."] = "屏幕中间显示战场信息"
+L["Display bind names on action buttons."] = "在动作条按钮上显示键位名称"
+L["Display cooldown text on anything with the cooldown spiral."] = "显示技能冷却时间"
+L["Display data panels below the chat, used for datatexts."] = "显示聊天框下方的信息框"
+L["Display emotion icons in chat."] = "在聊天中显示表情图标"
+L["Display guild ranks if a unit is guilded."] = "当目标有公会时显示其在公会内的等级"
+L["Display how many of a certain item you have in your possession."] = "显示当前物品在你身上的数量."
+L["Display macro names on action buttons."] = "在动作条按钮上显示宏名称"
+L["Display minimap panels below the minimap, used for datatexts."] = "显示小地图下方的信息框"
+L["Display player titles."] = "显示玩家头衔"
+L["Display reminder bar on the minimap."] = true
+L["Display the castbar icon inside the castbar."] = "在施法条内显示图标"
+L["Display the castbar inside the information panel, the icon will be displayed outside the main unitframe."] = "如果关闭施法条内显示图标,你可以自定义施法条外图标的大小和位置"
+L["Display the hyperlink tooltip while hovering over a hyperlink."] = "鼠标指向链接时显示鼠标提示"
+L["Display the junk icon on all grey items that can be vendored."] = "为所有能够卖店的灰色物品显示垃圾图标"
+L["Display the name of the unit on the chat bubble."] = true
+L["Display the npc ID when mousing over a npc tooltip."] = "在指向NPC时显示NPC ID."
+L["Display the spell or item ID when mousing over a spell or item tooltip."] = "在鼠标提示中显示技能或物品的ID."
+L["Display the target of your current cast. Useful for mouseover casts."] = "显示你当前的施法目标. 可以转换成鼠标滑过类型"
+L["Display tick marks on the castbar for channelled spells. This will adjust automatically for spells like Drain Soul and add additional ticks based on haste."] = "若为需引导的法术, 在施法条上显示每跳时间点. 这将针对吸取灵魂这类的法术根据急速自动调整显示每跳时间点和额外跳数."
+L["Displayed server time."] = true
+L["Displays a detailed report of every item sold when enabled."] = "启用后显示包含每个物品金额的详细报告"
+L["Displays item level on equippable items."] = "显示可装备物品的物品等级"
+L["Display Types"] = true
+L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."] = "不显示高于此时间(单位:秒)的光环.设置为0以禁用"
+L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."] = "不显示低于此时间(单位:秒)的光环.设置为0以禁用"
+L["Donations:"] = "捐款:"
+L["Down"] = "下"
+L["Dropdown CheckBox Skin"] = true
+L["Dungeon & Raid Filter"] = "地下城与团队副本过滤器"
+L["Duration Enable"] = "启用持续时间"
+L["Duration Font Size"] = "持续时间字体大小"
+L["Duration Reverse"] = "持续时间反转"
+L["Duration Text"] = "持续时间文字"
+L["Duration"] = "持续时间"
+L["Editbox History Size"] = true
+L["ELVUI_CREDITS"] = "我想透过这个特别方式, 向那些协助测试、编码及透过捐款协助过我的人表达感谢, 请曾提供协助的朋友至论坛传私讯给我, 我会将你的名字添加至此处"
+L["ENEMY_NPC"] = "敌对NPC"
+L["ENEMY_PLAYER"] = "敌对玩家"
+L["Elite Icon"] = "精英标志"
+L["Emotion Icons"] = "表情图标"
+L["Enable Custom Color"] = "启用自定义颜色"
+L["Enable the use of separate size options for the right chat panel."] = "为左右两个聊天框设置不同的材质和尺寸"
+L["Enable/Disable the Bag-Bar."] = "启用/禁用背包条"
+L["Enable/Disable the all-in-one bag."] = "启用/禁用整合背包"
+L["Enable/Disable the loot frame."] = "开/关物品掉落框架"
+L["Enable/Disable the loot roll frame."] = "开/关掷骰子框架"
+L["Enable/Disable the minimap. |cffFF0000Warning: This will prevent you from seeing the consolidated buffs bar, and prevent you from seeing the minimap datatexts.|r"] = true
+L["Enable/Disable the scaling of targetted nameplates."] = true
+L["Enables the ElvUI Raid Control panel."] = "启用ElvUI团队控制面板"
+L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."] = "启用后将可以在整个团队内排序, 但你不再可以区分不同小队"
+L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."] = "启用后翻转未满团队的队伍顺序(起始方向)"
+L["Enabling this will check your health amount."] = "启用后将检查你的血量"
+L["Enabling this will check your power amount."] = "启用后将检查你的能量"
+L["Enchanting"] = "附魔"
+L["Enemy Aura Type"] = "敌对光环类型"
+L["Enemy Combat Toggle"] = "敌对战斗开关"
+L["Enemy NPC Frames"] = true
+L["Enemy Player Frames"] = true
+L["Enemy"] = "敌对"
+L["Engineering"] = "工程"
+L["Enhanced PVP Messages"] = "PVP增强信息"
+L["Equipped Item Color"] = "已装备物品颜色"
+L["Equipped Item"] = "已装备物品"
+L["Error decoding data. Import string may be corrupted!"] = "解码错误.导入的字符串可能已损坏!"
+L["Error exporting profile!"] = "导出配置文件失败"
+L["Exclude Name"] = "排除名字"
+L["Excluded Names"] = "排除的名字"
+L["Excluded names will not be class colored."] = "排除的名字将不会使用职业颜色"
+L["Expiring"] = "即将冷却完毕"
+L["Export Profile"] = "导出配置文件"
+L["Exported"] = "已导出"
+L["FRIENDLY_NPC"] = "友方NPC"
+L["FRIENDLY_PLAYER"] = "友方玩家"
+L["Fade Chat Toggles"] = true
+L["Fade Out Delay"] = "渐隐延迟"
+L["Fade Out"] = "淡出时长"
+L["Fade Tabs No Backdrop"] = "隐藏拖出的聊天框"
+L["Fade Threshold"] = "阈值渐隐"
+L["Fade Undocked Tabs"] = "隐藏分离的聊天框"
+L["Fade the chat text when there is no activity."] = "隐藏聊天框内长期不活动的文字"
+L["Fader"] = "隐藏"
+L["Fades the buttons that toggle chat windows when that window has been toggled off."] = true
+L["Fades the text on chat tabs that are docked in a panel where the backdrop is disabled."] = "当你把一个聊天框拖出聊天背景框的时候会自动隐藏掉,注意这个聊天框并没有被删除,关闭该选项你可以重新找到它"
+L["Fades the text on chat tabs that are not docked at the left or right chat panel."] = "当你把一个聊天框设置为分离状态时会自动隐藏掉,注意这个聊天框并没有被删除,关闭该选项你可以重新找到它"
+L["Fill"] = "填充"
+L["Filled"] = "全长"
+L["Filter Priority"] = "过滤器优先级"
+L["Filter Search"] = "筛选"
+L["Filter Type"] = "过滤器类型"
+L["Filter already exists!"] = "过滤器已存在!"
+L["Filters Page"] = "过滤器界面"
+L["Filters are not allowed to have commas in their name. Stripping commas from filter name."] = "过滤器的名字中不允许有逗号, 已将逗号移除."
+L["Flash"] = "闪光"
+L["Fluid Position Buffs on Debuffs"] = "增益流动定位在减益上"
+L["Fluid Position Debuffs on Buffs"] = "减益流动定位在增益上"
+L["Flyout Direction"] = "飞出方向"
+L["Flyout Spacing"] = true
+L["Focus"] = "焦点"
+L["FocusTarget"] = "焦点的目标"
+L["Font Outline"] = "字体描边"
+L["Font"] = "字体"
+L["Fonts"] = "字体"
+L["Force Off"] = "强制关闭"
+L["Force On"] = "强制开启"
+L["Force Reaction Color"] = "强制声望颜色"
+L["Force the frames to show, they will act as if they are the player frame."] = "强制框架显示"
+L["Forces Debuff Highlight to be disabled for these frames"] = "为这些框架强制禁用减益高亮"
+L["Forces Mouseover Glow to be disabled for these frames"] = "在这些框体中强制关闭鼠标指向高亮"
+L["Forces Target Glow to be disabled for these frames"] = "为这些框体强制禁用目标高亮"
+L["Forces reaction color instead of class color on units controlled by players."] = "对于玩家控制的角色强制使用声望颜色而不是职业颜色"
+L["Format"] = "格式"
+L["Frame Glow"] = "框体高亮"
+L["Frame Level"] = "框架层次"
+L["Frame Orientation"] = "框架方向"
+L["Frame Strata"] = "框架层级"
+L["Frequent Updates"] = "频繁更新"
+L["Friendly Aura Type"] = "友好光环类型"
+L["Friendly Combat Toggle"] = "友方战斗开关"
+L["Friendly NPC Frames"] = true
+L["Friendly Player Frames"] = true
+L["Friendly"] = "友好"
+L["Full Overlay"] = "全覆盖"
+L["Full"] = "满"
+L["GM Chat"] = "GM对话框"
+L["GPS Arrow"] = "位置箭头"
+L["Gems"] = "珠宝"
+L["General Options"] = "常规选项"
+L["Global (Account Settings)"] = "全局(账号设置)"
+L["Global Fade Transparency"] = "全局透明渐隐"
+L["Global"] = "全局"
+L["Glow"] = "边框发光"
+L["Gold Format"] = "金币格式"
+L["Good Color"] = "正常颜色"
+L["Good Scale"] = "正常缩放"
+L["Good Transition Color"] = "正常过渡颜色"
+L["Good"] = "安全"
+L["Gossip Frame"] = "闲谈"
+L["Group By"] = "队伍排列方式"
+L["Group Spacing"] = "小队间隔"
+L["Grouping & Sorting"] = "分组与排序"
+L["Groups Per Row/Column"] = "每行/列的队伍数"
+L["Growth Direction"] = "增长方向"
+L["Growth X-Direction"] = "X方向生长"
+L["Growth Y-Direction"] = "Y方向生长"
+L["Growth direction from the first unitframe."] = "增长方向从第一个头像框架开始"
+L["Guide:"] = "指导:"
+L["Guild Ranks"] = "公会等级"
+L["Guild Registrar"] = "公会注册"
+L["HH:MM Threshold"] = "时:分 阈值"
+L["HH:MM"] = "时:分"
+L["Header Font Size"] = "标题名字大小"
+L["Heal Prediction"] = "治疗量预估"
+L["Healer Icon"] = "治疗图标"
+L["Health Backdrop Multiplier"] = "生命条背景倍数"
+L["Health Backdrop"] = "生命条背景"
+L["Health Bar"] = "生命条"
+L["Health Border"] = "生命条边框"
+L["Health By Value"] = "生命条颜色依数值变化"
+L["Health Color"] = "血量颜色"
+L["Health Length"] = "血量变化时长"
+L["Health Threshold"] = "血量阈值"
+L["Health"] = "生命条"
+L["Height Multiplier"] = "高度倍增"
+L["Height of the objective tracker. Increase size to be able to see more objectives."] = "任务框体的高度.增加大小以看到更多目标"
+L["Height"] = "高"
+L["Help Frame"] = "帮助"
+L["Herbalism"] = "草药"
+L["Here you can add items or search terms that you want to be excluded from sorting. To remove an item just click on its name in the list."] = "你可以在这里添加你想在排序中排除的物品或者匹配语法.在列表中点击他们的名字来移除一个物品"
+L["Hide At Max Level"] = "在最高等级时隐藏"
+L["Hide Both"] = "全部隐藏"
+L["Hide Error Text"] = "隐藏错误文字"
+L["Hide Frame"] = "隐藏框架"
+L["Hide In Combat"] = "战斗中隐藏"
+L["Hide In Vehicle"] = "骑乘时隐藏"
+L["Hide Spell Name"] = "隐藏法术名字"
+L["Hide Time"] = "隐藏时间"
+L["Hide specific sections in the datatext tooltip."] = "隐藏信息文字鼠标提示中的特定模块"
+L["Hide tooltip while in combat."] = "战斗时不显示提示"
+L["Hides the red error text at the top of the screen while in combat."] = "战斗中隐藏屏幕顶部红字错误信息"
+L["History Size"] = true
+L["History"] = true
+L["Horizontal Spacing"] = "水平间隔"
+L["Horizontal"] = "水平"
+L["Hours"] = "时"
+L["Hover Highlight"] = "鼠标指向高亮"
+L["Hover"] = "鼠标指向"
+L["How long the cutaway health will take to fade out."] = "血量变化高亮淡出过程所需的时间"
+L["How long the cutaway power will take to fade out."] = "能量变化高亮淡出过程所需的时间"
+L["How many seconds the castbar should stay visible after the cast failed or was interrupted."] = "在施法失败或被打断时施法条保持可见的秒数"
+L["How much time before the cutaway health starts to fade."] = "血量变化高亮淡出前所需要的时间"
+L["How much time before the cutaway power starts to fade."] = "能量变化高亮淡出前所需要的时间"
+L["Hyperlink Hover"] = "链接悬停"
+L["Icon Frame"] = true
+L["Icon Inside Castbar"] = "施法条内的图标"
+L["Icon Only"] = true
+L["Icon Position"] = "图标位置"
+L["Icon Size"] = "图标尺寸"
+L["Icon"] = "图标"
+L["Icon: BOTTOM"] = "图标: 底部"
+L["Icon: BOTTOMLEFT"] = "图标: 底部左侧"
+L["Icon: BOTTOMRIGHT"] = "图标: 底部右侧"
+L["Icon: LEFT"] = "图标: 左侧"
+L["Icon: RIGHT"] = "图标: 右侧"
+L["Icon: TOP"] = "图标: 顶部"
+L["Icon: TOPLEFT"] = "图标: 顶部左侧"
+L["Icon: TOPRIGHT"] = "图标: 顶部右侧"
+L["Icons and Text (Short)"] = "图标和文字(短)"
+L["Icons and Text"] = "图标和文字"
+L["If enabled then it checks if auras are missing instead of being present on the unit."] = "启用后将会检查光环是否缺失而不是光环是否存在."
+L["If enabled then it will require all auras to activate the filter. Otherwise it will only require any one of the auras to activate it."] = "启用后要求满足所有光环. 否则只要求任一光环存在即可激活."
+L["If enabled then it will require all cooldowns to activate the filter. Otherwise it will only require any one of the cooldowns to activate it."] = "启用后要求满足所有冷却. 否则只要求任一冷却存在即可激活."
+L["If enabled then the filter will activate if the unit is casting anything."] = true
+L["If enabled then the filter will activate if the unit is channeling anything."] = true
+L["If enabled then the filter will activate if the unit is not casting anything."] = true
+L["If enabled then the filter will activate if the unit is not channeling anything."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or higher than this value."] = "启用后过滤器仅在单位等级大于等于该值的时候激活."
+L["If enabled then the filter will only activate if the level of the unit is equal to or lower than this value."] = "启用后过滤器仅在单位等级小于等于该值的时候激活."
+L["If enabled then the filter will only activate if the level of the unit matches this value."] = "启用后过滤器仅在单位等级符合该值的时候激活."
+L["If enabled then the filter will only activate if the level of the unit matches your own."] = "启用后过滤器仅在单位等级符合你的等级的时候激活."
+L["If enabled then the filter will only activate if the unit is casting interruptible spells."] = "启用后过滤器仅在单位施放可打断技能的时候激活."
+L["If enabled then the filter will only activate if the unit is casting not interruptible spells."] = "启用后过滤器仅在单位施放不可打断技能的时候激活."
+L["If enabled then the filter will only activate if the unit is not casting or channeling one of the selected spells."] = "启用后过滤器仅在单位未施放或引导任一勾选的技能时激活."
+L["If enabled then the filter will only activate when you are in combat."] = "启用后过滤器仅在你在战斗中的时候激活."
+L["If enabled then the filter will only activate when you are not targeting the unit."] = "启用后过滤器仅对非当前目标激活."
+L["If enabled then the filter will only activate when you are out of combat."] = "启用后过滤器仅在你不在战斗中的时候激活."
+L["If enabled then the filter will only activate when you are targeting the unit."] = "启用后过滤器仅对当前目标激活."
+L["If enabled then the filter will only activate when you have a target."] = true
+L["If not set to 0 then override the size of the aura icon to this."] = "如果不为0, 此值将覆盖光环图标的尺寸"
+L["If the aura is listed with a number then you need to use that to remove it from the list."] = "如果光环和一个数一起列出你需要用它来将其移出列表"
+L["If this list is empty, and if 'Interruptible' is checked, then the filter will activate on any type of cast that can be interrupted."] = "如果列表为空, 并且'可打断'被选中, 那么过滤器会在任何可被打断的施法时激活"
+L["If this threshold is used then the health of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = "如果这个阈值被设置则单位的血量需要比设定值更高才会将过滤器激活. 设为0以禁用."
+L["If this threshold is used then the health of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = "如果这个阈值被设置则单位的血量需要比设定值更低才会将过滤器激活. 设为0以禁用."
+L["If this threshold is used then the power of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = "如果这个阈值被设置则单位的能量需要比设定值更高才会将过滤器激活. 设为0以禁用."
+L["If this threshold is used then the power of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = "如果这个阈值被设置则单位的能量需要比设定值更低才会将过滤器激活. 设为0以禁用."
+L["If you have a lot of 3D Portraits active then it will likely have a big impact on your FPS. Disable some portraits if you experience FPS issues."] = "如果你同时激活了很多3D头像你很可能有帧数的影响.如果你有这方面的问题请禁用一部分头像"
+L["If you have any plugins supporting this feature installed you can find them in the selection dropdown to the right."] = "如果你有任何已安装的插件支持该功能, 你可以在下面的下拉菜单找到它们"
+L["If you unlock actionbars then trying to move a spell might instantly cast it if you cast spells on key press instead of key release."] = "如果不锁定动作条, 那么当你试图移动技能时你可能会在鼠标按下技能键时使用技能"
+L["Ignore UI Scale Popup"] = "忽略UI缩放提示"
+L["Ignore mouse events."] = "忽略鼠标事件"
+L["Ignored Items and Search Syntax (Global)"] = "被忽略的物品和搜索语法(全局)"
+L["Ignored Items and Search Syntax (Profile)"] = "被忽略的物品和搜索语法(配置文件)"
+L["Import Profile"] = "导入配置文件"
+L["Importing"] = "正在导入"
+L["Inactivity Timer"] = "不活跃时间"
+L["Index"] = "索引"
+L["Indicate whether buffs you cast yourself should be separated before or after."] = "将你自身施放的增益从整体增益之前或之后分离出来"
+L["InfoPanel Border"] = "信息面板边框"
+L["Information Panel"] = "信息面板"
+L["Inherit Global Fade"] = "继承全局渐隐"
+L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."] = "继承全局渐隐, 鼠标悬浮、目标、焦点、损失血量、进入战斗会减低不透明度.否则会为全局透明度使用一般动作条的设置"
+L["Inset"] = "插入"
+L["Inside Information Panel"] = "插入信息面板"
+L["Install"] = "安装"
+L["Instance Difficulty"] = "副本难度"
+L["Instance Type"] = "副本类型"
+L["Interruptable"] = "可打断颜色"
+L["Interruptible"] = "可打断"
+L["Invert Colors"] = "反转颜色"
+L["Invert Grouping Order"] = "反转队伍排序"
+L["Invert foreground and background colors."] = "反转前景色和背景色."
+L["Is Casting Anything"] = "正在施法"
+L["Is Channeling Anything"] = "正在引导"
+L["Is Targeted"] = "当前目标"
+L["Item Count Font"] = "物品数目字体"
+L["Item Count"] = "物品数量"
+L["Item Level Threshold"] = "物品等级阈值"
+L["Item Level"] = "物品等级"
+L["JustifyH"] = "水平对齐"
+L["Key Down"] = "按下施法"
+L["Keybind Mode"] = "键位设置模式"
+L["Keybind Text Position"] = "快捷键文字位置"
+L["Keybind Text X-Offset"] = "快捷键文字X偏移"
+L["Keybind Text Y-Offset"] = "快捷键文字Y偏移"
+L["Keybind Text"] = "键位文字"
+L["Keyword Alert"] = "关键字警报"
+L["Keywords"] = "关键字"
+L["LBF Support"] = true
+L["LEVEL_BOSS"] = "对首领请设置为-1, 或者设为0以禁用."
+L["LFD Frame"] = true
+L["LFG Queue"] = "随机队列"
+L["LFR Frame"] = true
+L["Latency"] = "延迟"
+L["Leatherworking"] = "制皮"
+L["Left Only"] = "仅显示左边"
+L["Left to Right"] = "左到右"
+L["Left"] = "左"
+L["Limit the number of rows or columns."] = "最大行数或列数"
+L["List of words to color in chat if found in a message. If you wish to add multiple words you must seperate the word with a comma. To search for your current name you can use %MYNAME%.\n\nExample:\n%MYNAME%, ElvUI, RBGs, Tank"] = "如果在聊天信息中发现如下文字会自动上色该文字. 如果你需要添加多个词必须用逗号分开. 搜索你的名字可使用 %MYNAME%.\n\n例如:\n%MYNAME%, ElvUI, RBGs, Tank"
+L["Location Text"] = "所在位置"
+L["Lock Positions"] = "锁定位置"
+L["Log Taints"] = "错误记录"
+L["Log the main chat frames history. So when you reloadui or log in and out you see the history from your last session."] = "进行聊天记录,当你重载,登录和退出时会恢复你最后一次会话"
+L["Login Message"] = "登陆信息"
+L["Loot Frames"] = "拾取"
+L["Loot Roll"] = "掷骰"
+L["Losing Threat"] = "失去仇恨"
+L["Low Health Threshold"] = "低生命值阈值"
+L["Low Threat"] = "低仇恨"
+L["Low Threshold"] = "冷却时间阈值"
+L["Lower numbers mean a higher priority. Filters are processed in order from 1 to 100."] = "更低的数值意味着更高的优先级. 过滤器将按照1至100的顺序进行."
+L["MM:SS Threshold"] = "分:秒 阈值"
+L["MM:SS"] = "分:秒"
+L["Macro Text"] = "宏名称"
+L["Magic Effect"] = true
+L["Main Tanks / Main Assist"] = "主坦克/主助理"
+L["Main backdrop color of the UI."] = "界面背景主色"
+L["Main border color of the UI."] = "界面边框主色"
+L["Main statusbar texture."] = "主状态条材质"
+L["Make textures transparent."] = "材质透明"
+L["Make the unitframe glow yellow when it is below this percent of health, it will glow red when the health value is half of this value."] = "姓名板在此设定值下会变黄色, 在设定值一半以下会变红色"
+L["Make the world map smaller."] = "让世界地图更小"
+L["Map Opacity When Moving"] = "移动时地图透明度"
+L["Maps"] = "地图"
+L["Match Frame Width"] = "匹配框体宽度"
+L["Match Player Level"] = "符合玩家等级"
+L["Max Alpha"] = "最大透明度"
+L["Max Bars"] = "最多"
+L["Max Lines"] = true
+L["Max Overflow"] = "最大治疗吸收盾"
+L["Max Wraps"] = "每行最大数"
+L["Max amount of overflow allowed to extend past the end of the health bar."] = "显示在生命值条末端的治疗吸收盾的最大量"
+L["Maximum Duration"] = "最大持续时间"
+L["Maximum Level"] = "最高等级"
+L["Maximum Time Left"] = "最大时间剩余"
+L["Media"] = "材质"
+L["Method to sort by."] = "排序方式"
+L["Middle Click - Set Focus"] = "鼠标中键 - 设置焦点"
+L["Middle clicking the unit frame will cause your focus to match the unit."] = "鼠标中键点击单位框架设置焦点"
+L["Middle"] = "中间"
+L["Min Alpha"] = "最小透明度"
+L["Minimap Mouseover"] = "小地图鼠标滑过"
+L["Minimap Panels"] = "小地图栏"
+L["Minimum Duration"] = "最小持续时间"
+L["Minimum Level"] = "最低等级"
+L["Minimum Time Left"] = "最小时间剩余"
+L["Mining"] = "采矿"
+L["Minutes"] = "分"
+L["Mirror Timers"] = "镜像计时器"
+L["Misc Frames"] = "其他"
+L["Missing"] = "缺失"
+L["Modulating Blend"] = "忽略Alpha通道"
+L["Module Control"] = "模块控制"
+L["Module Copy"] = "模块复制"
+L["Module Reset"] = "模块重置"
+L["Money Format"] = "金币格式"
+L["Mouse Over"] = "鼠标滑过显示"
+L["Mouseover Glow"] = "鼠标指向边框"
+L["Mouseover Highlight"] = "鼠标指向高亮"
+L["Mouseover"] = "鼠标滑过显示"
+L["Multi-Monitor Support"] = "多显示器支持"
+L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."] = "根据此值增加背景的高度或宽度. 一般用来在一个背景框里放置多条动作条"
+L["NPC IDs"] = "NPC ID"
+L["Name Color"] = "姓名颜色"
+L["Name Colored Glow"] = true
+L["Name Font"] = "名称字体"
+L["Name Only"] = "仅姓名"
+L["Name"] = "姓名"
+L["NamePlate Style Filters"] = "姓名板样式过滤器"
+L["NamePlates"] = "姓名板"
+L["Nameplate"] = "姓名板"
+L["Neutral"] = "中立"
+L["Never Hide"] = "从不隐藏"
+L["No Alert In Combat"] = "战斗中不警报"
+L["No Duration"] = true
+L["No Sorting"] = "不排序"
+L["Non-Interruptable"] = "不可打断"
+L["Non-Target Alpha"] = "非目标透明度"
+L["Not Casting Anything"] = "未施法"
+L["Not Channeling Anything"] = "未引导"
+L["Not Spell"] = "非法术"
+L["Not Targeted"] = "非目标"
+L["Not Usable"] = "不可用"
+L["Not valid spell id"] = "不正确的技能ID"
+L["Num Rows"] = "行数"
+L["Number of Groups"] = "队伍数目"
+L["Number of messages you scroll for each step."] = "每次滚动的聊天信息数目"
+L["Number of repeat characters while in combat before the chat editbox is automatically closed. Set to 0 to disable."] = "当你在战斗中按下技能键时,有可能你的输入框还处于打开状态,这个功能可以在你按下技能键并且在输入框中输入下列个数字符串却没有放出技能时帮你自动关闭输入框, 设为0以禁用"
+L["Number of time in seconds to scroll down to the bottom of the chat window if you are not scrolled down completely."] = "聊天框滚动到底部所需要的滚动时间(秒)"
+L["Objective Frame Height"] = "任务框架高度"
+L["Off Cooldown"] = "冷却外"
+L["Offset of the powerbar to the healthbar, set to 0 to disable."] = "偏移能量条与生命条的位置, 设为0代表停用"
+L["Offset position for text."] = "偏移文本的位置"
+L["Offset"] = "偏移"
+L["On Cooldown"] = "冷却中"
+L["Only Match SpellID"] = "仅匹配法术ID"
+L["Only show when the unit is not in range."] = true
+L["Only show when you are mousing over a frame."] = true
+L["Other Filter"] = "其他过滤器"
+L["Other's First"] = "他人光环优先"
+L["Others"] = "他人的"
+L["Out of Power"] = "能量不足"
+L["Out of Range"] = "超出范围"
+L["Over Health Threshold"] = "高于血量阈值"
+L["Over Power Threshold"] = "高于能量阈值"
+L["Overlay Alpha"] = "重叠透明度"
+L["Overlay"] = "重叠显示"
+L["Overnuking"] = true
+L["Override any custom visibility setting in certain situations, EX: Only show groups 1 and 2 inside a 10 man instance."] = "覆盖可见性的设定, 例如: 在10人副本里只显示1队和2队"
+L["Override the default class color setting."] = "覆盖默认的职业色设置"
+L["Owners Name"] = "所有者姓名"
+L["PVP Trinket"] = "PvP饰品"
+L["Panel Backdrop"] = "聊天框背景"
+L["Panel Height"] = "聊天框高度"
+L["Panel Texture (Left)"] = "聊天框材质(左)"
+L["Panel Texture (Right)"] = "聊天框材质(右)"
+L["Panel Transparency"] = "面板透明"
+L["Panel Width (Bags)"] = "背包面板宽度"
+L["Panel Width (Bank)"] = "银行面板宽度"
+L["Panel Width"] = "聊天框宽度"
+L["Panels"] = "面板"
+L["Parent"] = "跟随框架"
+L["Party / Raid"] = "小队/团队"
+L["Party Only"] = "仅小队"
+L["Party Pets"] = "队伍宠物"
+L["Party Targets"] = "队伍目标"
+L["Per Row"] = "每行"
+L["Percent"] = "百分比"
+L["Personal"] = "自己的"
+L["Pet Name"] = "宠物名字"
+L["Pet"] = "宠物"
+L["PetTarget"] = "宠物的目标"
+L["Petition Frame"] = "回报GM"
+L["Pick Up Action Key"] = true
+L["Player Frame Aura Bars"] = "玩家框架光环条"
+L["Player Health"] = "玩家血量"
+L["Player Out of Combat"] = "玩家不在战斗中"
+L["Player Target"] = "玩家目标"
+L["Player Titles"] = "玩家头衔"
+L["Player in Combat"] = "玩家在战斗中"
+L["Player"] = "玩家"
+L["Plugin"] = "插件"
+L["Poison Effect"] = true
+L["Portrait"] = "头像"
+L["Position Buffs on Debuffs"] = "增益定位在减益上"
+L["Position Debuffs on Buffs"] = "减益定位在增益上"
+L["Position of the Chat EditBox, if datatexts are disabled this will be forced to be above chat."] = "聊天输入框位置,如果底部的信息文字被禁用的话,将会强制显示在聊天框顶部."
+L["Position"] = "位置"
+L["Power Threshold"] = "能量阈值"
+L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."] = "NPC目标将隐藏能量文字"
+L["Power"] = "能量条"
+L["Powers"] = "能量"
+L["Prevent the same messages from displaying in chat more than once within this set amount of seconds, set to zero to disable."] = "屏蔽设定时间(秒)内的重复聊天信息, 0为禁用此功能"
+L["Primary Texture"] = "主要材质"
+L["Priority"] = "优先级"
+L["Private (Character Settings)"] = "个人(角色配置)"
+L["Profession Bags"] = "专业背包"
+L["Profile Name"] = "配置文件名称"
+L["Profile Specific"] = "角色专用"
+L["Profile imported successfully!"] = "配置文件导入成功"
+L["Profile"] = "配置文件"
+L["Progress Bar"] = "进度条"
+L["Puts coordinates on the world map."] = "在世界地图上显示坐标"
+L["PvP Frames"] = "PvP框架"
+L["PvP Icon"] = true
+L["PvP Queue"] = true
+L["PvP Text"] = "PvP文字"
+L["Quest Frames"] = "任务"
+L["Quest Starter"] = "任务初始道具"
+L["Quiver"] = true
+L["RAID_CONTROL"] = "团队管理"
+L["RL / ML Icons"] = true
+L["Raid Difficulty"] = "副本难度"
+L["Raid Frame"] = "团队"
+L["Raid Icon"] = "团队图标"
+L["Raid Only"] = "仅团队"
+L["Raid Pet"] = "团队宠物框架"
+L["Raid-40"] = "40人团队框架"
+L["Raid-Wide Sorting"] = "全团队排序"
+L["RaidDebuff Indicator"] = "副本减益光环"
+L["Range"] = "范围"
+L["Rapidly update the health, uses more memory and cpu. Only recommended for healing."] = "实时更新生命值会占用更多的内存的和CPU, 只推荐治疗角色开启"
+L["Reaction Castbars"] = "声望施法条"
+L["Reaction Colors"] = "声望颜色"
+L["Reaction Type"] = "声望类型"
+L["Reactions"] = "声望"
+L["Ready Check Icon"] = "就位确认图标"
+L["Realm Time"] = true
+L["Remaining / Max"] = "剩余值 / 最大值"
+L["Remaining Time"] = true
+L["Remaining"] = "剩余值"
+L["Reminder"] = true
+L["Remove Backdrop"] = "去除背景"
+L["Remove Name"] = true
+L["Remove Spell ID or Name"] = "移除技能ID或者名字"
+L["Remove Spell"] = "移除技能"
+L["Remove SpellID"] = "移除技能ID"
+L["Remove a Name from the list."] = true
+L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."] = "从过滤器中移除一个技能. 当过滤器中的技能名字中有ID时使用技能ID"
+L["Remove a spell from the filter."] = "从过滤器中移除一个技能"
+L["Replace Blizzard Fonts"] = "替代暴雪字体"
+L["Replaces the default Blizzard fonts on various panels and frames with the fonts chosen in the Media section of the ElvUI Options. NOTE: Any font that inherits from the fonts ElvUI usually replaces will be affected as well if you disable this. Enabled by default."] = "用ElvUI字体设置代替暴雪原有字体设置,如果禁用有可能导致你的UI出问题,默认开启开选项"
+L["Reposition Window"] = "重置窗口位置"
+L["Require All"] = "要求全部"
+L["Require Target"] = true
+L["Require holding the Alt key down to move cursor or cycle through messages in the editbox."] = "开启该选项使你在查看聊天历史记录时需要按住Alt+上下键,如果关闭则直接按上下键即可"
+L["Reset Anchors"] = "重置定位"
+L["Reset Aura Filters"] = "重置光环过滤器"
+L["Reset Editbox History"] = true
+L["Reset Filter"] = "重置过滤器"
+L["Reset History"] = true
+L["Reset Priority"] = "重置优先级"
+L["Reset Zoom"] = "重置缩放"
+L["Reset all frames to their original positions."] = "重设所有框架至预设位置"
+L["Reset filter priority to the default state."] = "重置过滤器优先级到默认状态"
+L["Reset the size and position of this frame."] = "重置本窗口大小和位置"
+L["Rest Icon"] = "充分休息图标"
+L["Restore Bar"] = "重置动作条"
+L["Restore Defaults"] = "恢复预设"
+L["Restore the actionbars default settings"] = "恢复此动作条的预设设定"
+L["Resurrect Icon"] = "复活图标"
+L["Return filter to its default state."] = "返回过滤器至默认状态"
+L["Reverse Bag Slots"] = "反向背包格子"
+L["Reverse Cooldown"] = true
+L["Reverse Style"] = true
+L["Reverse Toggle will enable Cooldown Text on this module when the global setting is disabled and disable them when the global setting is enabled."] = "启用时该模块将在全局禁用时启用, 全局启用是禁用."
+L["Reverse Toggle"] = "反转开关"
+L["Right Only"] = "仅显示右边"
+L["Right Panel Height"] = "右面板高度"
+L["Right Panel Width"] = "右面板宽度"
+L["Right to Left"] = "右到左"
+L["Right"] = "右"
+L["RightClick Self-Cast"] = "右键自我施法"
+L["Role Icon"] = "角色职责图标"
+L["Run the installation process."] = "执行安装程序"
+L["Sanctuary"] = true
+L["Scale of the nameplate that is targetted."] = true
+L["Scale"] = "缩放"
+L["Scroll Interval"] = "滚动间隔"
+L["Scroll Messages"] = "滚动信息数目"
+L["Search Syntax"] = "搜索语法"
+L["Search for a spell name inside of a filter."] = "在过滤器中筛选法术"
+L["Secondary Texture"] = "次要材质"
+L["Seconds remaining on the aura duration before the bar starts moving. Set to 0 to disable."] = "光环条移动前的剩余时间(秒), 设为0以禁用"
+L["Seconds"] = "秒"
+L["Selected Text Color"] = true
+L["Selector Color"] = true
+L["Selector Style"] = true
+L["Securely Tanking"] = "安全坦住"
+L["Select Filter"] = "选择过滤器"
+L["Select Spell"] = "选择技能"
+L["Select a profile to copy from/to."] = "选择一个配置文件用于复制"
+L["Select a unit to copy settings from."] = "选择从哪单位复制"
+L["Select the display method of the portrait."] = "选择头像的显示方式"
+L["Sell Interval"] = "售卖周期"
+L["Send ADDON_ACTION_BLOCKED errors to the Lua Error frame. These errors are less important in most cases and will not effect your game performance. Also a lot of these errors cannot be fixed. Please only report these errors if you notice a Defect in gameplay."] = "发送ADDON_ACTION_BLOCKED错误至Lua错误框, 这些错误并不重要, 不会影响你的游戏体验. 并且很多这类错误无法被修复. 请只将影响游戏体验的错误发送给我们"
+L["Sends your current profile to your target."] = "发送你的配置文件到当前目标"
+L["Sends your filter settings to your target."] = "发送你的过滤器配置到当前目标"
+L["Separate Panel Sizes"] = "分离框体大小"
+L["Seperate"] = "光环分离"
+L["Set Settings to Default"] = "恢复默认设置"
+L["Set the alpha level of portrait when frame is overlayed."] = "当框体被遮挡时头像的透明度"
+L["Set the filter type. Blacklist will hide any auras in the list and show all others. Whitelist will show any auras in the filter and hide all others."] = "设置过滤器类型. 黑名单将隐藏列表内的任何光环而显示其他. 白名单将显示过滤器内的任何光环而隐藏其他所有光环"
+L["Set the font outline."] = "设定字体的描边"
+L["Set the font size for everything in UI. Note: This doesn't effect somethings that have their own seperate options (UnitFrame Font, Datatext Font, ect..)"] = "设定界面上所有字体的大小, 但不包含本身有独立设定的字体(如单位框架字体、信息文字字体等)"
+L["Set the font size for unitframes."] = "设置单位框架字体尺寸"
+L["Set the order that the group will sort."] = "设置组排序的顺序"
+L["Set the orientation of the UnitFrame."] = "设置框架的方向"
+L["Set the priority order of the spell, please note that prioritys are only used for the raid debuff module, not the standard buff/debuff module. If you want to disable set to zero."] = "设置该法术的优先顺序. 请注意, 优先级只用于Raid Debuff模块, 而不是标准的Buff/Debuff模块. 设为0以禁用此功能"
+L["Set the size of the individual auras."] = "设置每个光环的尺寸"
+L["Set the size of your bag buttons."] = "设置背包按钮尺寸"
+L["Set the type of auras to show when a unit is a foe."] = "当单位是敌对时设置光环显示的类型"
+L["Set the type of auras to show when a unit is friendly."] = "当单位是友好时设置光环显示的类型"
+L["Set to either stack nameplates vertically or allow them to overlap."] = "设置将姓名板垂直排列或者允许重叠"
+L["Sets the font instance's horizontal text alignment style."] = "设置字体实例的水平文本对齐方式"
+L["Share Current Profile"] = "分享当前配置文件"
+L["Share Filters"] = "分享过滤器配置"
+L["Short (Whole Numbers)"] = "短(完整数字)"
+L["Short Channels"] = "隐藏频道名称"
+L["Shortcut to 'Filters' section of the config."] = "一个到'过滤器'菜单的快捷键"
+L["Shortcut to global filters."] = "到全局过滤器的快捷方式"
+L["Shortcuts"] = "快捷键"
+L["Shorten the channel names in chat."] = "在聊天窗口中隐藏频道名称"
+L["Should tooltip be anchored to mouse cursor"] = "提示显示在鼠标处"
+L["Show Aura From Other Players"] = "显示其他玩家的光环"
+L["Show Auras"] = "显示光环"
+L["Show Bind on Equip/Use Text"] = "显示绑定状态"
+L["Show Both"] = "全部显示"
+L["Show Coins"] = "显示硬币"
+L["Show Dispellable Debuffs"] = "显示可驱散的减益光环"
+L["Show Empty Buttons"] = "显示空白按钮"
+L["Show For DPS"] = "为输出显示"
+L["Show For Healers"] = "为治疗显示"
+L["Show For Tanks"] = "为坦克显示"
+L["Show Icon"] = "显示图标"
+L["Show Junk Icon"] = "显示垃圾图标"
+L["Show Quality Color"] = "显示稀有度图标"
+L["Show Quest Icon"] = true
+L["Show When Not Active"] = "缺失时显示光环"
+L["Show an incoming heal prediction bar on the unitframe. Also display a slightly different colored bar for incoming overheals."] = "在单位框架中显示即将回复的的预估治疗量, 过量治疗则以不同颜色显示"
+L["Show the castbar icon desaturated if a spell is not interruptible."] = "在法术不可被打断时显示褪色的图标"
+L["Show/Hide Test Frame"] = "显示/隐藏测试框架"
+L["Side Arrows"] = "侧面箭头"
+L["Size Override"] = "尺寸覆盖"
+L["Size and Positions"] = "大小和位置"
+L["Size of the indicator icon."] = "指示图标大小"
+L["Size"] = "大小"
+L["Skin Backdrop (No Borders)"] = "美化背景(无边框)"
+L["Skin Backdrop"] = "美化背景"
+L["Skin the blizzard chat bubbles."] = "美化暴雪聊天泡泡"
+L["Skins"] = "美化外观"
+L["Small Panels"] = "迷你面板"
+L["Smaller World Map"] = "小型世界地图"
+L["Smart Aura Position"] = "智能光环位置"
+L["Smart Raid Filter"] = "智能团队过滤"
+L["Smart"] = "智能"
+L["Smooth Bars"] = "平滑化"
+L["Smooth"] = "平滑"
+L["Smoothing Amount"] = "平滑量"
+L["Socket Frame"] = "珠宝插槽"
+L["Sort By"] = "排序"
+L["Sort Direction"] = "排列方向"
+L["Sort Inverted"] = "倒序"
+L["Sort Method"] = "排序方式"
+L["Soul Bag"] = true
+L["Spaced"] = "留空"
+L["Spacing"] = "间隙"
+L["Spam Interval"] = "垃圾间隔"
+L["Spark"] = "火花"
+L["Spell/Item IDs"] = "技能/物品ID"
+L["Split"] = "分隔"
+L["Stable"] = "兽栏"
+L["Stack Counter"] = "层数计数"
+L["Stack Text Position"] = "叠层文字位置"
+L["Stack Text X-Offset"] = "叠层文字X偏移"
+L["Stack Text Y-Offset"] = "叠层文字Y偏移"
+L["Stack Threshold"] = "层数阈值"
+L["Start Near Center"] = "从中心开始"
+L["StatusBar Texture"] = "状态条材质"
+L["Statusbar Fill Orientation"] = "状态条填充方向"
+L["Statusbar"] = true
+L["Sticky Chat"] = "记忆聊天频道"
+L["Strata and Level"] = "框架层级和层次"
+L["Style Filter"] = "样式过滤器"
+L["Style"] = "风格"
+L["Tab Font Outline"] = "标题栏字体描边"
+L["Tab Font Size"] = "标题栏字体尺寸"
+L["Tab Font"] = "标题栏字体"
+L["Tab Panel Transparency"] = "标签面板透明"
+L["Tab Panel"] = "标签面板"
+L["Tab Selector"] = true
+L["Tabard Frame"] = "战袍"
+L["Table"] = "表"
+L["Tank Target"] = "坦克目标"
+L["Tank"] = "坦克"
+L["Tapped"] = "被攻击"
+L["Target Indicator Color"] = "目标指示器颜色"
+L["Target Info"] = "目标信息"
+L["Target On Mouse-Down"] = "鼠标按下设为目标"
+L["Target Scale"] = "目标缩放"
+L["Target units on mouse down rather than mouse up. \n\n|cffFF0000Warning: If you are using the addon 'Clique' you may have to adjust your clique settings when changing this."] = "按下鼠标时设为目标,而不是松开鼠标按键时. \n\n|cffFF0000警告: 如果使用'Clique'等点击施法插件, 你可能需要调整这些插件的设置"
+L["Target/Low Health Indicator"] = "目标指示器"
+L["TargetTarget"] = "目标的目标"
+L["TargetTargetTarget"] = "目标的目标的目标"
+L["Targeted Glow"] = "目标边框"
+L["Targeting"] = "目标"
+L["Testing:"] = "测试:"
+L["Text Fade"] = true
+L["Text Color"] = "文字颜色"
+L["Text Font Size"] = "字体大小"
+L["Text Format"] = "文字格式"
+L["Text Position"] = "文字位置"
+L["Text Threshold"] = "文本阈值"
+L["Text Toggle On NPC"] = "NPC文字显示开关"
+L["Text xOffset"] = "文字X轴偏移"
+L["Text yOffset"] = "文字Y轴偏移"
+L["Text"] = "文本"
+L["Texture"] = "材质"
+L["Textured Icon"] = "图标"
+L["Textures"] = "材质"
+L["The Portrait will overlay the Healthbar. This will be automatically happen if the Frame Orientation is set to Middle."] = "头像将显示在生命条上. 当框体层级设置为Middle时自动设置"
+L["The Thin Border Theme option will change the overall apperance of your UI. Using Thin Border Theme is a slight performance increase over the traditional layout."] = "细边框主题会改变所有的外观,使用细边框主题会略微提升性能"
+L["The amount of buttons to display per row."] = "每行显示多少个按钮数"
+L["The amount of buttons to display."] = "显示多少个动作条按钮"
+L["The button you must hold down in order to drag an ability to another action button."] = "按住某个键后才能拖动动作条的按钮"
+L["The debuff needs to reach this amount of stacks before it is shown. Set to 0 to always show the debuff."] = "减益需要达到这个数量的层数才会显示. 设为0来一直显示它"
+L["The direction that the bag frames be (Horizontal or Vertical)."] = "此方向决定框架是横排还是竖排"
+L["The direction that the bag frames will grow from the anchor."] = "背包框架将从此方向开始排列"
+L["The direction the auras will grow and then the direction they will grow after they reach the wrap after limit."] = "光环图标在第一个方向摆满之后会向下一个方向继续延伸"
+L["The display format of the currency icons that get displayed below the main bag. (You have to be watching a currency for this to display)"] = "背包底部的货币显示格式(你需要在货币页中勾选显示)"
+L["The display format of the money text that is shown at the top of the main bag."] = "在主背包上方显示的金钱文字的格式"
+L["The display format of the money text that is shown in the gold datatext and its tooltip."] = "在信息文字中显示的金钱格式"
+L["The first button anchors itself to this point on the bar."] = "第一个按钮对齐动作条的方向"
+L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."] = "为了显示设定过的过滤器下面的宏必须启用"
+L["The font that appears on the text above players heads. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "玩家头顶姓名的字体. |cffFF0000警告: 你需要重启游戏或重新登录才能使用此功能.|r"
+L["The font that combat text will use. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "战斗信息将使用此字体, |cffFF0000警告:需重启游戏或重新登陆才可使此变更生效.|r"
+L["The font that the core of the UI will use."] = "核心UI所使用的字体"
+L["The font that the unitframes will use."] = "单位框架字体"
+L["The frame is not shown unless you mouse over the frame."] = "只在鼠标移到框架上时显示"
+L["The initial group will start near the center and grow out."] = "最初的队伍由中心开始增长"
+L["The minimum item level required for it to be shown."] = "显示的最低物品等级"
+L["The name you have selected is already in use by another element."] = "你所选的名称已经被另一组件占用"
+L["The object you want to attach to."] = "你想依附的目标"
+L["The size of the action buttons."] = "动作条按钮尺寸"
+L["The size of the individual buttons on the bag frame."] = "背包框架单个格子的尺寸"
+L["The size of the individual buttons on the bank frame."] = "银行框架单个格子的尺寸"
+L["The spacing between buttons."] = "两个按钮间的距离"
+L["The spacing between the backdrop and the buttons."] = "背景与按钮之间的间隙"
+L["The texture that will be used mainly for statusbars."] = "此材质主用于进度条上"
+L["The unit prefixes you want to use when values are shortened in ElvUI. This is mostly used on UnitFrames."] = "在ElvUI中数值单位的缩写. 该选项主要应用在单位框体"
+L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."] = "这些过滤器不像常规过滤器那样使用一个法术列表, 而是使用魔兽API和部分代码逻辑来决定光环显示与否."
+L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."] = "这些过滤器使用一个法术列表来决定光环显示与否. 这些过滤器的内容可以在设置中的'过滤器'选项中更改."
+L["Thin Border Theme"] = "细边框主题"
+L["Thin Borders"] = "细边框"
+L["This dictates the size of the icon when it is not attached to the castbar."] = "指定未吸附在施法条内时图标的尺寸"
+L["This feature will allow you to transfer settings to other characters."] = "此功能将使你设置转移给他角色"
+L["This is for Customized Icons in your Interface/Icons folder."] = "这将应用于你的Interface/Icons文件夹下的自定义图标"
+L["This opens the UnitFrames Color settings. These settings affect all unitframes."] = "这将开启单位框体颜色设置.这些设置会影响所有单位框体"
+L["This option allows the overlay to span the whole health, including the background."] = "这个选项会将头像覆盖到整个生命条上, 包括背景"
+L["This section will allow you to copy settings to a select module from or to a different profile."] = "这部分将允许你将某个模块在不同配置文件中复制"
+L["This section will help reset specfic settings back to default."] = "这部分将帮助你重置特定设置为默认."
+L["This selects the Chat Frame to use as the output of ElvUI messages."] = "选择ElvUI信息的聊天输出"
+L["This setting controls the size of text in item comparison tooltips."] = "设置对比框中的文字大小"
+L["This setting will be updated upon changing stances."] = "这个设置会在改变姿态时更新"
+L["This texture will get used on objects like chat windows and dropdown menus."] = "主要用于聊天窗口及下拉选单等物件的材质"
+L["This will override the global cooldown settings."] = "这将强制覆盖全局冷却设置"
+L["This will prevent the UI Scale Popup from being shown when changing the game window size."] = "这将阻止改变游戏窗口大小时弹出UI缩放提示"
+L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."] = "这会重置这个过滤器到初始状态. 你添加到这个过滤器的任何技能都会被移除."
+L["Threat Display Mode"] = "仇恨显示模式"
+L["Threat Health"] = "仇恨血量"
+L["Threat Power"] = "仇恨能量"
+L["Threat"] = "仇恨"
+L["Threshold (in minutes) before text is shown in the HH:MM format. Set to -1 to never change to this format."] = "文字以时:分格式显示的阈值(单位:分). 设为-1以禁用此格式."
+L["Threshold (in seconds) before text is shown in the MM:SS format. Set to -1 to never change to this format."] = "文字以分:秒格式显示的阈值(单位:秒). 设为-1以禁用此格式."
+L["Threshold before text goes into decimal form. Set to -1 to disable decimals."] = "文字变为小数时的阈值.设为-1以禁用小数"
+L["Threshold before text turns red and is in decimal form. Set to -1 for it to never turn red"] = "冷却时间低于此秒数后将变为红色数字, 并以小数显示, 设为-1来使其不会变为红色"
+L["Threshold before the icon will fade out and back in. Set to -1 to disable."] = "图标闪烁时的阈值, 设为-1以禁用."
+L["Ticks"] = "周期伤害"
+L["Time Format"] = true
+L["Time Indicator Colors"] = "时间指示器颜色"
+L["Time Remaining Reverse"] = "剩余时间反转"
+L["Time Remaining"] = "剩余时间"
+L["Time To Hold"] = "停留时间"
+L["Time xOffset"] = "时间X偏移"
+L["Time yOffset"] = "时间Y偏移"
+L["Time"] = "时间"
+L["Timestamp Color"] = "时间戳颜色"
+L["Toggle Anchors"] = "切换定位开关"
+L["Toggle Off While In Combat"] = "战斗时关闭"
+L["Toggle On While In Combat"] = "战斗时启用"
+L["Toggle Tutorials"] = "教学开关"
+L["Toggle showing of the left and right chat panels."] = "显示/隐藏左右聊天框"
+L["Toggle the chat tab panel backdrop."] = "显示/隐藏聊天框架标签面板背景"
+L["Toggles the display of the actionbars backdrop."] = "切换动作条显示背景框"
+L["Tooltip Font Settings"] = "提示文字设置"
+L["Top Arrow"] = "顶部箭头"
+L["Top Left"] = "左上"
+L["Top Panel"] = "顶部面板"
+L["Top Right"] = "右上"
+L["Top to Bottom"] = "顶部到底部"
+L["Top"] = "上"
+L["TopLeftMiniPanel"] = "小地图左上内侧"
+L["TopMiniPanel"] = "小地图顶部内侧"
+L["TopRightMiniPanel"] = "小地图右上内侧"
+L["Totem"] = true
+L["Trainer Frame"] = "训练师"
+L["Transparency level when not in combat, no target exists, full health, not casting, and no focus target exists."] = "在非战斗, 无目标存在, 满血, 未施法, 无焦点目标存在时的不透明度"
+L["Transparent Backdrops"] = true
+L["Transparent Buttons"] = true
+L["Transparent"] = "透明"
+L["Triggers"] = "触发器"
+L["Turtle Color"] = "减伤类的颜色"
+L["Tutorial Frame"] = true
+L["URL Links"] = "网址链接"
+L["Under Health Threshold"] = "低于血量阈值"
+L["Under Power Threshold"] = "低于能量阈值"
+L["Uniform Threshold"] = "统一阈值"
+L["Unique Units"] = true
+L["Unit Prefix Style"] = "单位缩写"
+L["Unit Target"] = "单位目标"
+L["Unit Type"] = "单位类型"
+L["UnitFrames"] = "单位框架"
+L["Unlock various elements of the UI to be repositioned."] = "解锁界面上的各种框架来更改位置"
+L["Up"] = "上"
+L["Usable"] = "可用"
+L["Use Alt Key"] = "聊天历史Alt键"
+L["Use Class Color"] = "使用职业颜色"
+L["Use Custom Level"] = "使用自定义层次"
+L["Use Custom Strata"] = "使用自定义层级"
+L["Use Dead Backdrop"] = "死亡背景"
+L["Use Default"] = "使用默认值"
+L["Use Indicator Color"] = "使用指示器颜色"
+L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."] = "使用Shift+左键来改变友方/敌方/普通状态. 普通状态将允许过滤器检查所有单位. 友方/敌方将只检查对应单位."
+L["Use Target Scale"] = "使用目标缩放"
+L["Use Threat Color"] = "使用仇恨颜色"
+L["Use class color for the names of players when they are mentioned."] = "当玩家名字被提及时使用职业颜色"
+L["Use coin icons instead of colored text."] = "显示硬币图标而不是颜色文字"
+L["Use drag and drop to rearrange filter priority or right click to remove a filter."] = "使用拖拽的方式调整过滤器优先级, 或者右键移除一个过滤器"
+L["Use the Name Color of the unit for the Name Glow."] = "对姓名高亮使用名字颜色"
+L["Use the custom backdrop color instead of a multiple of the main color."] = "使用自定义背景色而不是多种主色."
+L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."] = "使用配置文件内的增益指示器而不是全局的"
+L["Use thin borders on certain unitframe elements."] = "使用细边框"
+L["Use this backdrop color for units that are dead or ghosts."] = "死亡或灵魂状态背景"
+L["Used as RaidDebuff Indicator"] = "作为团队减益指示器"
+L["Value Color"] = "数值颜色"
+L["Value must be a number"] = "数值必须为一个数字"
+L["Vehicle Seat Indicator Size"] = "载具座位框大小"
+L["Vehicle"] = "载具"
+L["Vendor Gray Detailed Report"] = "出售灰色物品详细报告"
+L["Vendor Grays"] = "出售灰色物品"
+L["Version"] = "版本"
+L["Vertical Fill Direction"] = "垂直填充方向"
+L["Vertical Spacing"] = "垂直间隔"
+L["Vertical"] = "垂直"
+L["Visibility State"] = "可见状态"
+L["Visibility"] = "可见性"
+L["Watch Frame"] = "任务追踪"
+L["What point to anchor to the frame you set to attach to."] = "框架的定位对齐方向"
+L["What to attach the buff anchor frame to."] = "Buff定位附加到的框架"
+L["What to attach the debuff anchor frame to."] = "debuff定位附加到的框架"
+L["When enabled active buff icons will light up instead of becoming darker, while inactive buff icons will become darker instead of being lit up."] = "启用后活跃buff图标会点亮而不是变暗, 非活跃buff图标会变暗而不是变亮"
+L["When enabled it will only show spells that were added to the filter using a spell ID and not a name."] = "启用后将只显示通过法术ID添加到过滤器中的法术, 而不包括通过名字添加的."
+L["When in a raid group display if anyone in your raid is targeting the current tooltip unit."] = "显示团队中目标与你目前鼠标提示目标相同的队友"
+L["When inside a battleground display personal scoreboard information on the main datatext bars."] = "处于战场时, 在主信息文字条显示你的战场得分信息"
+L["When opening the Chat Editbox to type a message having this option set means it will retain the last channel you spoke in. If this option is turned off opening the Chat Editbox should always default to the SAY channel."] = "当你开始输入消息时此选项的启用将会让你保留最后一次聊天的频道, 如果关闭将始终使用说话频道"
+L["When true, the header includes the player when not in a raid."] = "若启用, 队伍中将显示玩家."
+L["When you go AFK display the AFK screen."] = "当你离开时显示AFK界面"
+L["Whitelist"] = "白名单"
+L["Width Multiplier"] = "宽度倍增"
+L["Width"] = "宽"
+L["Will attempt to sell another item in set interval after previous one was sold."] = "尝试在设定的周期后卖下一个物品"
+L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."] = "如果没有减益则把增益显示在减益位置, 反之亦然"
+L["Word Wrap"] = "自动换行"
+L["World Map Coordinates"] = "世界地图坐标"
+L["World State Frame"] = true
+L["Wrap After"] = "每行行数"
+L["X-Offset"] = "X轴偏移"
+L["Y-Offset"] = "Y轴偏移"
+L["You do not need to use 'Is Casting Anything' or 'Is Channeling Anything' for these spells to trigger."] = true
+L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."] = "你不能移除一个内建技能, 仅能停用此技能"
+L["You must be targeting a player."] = "你必须以一名玩家为目标"
+L["You need to hold this modifier down in order to blacklist an aura by right-clicking the icon. Set to None to disable the blacklist functionality."] = "按住设置按键+右键单击会把该玩家加入黑名单, 设为无以关闭该功能"
+L["Your Auras First"] = "自身光环优先"
+L["xOffset"] = "X轴偏移"
+L["yOffset"] = "Y轴偏移"
+
+L["ACTIONBARS_DESC"] = "修改动作条设定"
+L["AURAS_DESC"] = "小地图旁的光环图标设置"
+L["BAGS_DESC"] = "调整ElvUI背包设置"
+L["CHAT_DESC"] = "聊天框设置"
+L["COOLDOWN_DESC"] = "调整冷却文字设置"
+L["DATABAR_DESC"] = "设置各种数据条"
+L["DATATEXT_DESC"] = "设定屏幕所显示的部分信息文字"
+L["ELVUI_DESC"] = "ElvUI为一套功能完整, 可用来替换WoW原始界面的套件"
+L["NAMEPLATE_DESC"] = "修改姓名板设定"
+L["PANEL_DESC"] = "调整左、右聊天框的大小, 此设定将会影响聊天与背包框架的大小"
+L["SKINS_DESC"] = "调整外观设定"
+L["TOGGLESKIN_DESC"] = "启用/停用此外观"
+L["TOOLTIP_DESC"] = "鼠标提示信息设定选项"
+L["UNITFRAME_DESC"] = "修改单位框架设定"
+L["SEARCH_SYNTAX_DESC"] = [=[因为新增了LibItemSearch,你现在可以使用更高级的物品检索. 下面是一份检索语法的文档. 查看完整说明: https://github.com/Jaliborc/LibItemSearch-1.2/wiki/Search-Syntax.
+
+特性检索:
+ • q:[品质] 或 quality:[品质]. 例如, 输入 q:史诗 会检索所有史诗物品.
+ • l:[物品等级], lvl:[物品等级] 或 level:[物品等级]. 例如, 输入 l:30 会检索所有物品等级为30的物品.
+ • t:[类型], type:[类型] 或 slot:[类型]. 例如, 输入 t:武器 会检索所有武器类型的物品.
+ • n:[名称] 或 name:[名称]. 例如, 输入 n:muffins 会检索所有包含"muffins"字样的物品.
+ • s:[方案名称] 或 set:[方案名称]. 例如, 输入 set:fire 会检索所有以fire开头命名的装备配置方案中的物品.
+ • r:[等级], reg:[等级], rl:[等级], regl:[等级] 或 reqlvl:[等级]. 例如, 输入 reqlvl:30 会检索所有需要等级达到30才可以使用的物品.
+ • tt:[提示文字], tip:[提示文字] 或 tooltip:[提示文字]. 例如, 输入 tt:绑定 会检索所有鼠标提示文字中包含"绑定"字样的物品.
+
+
+检索运算符:
+ • ! : 反向检索. 例如, 输入 !q:史诗 会检索所有非史诗的物品.
+ • | : 并集检索. 例如, 输入 q:史诗 | t:武器 会检索所有品质为史诗或类型为武器的物品.
+ • & : 交集检索. 例如, 输入 q:史诗 & t:武器 会检索所有品质为史诗并且类型是武器的物品
+ • >, <, <=, => : 对数值进行比较的检索. 例如, 输入 lvl: >30 会检索所有物品等级大于30的物品.
+
+
+还可以使用下列检索关键字:
+ • soulbound, bound, bop : 拾取绑定物品.
+ • bou : 使用绑定物品.
+ • boe : 装备绑定物品.
+ • boa : 账号绑定物品.
+ • quest : 任务绑定物品.]=]
+L["TEXT_FORMAT_DESC"] = [=[提供一个更改文字格式的方式
+
+例如:
+[namecolor][name] [difficultycolor][smartlevel] [shortclassification]
+[healthcolor][health:current-max]
+[powercolor][power:current]
+
+生命条 / 能量条 格式:
+"current" - 当前值
+"percent" - 百分比
+"current-max" - 当前值 - 最大值. 当当前值等于最大值时只显示最大值
+"current-percent" - 当前值 - 百分比. 当百分比为100%时只显示当前值
+"current-max-percent" - 当前值 - 最大值 - 百分比. 当当前值不等于最大值时显示
+"deficit" - 失去值. 没有失去值时不显示
+
+姓名格式:
+"name:veryshort" - Name restricted to 5 characters
+"name:short" - 姓名显示限制于10字节内
+"name:medium" -姓名显示限制于15字节内
+"name:long" - 姓名显示限制于20字节内
+"name:short:translit" - Name restricted to 10 characters with transliteration
+
+空白则为禁用. 如需技术支持请至https://www.tukui.org/forum/viewtopic.php?t=6]=]
+L["NAMEPLATE_FRAMELEVEL_DESC"] = [=[如果你设置为1则所有符合这个过滤器的姓名板将在其他姓名板上方。
+如果你将另一个过滤器设置为2则符合那个过滤器的姓名板将在设为1的姓名板以及未触发的姓名板上方。
+请注意:这个设置不会修复在互相重叠的姓名板上点击/鼠标指向的问题。该问题是由于我们无法处理姓名板可点击区域的层次。]=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to page differently.
+ Example: '[combat] 2;']=] ] = [=[和宏写法类似, 能根据不同姿态切换动作条.
+ 例如: '[combat] 2;']=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to show/hide differently.
+ Example: '[combat] show;hide']=] ] = [=[和宏写法类似, 能根据不同姿态切换动作条显示或隐藏.
+ 例如: '[combat] show;hide']=]
+
+L[ [=[Specify a filename located inside the World of Warcraft directory. Textures folder that you wish to have set as a panel background.
+
+Please Note:
+-The image size recommended is 256x128
+-You must do a complete game restart after adding a file to the folder.
+-The file type must be tga format.
+
+Example: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Or for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here.]=] ] = [=[若要设定聊天框背景, 请你指定位于WoW目录下的「Textures」文件夹中的材质文件名.
+
+请注意:
+- 图片尺寸建议为256x128
+- 在添加文件后你必须完全重新启动游戏
+- 文件必须为tga格式
+
+举例:Interface\AddOns\ElvUI\Media\Textures\Copy
+
+对多数玩家来说, 较简易的方式是将tga文件放入WoW文件夹中, 然后在此处输入文件名.]=]
+
+-- Global Strings
+L["ACHIEVEMENTS"] = "成就"
+L["ALT_KEY_TEXT"] = "ALT"
+L["ARENA"] = "竞技场"
+L["AUCTIONS"] = "拍卖"
+L["BAGSLOT"] = "背包"
+L["BARBERSHOP"] = "理发店"
+L["BATTLEGROUND"] = "战场"
+L["BATTLEFIELDS"] = "战场"
+L["BLOCK"] = "格挡"
+L["BOSS"] = "首领"
+L["BUFFOPTIONS_LABEL"] = "增益效果和负面效果"
+L["CLASS"] = "职业"
+L["CHANNEL"] = "频道"
+L["COLOR"] = "颜色"
+L["COLORS"] = "颜色"
+L["COMBAT"] = "战斗"
+L["COMBAT_TEXT_RUNE_BLOOD"] = "鲜血符文"
+L["COMBAT_TEXT_RUNE_DEATH"] = "死亡符文"
+L["COMBAT_TEXT_RUNE_FROST"] = "冰霜符文"
+L["COMBAT_TEXT_RUNE_UNHOLY"] = "邪恶符文"
+L["COMBO_POINTS"] = "连击点数"
+L["CTRL_KEY"] = "CTRL"
+L["CUSTOM"] = "自定义"
+L["DAMAGER"] = "伤害输出"
+L["DEFAULT"] = "默认"
+L["DELETE"] = "删除"
+L["DISABLE"] = "禁用"
+L["DRESSUP_FRAME"] = "试衣间"
+L["DUNGEON_DIFFICULTY"] = "地下城难度"
+L["DUNGEONS"] = "地下城"
+L["EMOTE"] = "表情"
+L["ENEMY"] = "敌方"
+L["ENERGY"] = "能量"
+L["FACTION_STANDING_LABEL1"] = "仇恨"
+L["FACTION_STANDING_LABEL2"] = "敌对"
+L["FACTION_STANDING_LABEL3"] = "冷淡"
+L["FACTION_STANDING_LABEL4"] = "中立"
+L["FACTION_STANDING_LABEL5"] = "友善"
+L["FACTION_STANDING_LABEL6"] = "尊敬"
+L["FACTION_STANDING_LABEL7"] = "崇敬"
+L["FACTION_STANDING_LABEL8"] = "崇拜"
+L["FILTERS"] = "过滤器"
+L["FLIGHT_MAP"] = "飞行地图"
+L["FOCUS"] = "集中值"
+L["FONT_SIZE"] = "字体大小"
+L["FRIEND"] = "好友"
+L["FRIENDS"] = "好友"
+L["GROUP"] = "小队"
+L["GUILD"] = "公会"
+L["GUILD_BANK"] = "公会银行"
+L["HAPPINESS"] = "快乐"
+L["HEALER"] = "治疗者"
+L["HEALTH"] = "生命值"
+L["HIDE"] = "隐藏"
+L["INSCRIPTION"] = "铭文"
+L["INSPECT"] = "观察"
+L["INTERFACE_OPTIONS"] = "界面选项"
+L["INTERRUPTED"] = "被打断"
+L["ITEM_BIND_QUEST"] = "任务物品"
+L["ITEMS"] = "物品"
+L["KEY_BINDINGS"] = "按键设置"
+L["LANGUAGE"] = "语言"
+L["LEAVE_VEHICLE"] = "离开载具"
+L["LEVEL"] = "等级"
+L["LOCK_ACTIONBAR_TEXT"] = "锁定动作条"
+L["LOOT"] = "Loot"
+L["MACROS"] = "宏命令设置"
+L["MAIL_LABEL"] = "信件"
+L["MANA"] = "法力值"
+L["MAP_FADE_TEXT"] = "移动时地图透明"
+L["MERCHANT"] = "商人"
+L["MINIMAP_LABEL"] = "微缩地图"
+L["MISCELLANEOUS"] = "杂项"
+L["NAME"] = "名字"
+L["NONE"] = "无"
+L["OFFICER"] = "官员"
+L["OPACITY"] = "不透明"
+L["OPTION_TOOLTIP_ACTION_BUTTON_USE_KEY_DOWN"] = "在按下快捷键时施法,而不是在松开快捷键时施法。"
+L["OPTION_TOOLTIP_TIMESTAMPS"] = "选择聊天信息的时间戳格式。"
+L["PARTY"] = "小队"
+L["PET"] = "宠物"
+L["PLAYER"] = "玩家"
+L["PLAYER_DIFFICULTY1"] = "普通"
+L["PLAYER_DIFFICULTY2"] = "英雄"
+L["RAGE"] = "怒气"
+L["RAID"] = "团队"
+L["RAID_TARGET_1"] = "星形"
+L["RAID_TARGET_2"] = "圆形"
+L["RAID_TARGET_3"] = "菱形"
+L["RAID_TARGET_4"] = "三角"
+L["RAID_TARGET_5"] = "月亮"
+L["RAID_TARGET_6"] = "方块"
+L["RAID_TARGET_7"] = "十字"
+L["RAID_TARGET_8"] = "骷髅"
+L["REPUTATION"] = "声望"
+L["ROLE"] = "职责"
+L["RUNIC_POWER"] = "符文能量"
+L["SAY"] = "说"
+L["SHIFT_KEY"] = "SHIFT"
+L["SHORT"] = "短"
+L["SHOW"] = "显示"
+L["SPEED"] = "速度"
+L["SPELLBOOK"] = "法术书"
+L["TALENTS"] = "天赋"
+L["TANK"] = "坦克"
+L["TARGET"] = "目标"
+L["TIMEMANAGER_TITLE"] = "时钟"
+L["TIMESTAMPS_LABEL"] = "聊天时间戳"
+L["TRADE"] = "交易"
+L["TRADESKILLS"] = "商业技能"
+L["TUTORIAL_TITLE47"] = "图腾栏"
+L["UI_SCALE"] = "UI缩放"
+L["UNIT_NAMEPLATES_TYPES"] = "姓名板排列方式"
+L["UNIT_NAMEPLATES_TYPE_1"] = "重叠姓名板"
+L["UNIT_NAMEPLATES_TYPE_2"] = "堆叠姓名板"
+L["WHISPER"] = "悄悄话"
+L["WORLD_MAP"] = "地图"
+L["XPBAR_LABEL"] = "经验槽"
+L["YELL"] = "大喊"
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Locales/zhTW.lua b/ElvUI_OptionsUI/Locales/zhTW.lua
new file mode 100644
index 0000000..01eed5b
--- /dev/null
+++ b/ElvUI_OptionsUI/Locales/zhTW.lua
@@ -0,0 +1,1393 @@
+-- Traditional Chinese localization file for zhTW.
+local L = ElvUI[1].Libs.ACL:NewLocale("ElvUI", "zhTW")
+
+L["%s and then %s"] = "%s 與 %s"
+L["2D"] = "2D"
+L["3D"] = "3D"
+L["AFK Mode"] = "離開模式"
+L["ANCHOR_CURSOR"] = "指針"
+L["ANCHOR_CURSOR_LEFT"] = "指針的左邊"
+L["ANCHOR_CURSOR_RIGHT"] = "指針的右邊"
+L["Abbreviation"] = true
+L["Above Chat"] = "對話框上方"
+L["Above"] = "向上"
+L["Accept Invites"] = "接受組隊邀請"
+L["Action Paging"] = "快捷列翻頁"
+L["ActionBars"] = "快捷列"
+L["Actions"] = "動作"
+L["Add Item or Search Syntax"] = "增加物品或是搜尋語法"
+L["Add Name"] = "添加名稱"
+L["Add Regular Filter"] = "添加常規過濾器"
+L["Add Special Filter"] = "添加特殊過濾器"
+L["Add Spell ID or Name"] = "添加技能 ID 或者名字"
+L["Add SpellID"] = "添加技能 ID"
+L["Add a Name to the list."] = true
+L["Add a spell to the filter. Use spell ID if you don't want to match all auras which share the same name."] = "添加一個技能到過濾器.使用法術 ID 以避免匹配到同名的光環"
+L["Add a spell to the filter."] = "添加一個技能到過濾器"
+L["Add an item or search syntax to the ignored list. Items matching the search syntax will be ignored."] = "增加一個物品或是搜尋語法到忽略清單. 符合搜尋語法的物品將會被忽略"
+L["Additional Power Text"] = "額外能量文字"
+L["Additional spacing between each individual group."] = "各隊伍間的附加距離"
+L["Additive Blend"] = "覆蓋混合"
+L["Adjust the height of your right chat panel."] = "調整右側聊天框的高度"
+L["Adjust the position of the threat bar to either the left or right datatext panels."] = "調整仇恨條的位置於左側或右側資訊面板"
+L["Adjust the size of the minimap."] = "調整小地圖尺寸."
+L["Adjust the width of the bag frame."] = "調整背包框架寬度."
+L["Adjust the width of the bank frame."] = "調整銀行框架寬度."
+L["Adjust the width of your right chat panel."] = "調整右側聊天框的寬度"
+L["Alert Frames"] = "警報"
+L["Alerts"] = "警示"
+L["Allow LBF to handle the skinning of this element."] = "允許 LBF 來處理此元件的皮膚"
+L["Allowed Combat Repeat"] = "戰鬥連續按鍵修復"
+L["Alpha Fading"] = "淡入淡出"
+L["Alpha Key"] = "單位元 Alpha 通道混合"
+L["Alpha channel is taken from the color option."] = "Alpha 通道值取自色彩選項."
+L["Alpha"] = "透明度"
+L["Always Display"] = "總是顯示"
+L["Always Hide"] = "總是隱藏"
+L["Always Show Realm"] = "總是顯示伺服器"
+L["Always Show Target Health"] = "始終顯示目標血量"
+L["Ammo Pouch"] = true
+L["An X offset (in pixels) to be used when anchoring new frames."] = "錨定新框架時的X軸偏移(單位:像素)"
+L["An Y offset (in pixels) to be used when anchoring new frames."] = "錨定新框架時的Y軸偏移(單位:像素)"
+L["Anchor Point"] = "定位方向"
+L["Announce Interrupts"] = "斷法通告"
+L["Announce when you interrupt a spell to the specified chat channel."] = "在指定對話頻道通知斷法信息."
+L["Applies the font and font size settings throughout the entire user interface. Note: Some font size settings will be skipped due to them having a smaller font size by default."] = "把該字體設置應用到所有ElvUI設置中去,但是某些設置並不會被改變."
+L["Applies the primary texture to all statusbars."] = "將主要材質應用到所有狀態條"
+L["Apply Font To All"] = "應用字體到所有"
+L["Apply Texture To All"] = "應用材質到所有"
+L["Apply this filter if a buff has remaining time greater than this. Set to zero to disable."] = "當增益剩餘時間大於此值時使用此過濾器,設為0來停用"
+L["Apply this filter if a buff has remaining time less than this. Set to zero to disable."] = "當增益剩餘時間小於此值時使用此過濾器,設為0來停用"
+L["Apply this filter if a debuff has remaining time greater than this. Set to zero to disable."] = "當減益剩餘時間大於此值時使用此過濾器,設為0來停用"
+L["Apply this filter if a debuff has remaining time less than this. Set to zero to disable."] = "當減益剩餘時間小於此值時使用此過濾器,設為0來停用"
+L["Are you sure you want to reset ActionBars settings?"] = "你確定你要重置快捷列的設定?"
+L["Are you sure you want to reset Auras settings?"] = "你確定你要重置光環的設定?"
+L["Are you sure you want to reset Bags settings?"] = "你確定你要重置背包的設定?"
+L["Are you sure you want to reset Chat settings?"] = "你確定你要重置對話框的設定?"
+L["Are you sure you want to reset Cooldown settings?"] = "你確定你要重置冷卻的設定?"
+L["Are you sure you want to reset DataBars settings?"] = "你確定你要重置數據條的設定?"
+L["Are you sure you want to reset DataTexts settings?"] = "你確定你要重置資訊文字的設定?"
+L["Are you sure you want to reset General settings?"] = "你確定你要重置常規選項的設定?"
+L["Are you sure you want to reset NamePlates settings?"] = "你確定你要重置姓名板的設定?"
+L["Are you sure you want to reset Tooltip settings?"] = "你確定你要重置提示的設定?"
+L["Are you sure you want to reset UnitFrames settings?"] = "你確定你要重置單位框架的設定?"
+L["Arena Frame"] = true
+L["Arena Registrar"] = true
+L["Arena"] = "競技場"
+L["Ascending or Descending order."] = "升序或降序"
+L["Ascending"] = "升序"
+L["Assist Target"] = "助理目標"
+L["Assist"] = "助理框架"
+L["At what point should the text be displayed. Set to -1 to disable."] = "在何時顯示文本. 設定為-1 禁用此功能."
+L["Attach Text To"] = "文字附著於"
+L["Attach To"] = "附加到"
+L["Attempt to create URL links inside the chat."] = "對話視窗出現網址時建立連結."
+L["Attempt to lock the left and right chat frame positions. Disabling this option will allow you to move the main chat frame anywhere you wish."] = "鎖定左右對話框架的位置.禁用此選項將允許你移動對話框架到任意位置."
+L["Attempt to support eyefinity/nvidia surround."] = "嘗試支援 Eyefinity/NVIDIA Surround."
+L["Aura Bars"] = "光環條"
+L["Aura Filters"] = "光環過濾器"
+L["Auto Greed/DE"] = "自動貪婪/分解"
+L["Auto Hide"] = "自動隱藏"
+L["Auto Repair"] = "自動修裝"
+L["Auto-Hide"] = "自動隱藏"
+L["Automatic"] = "自動"
+L["Automatically accept invites from guild/friends."] = "自動接受公會成員/朋友的組隊邀請."
+L["Automatically hide the objetive frame during boss or arena fights."] = "在首領戰鬥或是競技場時自動隱藏目標追蹤框架."
+L["Automatically repair using the following method when visiting a merchant."] = "與商人對話時, 透過下列方式自動修復裝備."
+L["Automatically select greed or disenchant (when available) on green quality items. This will only work if you are the max level."] = "當你的等級達到滿級時, 自動選擇貪婪或分解綠色物品."
+L["Automatically vendor gray items when visiting a vendor."] = "當訪問商人時自動出售灰色物品."
+L["Available Tags"] = "可用標籤"
+L["BG Map"] = "戰場地圖"
+L["BG Score"] = "戰場積分"
+L["BINDING_HEADER_RAID_TARGET"] = "標記"
+L["Backdrop Color"] = "背景顏色"
+L["Backdrop Faded Color"] = "背景透明色"
+L["Backdrop Spacing"] = "背景間距"
+L["Backdrop color of transparent frames"] = "透明框架的背景顏色"
+L["Backdrop"] = "背景"
+L["Background Glow"] = "背景發光"
+L["Bad Color"] = "危險顏色"
+L["Bad Scale"] = "危險縮放"
+L["Bad Transition Color"] = "危險過渡顏色"
+L["Bad"] = "危險"
+L["Bag 1"] = "背包 1"
+L["Bag 2"] = "背包 2"
+L["Bag 3"] = "背包 3"
+L["Bag 4"] = "背包 4"
+L["Bag Sorting"] = "背包排序"
+L["Bag Spacing"] = "背包間隔"
+L["Bag"] = "背包"
+L["Bag-Bar"] = "背包條"
+L["Bags Only"] = "僅背包"
+L["Bags/Bank"] = "背包/銀行"
+L["Bank 1"] = "銀行 1"
+L["Bank 2"] = "銀行 2"
+L["Bank 3"] = "銀行 3"
+L["Bank 4"] = "銀行 4"
+L["Bank 5"] = "銀行 5"
+L["Bank 6"] = "銀行 6"
+L["Bank 7"] = "銀行 7"
+L["Bank Only"] = "僅銀行"
+L["Bar Direction"] = "背包條排序方向"
+L["Bars will transition smoothly."] = "狀態條平滑增減"
+L["Battleground Texts"] = "戰場資訊"
+L["Begin a new row or column after this many auras."] = "在這些光環旁開始新的行或列."
+L["Below Chat"] = "對話框下方"
+L["Below"] = "向下"
+L["Blacklist Modifier"] = "黑名單功能鍵"
+L["Blacklist"] = "黑名單"
+L["Blend Mode"] = "混合模式"
+L["Blend"] = "常規混合"
+L["BlizzUI Improvements"] = "暴雪介面增強"
+L["Blizzard Style"] = "暴雪風格"
+L["Blizzard"] = "暴雪原生"
+L["Block Combat Click"] = "戰鬥中屏蔽點擊"
+L["Block Combat Hover"] = "戰鬥中屏蔽提示"
+L["Block Mouseover Glow"] = "停用滑鼠指向發光"
+L["Block Target Glow"] = "停用目標發光"
+L["Blocks all click events while in combat."] = "戰鬥中禁用點擊事件"
+L["Blocks datatext tooltip from showing in combat."] = "戰鬥中禁用浮動提示"
+L["Border Color"] = "邊框顏色"
+L["Border Glow"] = "邊框發光"
+L["Border"] = "邊框"
+L["Borders"] = "邊框"
+L["Both"] = "兩者"
+L["Bottom Left"] = "左下"
+L["Bottom Panel"] = "底部面板"
+L["Bottom Right"] = "右下"
+L["Bottom to Top"] = "底部至頂部"
+L["Bottom"] = "下"
+L["BottomLeftMiniPanel"] = "小地圖左下 (內側)"
+L["BottomMiniPanel"] = "小地圖底部 (內側)"
+L["BottomRightMiniPanel"] = "小地圖右下 (內側)"
+L["Buff Indicator"] = "Buff 提示器"
+L["Button Size (Bag)"] = "單個格子尺寸 (背包)"
+L["Button Size (Bank)"] = "單個格子尺寸 (銀行)"
+L["Button Size"] = "按鈕尺寸"
+L["Button Spacing"] = "按鈕間距"
+L["Buttons Per Row"] = "每行按鈕數"
+L["Buttons"] = "按鈕數"
+L["By Type"] = "類型"
+L["Calendar Frame"] = "行事曆"
+L["Cast Bar"] = "施法條"
+L["Cast Color"] = "施法條顏色"
+L["Cast No Interrupt Color"] = "無法打斷的顏色"
+L["Cast Time Format"] = "施法時間格式"
+L["Castbar"] = "施法條"
+L["Casting"] = "施法"
+L["Center"] = "置中"
+L["Change settings for the display of the location text that is on the minimap."] = "改變小地圖所在位置文字的顯示設定."
+L["Change the alpha level of the frame."] = "改變框架透明度."
+L["Channel Alerts"] = true
+L["Change the width and controls how big of an area on the screen will accept clicks to target unit."] = true
+L["Channel Time Format"] = "通道法術時間格式"
+L["Character Frame"] = "角色"
+L["Chat Bubble Names"] = "聊天氣泡姓名"
+L["Chat Bubbles Style"] = "聊天氣泡樣式"
+L["Chat Bubbles"] = "聊天氣泡"
+L["Chat EditBox Position"] = "對話輸入框位置"
+L["Chat Output"] = "聊天輸出"
+L["Check these to only have the filter active in certain difficulties. If none are checked, it is active in all difficulties."] = "選中這些項目會使得過濾器只會在當前難度下啟用. 如果沒有選中任意一個, 將會在全部難度中啟用."
+L["CheckBox Skin"] = "選框皮膚"
+L["Choose Export Format"] = "選擇導出格式"
+L["Choose UIPARENT to prevent it from hiding with the unitframe."] = "使用UIPARENT來防止它隨框架隱藏"
+L["Choose What To Export"] = "選擇導出內容"
+L["Choose when you want the tooltip to show in combat. If a modifer is chosen, then you need to hold that down to show the tooltip."] = "如果你想在戰鬥中看到浮動提示請選中. 如果你已經選中了修飾鍵顯示, 那麼你需要按住來顯示浮動提示."
+L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."] = "選擇何時顯示提示. 如果選擇了設置鍵, 你需要按住它來顯示提示"
+L["Class Backdrop"] = "生命條背景職業色"
+L["Class Castbars"] = "施法條職業色"
+L["Class Color Mentions"] = "使用職業上色"
+L["Class Color Override"] = "職業色覆蓋"
+L["Class Health"] = "生命條職業色"
+L["Class Power"] = "能量條職業色"
+L["Class Resources"] = "職業能量"
+L["Class Totems"] = "職業圖騰"
+L["Clear Filter"] = "清空過濾器"
+L["Clear Search On Close"] = "關閉時清空搜尋"
+L["Click Through"] = "點擊穿透"
+L["Clickable Height"] = "可點擊高度"
+L["Clickable Size"] = "可點擊尺寸"
+L["Clickable Width / Width"] = "可點擊寬度 / 寬度"
+L["Coding:"] = "編碼:"
+L["Color Keybind Text when Out of Range, instead of the button."] = "在超出射程時給按鍵文字上色, 而不是整個技能圖示."
+L["Color Keybind Text"] = "按鍵文字上色"
+L["Color Override"] = "顏色覆蓋"
+L["Color Turtle Buffs"] = "減傷類 Buff 的顏色"
+L["Color all buffs that reduce the unit's incoming damage."] = "減少目標受到的傷害的所有 Buff 的顏色."
+L["Color aurabar debuffs by type."] = "按類型顯示光環條顔色."
+L["Color by Value"] = "根據數值染色"
+L["Color castbars by the class of player units."] = "按職業顯示施法條顏色"
+L["Color castbars by the reaction type of non-player units."] = "按非玩家單位的聲望顯示施法條顏色"
+L["Color health by amount remaining."] = "按數值變化血量顏色."
+L["Color health by classcolor or reaction."] = "以職業色顯示生命."
+L["Color health by threat status."] = "以威脅值顯示生命."
+L["Color of the actionbutton when not usable."] = "無法使用的技能快捷鍵顏色."
+L["Color of the actionbutton when out of power (Mana, Rage)."] = true
+L["Color of the actionbutton when out of range."] = "超出施放範圍的技能快捷鍵顏色."
+L["Color of the actionbutton when usable."] = "可使用的技能快捷鍵顏色."
+L["Color power by classcolor or reaction."] = "以威脅值顯示能量."
+L["Color power by threat status."] = "以威脅值顯示能量."
+L["Color some texts use."] = "數值(非文字)使用的顏色"
+L["Color the health backdrop by class or reaction."] = "生命條背景色以職業色顯示."
+L["Color the unit healthbar if there is a debuff that can be dispelled by you."] = "如果單位目標的減益光環可被驅散, 加亮顯示其生命值."
+L["Color when the text is about to expire"] = "即將冷卻完畢的數字顏色."
+L["Color when the text is in the days format."] = "以天顯示的文字顏色."
+L["Color when the text is in the hours format."] = "以小時顯示的文字顏色."
+L["Color when the text is in the minutes format."] = "以分顯示的文字顏色."
+L["Color when the text is in the seconds format."] = "以秒顯示的文字顏色."
+L["Colored Icon"] = "圖示色彩"
+L["Coloring (Specific)"] = "著色(具體)"
+L["Coloring"] = "著色"
+L["Colorize Selected Text"] = true
+L["Colors the border according to the Quality of the Item."] = "將背包格子的邊緣根據物品品質上色"
+L["Combat Icon"] = "戰鬥按鈕"
+L["Combat Override Key"] = "戰鬥中顯示按鍵"
+L["CombatText Font"] = "戰鬥文字字體"
+L["Combo Point"] = "連擊點"
+L["Comparison Font Size"] = "比較字體大小"
+L["Condensed"] = "濃縮"
+L["Configure Auras"] = "設置光環"
+L["Control enemy nameplates toggling on or off when in combat."] = "控制戰鬥中敵對姓名板的開啟和關閉"
+L["Control friendly nameplates toggling on or off when in combat."] = "控制戰鬥中友方姓名板的開啟和關閉"
+L["Controls how big of an area on the screen will accept clicks to target unit."] = "決定屏幕上一個多大的光環才允許通過點擊選定到目標框架上"
+L["Controls the amount of decimals used in values displayed on elements like NamePlates and UnitFrames."] = "控制在血條和單位框架等元件的小數位數"
+L["Controls the speed at which smoothed bars will be updated."] = "控制平滑條更新的速度."
+L["Controls how many seconds of inactivity has to pass before chat is faded."] = true
+L["Cooldown Orientation"] = true
+L["Cooldown Text"] = "冷卻文字"
+L["Cooldowns"] = "冷卻"
+L["Copy From"] = "複製自"
+L["Copy Settings From"] = "複製設置"
+L["Copy settings from another unit."] = "從其他框架中複製設置"
+L["Core |cff1784d1E|r|cffe5e3e3lvUI|r options."] = "核心 |cff1784d1E|r|cffe5e3e3lvUI|r 選項"
+L["Count Font Size"] = "計數字體尺寸"
+L["Count xOffset"] = "層數X軸偏移"
+L["Count yOffset"] = "層數Y軸偏移"
+L["Create Custom Text"] = "創建自定義文本"
+L["Create Filter"] = "創造過濾器"
+L["Create a filter, once created a filter can be set inside the buffs/debuffs section of each unit."] = "創建一個過濾器, 創建一次即可讓每個單位的 buff/debuff 都能使用."
+L["Credits"] = "嗚謝"
+L["Crop Icons"] = "切割圖標邊緣"
+L["Currency Format"] = "貨幣格式"
+L["Current - Max | Percent"] = "當前 - 最大 | 百分比"
+L["Current - Max"] = "目前值 - 最大值"
+L["Current - Percent (Remaining)"] = "當前值 - 百分百(剩餘)"
+L["Current - Percent"] = "目前值 - 百分比"
+L["Current - Remaining"] = "當前值 - 剩餘值"
+L["Current / Max"] = "目前/最大值"
+L["Current Level"] = "當前等級"
+L["Current"] = "目前值"
+L["Curse Effect"] = true
+L["Cursor Anchor Offset X"] = "指針錨點X軸偏移"
+L["Cursor Anchor Offset Y"] = "指針錨點Y軸偏移"
+L["Cursor Anchor Type"] = "指針錨點種類"
+L["Cursor Anchor"] = "指針錨點"
+L["Custom Backdrop"] = "自定義背景"
+L["Custom Color"] = "自定顏色"
+L["Custom Dead Backdrop"] = "自定義死亡背景"
+L["Custom Faction Colors"] = "自定義聲望顏色"
+L["Custom Texts"] = "自定義字體"
+L["Custom Texture"] = "自定義材質"
+L["Custom Timestamp Color"] = "自訂時間戳記顏色"
+L["Cutaway Bars"] = "掉血動畫"
+L["Darken Inactive"] = "非啟用者變暗"
+L["DataBars"] = "數據條"
+L["DataTexts"] = "資訊文字"
+L["Datatext Panel (Left)"] = "左側資訊框"
+L["Datatext Panel (Right)"] = "右側資訊框"
+L["Date Format"] = true
+L["Days"] = "天"
+L["Debuff Highlighting"] = "減益光環加亮顯示"
+L["Debug Tools"] = "除錯工具"
+L["Decimal Length"] = "小數位數"
+L["Decimal Threshold"] = "小數閾值"
+L["Decode Text"] = "解碼文字"
+L["Default Color"] = "默認顏色"
+L["Default Font"] = "預設字體"
+L["Default Settings"] = "默認設置"
+L["Deficit"] = "虧損值"
+L["Defines how the group is sorted."] = "定義群組的排序方式."
+L["Defines the sort order of the selected sort method."] = "定義所選排序方式的排序方向."
+L["Delete Filter"] = "刪除過濾器"
+L["Delete a created filter, you cannot delete pre-existing filters, only custom ones."] = "刪除一個創造的過濾器, 你不能刪除內建的過濾器, 只能刪除你自已添加的."
+L["Desaturate Cooldowns"] = "冷卻時"
+L["Desaturate Junk Items"] = "垃圾物品去色"
+L["Desaturated Icon"] = "低飽和度圖標"
+L["Descending"] = "降序"
+L["Detach From Frame"] = "從框架分離"
+L["Detached Width"] = "分離寬度"
+L["Direction the bag sorting will use to allocate the items."] = "整理背包物品時, 將依此排序方向排放物品."
+L["Direction the bar moves on gains/losses"] = "條增加/減少時的方向"
+L["Direction the health bar moves when gaining/losing health."] = "生命條的增減方向."
+L["Disable Bag Sort"] = "停用背包排序"
+L["Disable Bank Sort"] = "停用銀行排序"
+L["Disable Debuff Highlight"] = "禁用Debuff高亮"
+L["Disabled Blizzard Frames"] = "禁用暴雪框架"
+L["Disabled Blizzard"] = "停用暴雪框架"
+L["Disables the focus and target of focus unitframes."] = "禁用焦點和目標的焦點框架"
+L["Disables the player and pet unitframes."] = "禁用玩家和寵物框架"
+L["Disables the target and target of target unitframes."] = "禁用目標和目標的目標框架"
+L["Disconnected"] = "離線"
+L["Disease Effect"] = true
+L["Display Frames"] = "顯示框架"
+L["Display Item Level"] = "顯示物品等級"
+L["Display Player"] = "顯示玩家"
+L["Display Target"] = "顯示目標"
+L["Display Text"] = "顯示文本"
+L["Display a healer icon over known healers inside battlegrounds or arenas."] = "戰場或競技場中, 為已確認為補職的玩家標上補職圖示."
+L["Display a panel across the bottom of the screen. This is for cosmetic only."] = "顯示跨越螢幕底部的面板,僅僅是用于裝飾."
+L["Display a panel across the top of the screen. This is for cosmetic only."] = "顯示跨越螢幕頂部的面板,僅僅是用于裝飾."
+L["Display a spark texture at the end of the castbar statusbar to help show the differance between castbar and backdrop."] = "在施法狀態條的末端顯示一個火花材質來區分施法條和背景條."
+L["Display an exclamation mark on items that starts a quest."] = true
+L["Display battleground messages in the middle of the screen."] = "屏幕中間顯示戰場信息"
+L["Display bind names on action buttons."] = "在快捷列按鈕上顯示快捷鍵名稱."
+L["Display cooldown text on anything with the cooldown spiral."] = "在任何冷卻動畫上顯示技能冷卻時間."
+L["Display data panels below the chat, used for datatexts."] = "在對話框下顯示用於資訊的框架."
+L["Display emotion icons in chat."] = "在對話中顯示表情圖示."
+L["Display guild ranks if a unit is guilded."] = "當目標有公會時顯示其位階."
+L["Display how many of a certain item you have in your possession."] = "顯示當前物品在你身上的數量"
+L["Display macro names on action buttons."] = "在快捷列按鈕上顯示巨集名稱."
+L["Display minimap panels below the minimap, used for datatexts."] = "顯示小地圖下方的資訊框."
+L["Display player titles."] = "顯示玩家稱號."
+L["Display reminder bar on the minimap."] = true
+L["Display the castbar icon inside the castbar."] = "在施法條內顯示圖標"
+L["Display the castbar inside the information panel, the icon will be displayed outside the main unitframe."] = "如果關閉施法條內顯示圖標,你可以自定義施法條外圖標的大小和位置"
+L["Display the hyperlink tooltip while hovering over a hyperlink."] = "滑鼠懸停在超鏈接上時顯示鏈接提示框."
+L["Display the junk icon on all grey items that can be vendored."] = "在所有可販賣的灰色物品上顯示垃圾圖示"
+L["Display the name of the unit on the chat bubble."] = "在聊天氣泡上顯示人物名稱."
+L["Display the npc ID when mousing over a npc tooltip."] = "滑鼠提示中顯示NPC的ID"
+L["Display the spell or item ID when mousing over a spell or item tooltip."] = "滑鼠提示中顯示技能或物品的ID."
+L["Display the target of your current cast. Useful for mouseover casts."] = "顯示你當前的施法目標. 可以轉換成鼠标滑過類型."
+L["Display tick marks on the castbar for channelled spells. This will adjust automatically for spells like Drain Soul and add additional ticks based on haste."] = "若為需引導的法術, 在施法條上顯示每跳週期傷害. 啟動此功能後, 針對吸取靈魂這類的法術, 將自動調整顯示每跳週期傷害, 並視加速等級增加額外的周期傷害."
+L["Displayed server time."] = true
+L["Displays a detailed report of every item sold when enabled."] = "當啟用時顯示一個有關於每個物品賣價的詳細報告"
+L["Displays item level on equippable items."] = "在可裝備物品上顯示裝備等級"
+L["Display Types"] = true
+L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."] = "不顯示高於此時間(單位:秒)的光環. 設置為0以禁用"
+L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."] = "不顯示低於此時間(單位:秒)的光環. 設置為0以禁用"
+L["Donations:"] = "捐款: "
+L["Down"] = "下"
+L["Dropdown CheckBox Skin"] = true
+L["Dungeon & Raid Filter"] = "地城及團隊過濾器"
+L["Duration Enable"] = "啟用持續時間"
+L["Duration Font Size"] = "持續時間文字大小"
+L["Duration Reverse"] = "持續時間反轉"
+L["Duration Text"] = "持續時間文字"
+L["Duration"] = "持續時間"
+L["Editbox History Size"] = true
+L["ELVUI_CREDITS"] = "我想透過這個特別方式, 向那些協助測試、編碼及透過捐款協助過我的人表達感謝, 請曾提供協助的朋友至論壇傳私訊給我, 我會將你的名字添加至此處."
+L["ENEMY_NPC"] = "敵對NPC"
+L["ENEMY_PLAYER"] = "敵對玩家"
+L["Elite Icon"] = "精英標誌"
+L["Emotion Icons"] = "表情圖示"
+L["Enable Custom Color"] = "啟用自定顏色"
+L["Enable the use of separate size options for the right chat panel."] = "啟用獨立的右聊天框大小選項"
+L["Enable/Disable the Bag-Bar."] = "啟用/停用背包條."
+L["Enable/Disable the all-in-one bag."] = "啟用/停用整合背包."
+L["Enable/Disable the loot frame."] = "啟用/停用拾取框架."
+L["Enable/Disable the loot roll frame."] = "啟用/停用擲骰框架."
+L["Enable/Disable the minimap. |cffFF0000Warning: This will prevent you from seeing the consolidated buffs bar, and prevent you from seeing the minimap datatexts.|r"] = "啟用/停用小地圖. |cffFF0000警告: 這將使你無法看見綜合增益框和小地圖資訊欄.|r"
+L["Enable/Disable the scaling of targetted nameplates."] = "啟用/禁用目標姓名板的縮放"
+L["Enables the ElvUI Raid Control panel."] = "啟用ElvUI團隊控制台"
+L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."] = "啟用後將可以在整個團隊內排序, 但你不再可以區分不同小隊"
+L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."] = "啟用後翻轉未滿團隊的隊伍順序(起始方向)"
+L["Enabling this will check your health amount."] = "啟用這個將會檢查你的生命值"
+L["Enabling this will check your power amount."] = "啟用這個將會檢查你的能量值"
+L["Enchanting"] = "附魔"
+L["Enemy Aura Type"] = "敵對光環類型"
+L["Enemy Combat Toggle"] = "敵對戰鬥開關"
+L["Enemy NPC Frames"] = true
+L["Enemy Player Frames"] = true
+L["Enemy"] = "敵對"
+L["Engineering"] = "工程學"
+L["Enhanced PVP Messages"] = "PVP增強信息"
+L["Equipped Item Color"] = true
+L["Equipped Item"] = true
+L["Error decoding data. Import string may be corrupted!"] = "解碼錯誤.導出字符串可能已損壞!"
+L["Error exporting profile!"] = "導出配置文件失敗"
+L["Exclude Name"] = "排除名字"
+L["Excluded Names"] = "排除的名字"
+L["Excluded names will not be class colored."] = "排除的名字將不會使用職業顏色"
+L["Expiring"] = "即將冷卻完畢"
+L["Export Profile"] = "導出配置文件"
+L["Exported"] = "已導出"
+L["FRIENDLY_NPC"] = "友方NPC"
+L["FRIENDLY_PLAYER"] = "友方玩家"
+L["Fade Chat Toggles"] = true
+L["Fade Out Delay"] = "淡出延遲"
+L["Fade Out"] = "漸隱"
+L["Fade Tabs No Backdrop"] = "隱藏拖出的聊天框"
+L["Fade Threshold"] = "漸隱時間閾值"
+L["Fade Undocked Tabs"] = "隱藏分離的聊天框"
+L["Fade the chat text when there is no activity."] = "未出現新訊息時, 隱藏對話框的文字."
+L["Fader"] = "漸隱"
+L["Fades the buttons that toggle chat windows when that window has been toggled off."] = true
+L["Fades the text on chat tabs that are docked in a panel where the backdrop is disabled."] = "當你把一個聊天框拖出聊天背景框的時候會自動隱藏掉,注意這個聊天框並沒有被刪除,關閉該選項你可以重新找到它"
+L["Fades the text on chat tabs that are not docked at the left or right chat panel."] = "當你把一個聊天框設置為分離狀態時會自動隱藏掉,注意這個聊天框並沒有被刪除,關閉該選項你可以重新找到它"
+L["Fill"] = "填充"
+L["Filled"] = "全長"
+L["Filter Priority"] = "過濾器優先順序"
+L["Filter Search"] = "過濾器搜尋"
+L["Filter Type"] = "過濾器類型"
+L["Filter already exists!"] = "過濾器已存在!"
+L["Filters Page"] = "過濾器介面"
+L["Filters are not allowed to have commas in their name. Stripping commas from filter name."] = "過濾器名字稱內不允許有逗號. 清除過濾器名稱內的逗號"
+L["Flash"] = "閃光"
+L["Fluid Position Buffs on Debuffs"] = "增益流動定位在減益上"
+L["Fluid Position Debuffs on Buffs"] = "減益流動定位在增益上"
+L["Flyout Direction"] = "飛出方向"
+L["Flyout Spacing"] = true
+L["Focus"] = "專注目標"
+L["FocusTarget"] = "專注目標的目標"
+L["Font Outline"] = "字體描邊"
+L["Font"] = "字體"
+L["Fonts"] = "字體"
+L["Force Off"] = "強制關閉"
+L["Force On"] = "強制開啓"
+L["Force Reaction Color"] = "強制聲望顏色"
+L["Force the frames to show, they will act as if they are the player frame."] = "強制框架顯示."
+L["Forces Debuff Highlight to be disabled for these frames"] = "為這些框架強制禁用Debuff高亮"
+L["Forces Mouseover Glow to be disabled for these frames"] = "強制關閉這些框架的滑鼠指向發光"
+L["Forces Target Glow to be disabled for these frames"] = "強制關閉這些框架的目標發光"
+L["Forces reaction color instead of class color on units controlled by players."] = "對於玩家控制的角色強制使用聲望顏色而不是職業顏色"
+L["Format"] = "格式"
+L["Frame Glow"] = "框架發光"
+L["Frame Level"] = "框架層次"
+L["Frame Orientation"] = "框架方向"
+L["Frame Strata"] = "框架層級"
+L["Frequent Updates"] = "高頻更新"
+L["Friendly Aura Type"] = "友好目標光環類型"
+L["Friendly Combat Toggle"] = "友方戰鬥開關"
+L["Friendly NPC Frames"] = true
+L["Friendly Player Frames"] = true
+L["Friendly"] = "友好"
+L["Full Overlay"] = "完全覆蓋"
+L["Full"] = "滿"
+L["GM Chat"] = "GM 對話"
+L["GPS Arrow"] = true
+L["Gems"] = "寶石"
+L["General Options"] = "常規選項"
+L["Global (Account Settings)"] = "全域(賬號設置)"
+L["Global Fade Transparency"] = "全局漸隱透明度"
+L["Global"] = "全局"
+L["Glow"] = "閃爍"
+L["Gold Format"] = "金幣格式"
+L["Good Color"] = "正常顏色"
+L["Good Scale"] = "正常縮放"
+L["Good Transition Color"] = "正常過渡顏色"
+L["Good"] = "安全"
+L["Gossip Frame"] = "對話"
+L["Group By"] = "隊伍排列方式"
+L["Group Spacing"] = "隊伍間距"
+L["Grouping & Sorting"] = "分組與排序"
+L["Groups Per Row/Column"] = "每行/列的組數"
+L["Growth Direction"] = "增長方向"
+L["Growth X-Direction"] = "正常X軸偏移"
+L["Growth Y-Direction"] = "正常Y軸偏移"
+L["Growth direction from the first unitframe."] = "增長方向從第一個頭像框架開始."
+L["Guide:"] = "指導:"
+L["Guild Ranks"] = "公會會階"
+L["Guild Registrar"] = "公會註冊"
+L["HH:MM Threshold"] = "HH:MM(時:分) 閾值"
+L["HH:MM"] = "HH:MM(時:分)"
+L["Header Font Size"] = "標題名字大小"
+L["Heal Prediction"] = "治療量預測"
+L["Healer Icon"] = "補職圖示"
+L["Health Backdrop Multiplier"] = "生命條背景混合度"
+L["Health Backdrop"] = "生命條背景"
+L["Health Bar"] = "生命條"
+L["Health Border"] = "生命條邊框"
+L["Health By Value"] = "生命條顏色依數值變化"
+L["Health Color"] = "血量顏色"
+L["Health Length"] = true
+L["Health Threshold"] = "血量閾值"
+L["Health"] = "生命條"
+L["Height Multiplier"] = "高度倍數"
+L["Height of the objective tracker. Increase size to be able to see more objectives."] = "任務框架的高度.增加大小以看到更多目標"
+L["Height"] = "高"
+L["Help Frame"] = "幫助"
+L["Herbalism"] = "草藥學"
+L["Here you can add items or search terms that you want to be excluded from sorting. To remove an item just click on its name in the list."] = "在此你可以新增物品或是搜尋語法來排除排序某些物品. 要移除物品請點選列表中的物品名稱"
+L["Hide At Max Level"] = "在最高等級時隱藏"
+L["Hide Both"] = "全部隱藏"
+L["Hide Error Text"] = "隱藏錯誤文字"
+L["Hide Frame"] = "隱藏框架"
+L["Hide In Combat"] = "戰鬥中隱藏"
+L["Hide In Vehicle"] = "騎乘時隱藏"
+L["Hide Spell Name"] = "隱藏法術名字"
+L["Hide Time"] = "隱藏時間"
+L["Hide specific sections in the datatext tooltip."] = "在資訊文字提示上隱藏特定區塊"
+L["Hide tooltip while in combat."] = "戰鬥時不顯示提示."
+L["Hides the red error text at the top of the screen while in combat."] = "戰鬥中隱藏螢幕頂部紅字錯誤信息."
+L["History Size"] = true
+L["History"] = true
+L["Horizontal Spacing"] = "水平間隔"
+L["Horizontal"] = "水平"
+L["Hours"] = "時"
+L["Hover Highlight"] = "指向高亮"
+L["Hover"] = "滑鼠指向"
+L["How long the cutaway health will take to fade out."] = "生命值漸隱時間長度"
+L["How long the cutaway power will take to fade out."] = "能量值漸隱時間長度"
+L["How many seconds the castbar should stay visible after the cast failed or was interrupted."] = "在施法失敗或被打斷時施法條保持可見的秒數"
+L["How much time before the cutaway health starts to fade."] = "開始生命值漸隱前的時間長度"
+L["How much time before the cutaway power starts to fade."] = "開始能量值漸隱前的時間長度"
+L["Hyperlink Hover"] = "超連結提示資訊"
+L["Icon Frame"] = true
+L["Icon Inside Castbar"] = "施法條內的圖標"
+L["Icon Only"] = true
+L["Icon Position"] = "圖標位置"
+L["Icon Size"] = "圖標尺寸"
+L["Icon"] = "圖示"
+L["Icon: BOTTOM"] = "圖示: 底部"
+L["Icon: BOTTOMLEFT"] = "圖示: 底部左側"
+L["Icon: BOTTOMRIGHT"] = "圖示: 底部右側"
+L["Icon: LEFT"] = "圖示: 左側"
+L["Icon: RIGHT"] = "圖示: 右側"
+L["Icon: TOP"] = "圖示: 頂部"
+L["Icon: TOPLEFT"] = "圖示: 頂部左側"
+L["Icon: TOPRIGHT"] = "圖示: 頂部右側"
+L["Icons and Text (Short)"] = "圖示與文字(簡短)"
+L["Icons and Text"] = "圖示與文字"
+L["If enabled then it checks if auras are missing instead of being present on the unit."] = "如果選中則將會檢查光環是否缺失而不是光環是否存在"
+L["If enabled then it will require all auras to activate the filter. Otherwise it will only require any one of the auras to activate it."] = "如果選中則要求滿足所有光環. 不啟用則只要求任一光環存在即可啟動."
+L["If enabled then it will require all cooldowns to activate the filter. Otherwise it will only require any one of the cooldowns to activate it."] = "如果選中則要求滿足所有冷卻. 否則只要求任一冷卻存在即可啟動."
+L["If enabled then the filter will activate if the unit is casting anything."] = true
+L["If enabled then the filter will activate if the unit is channeling anything."] = true
+L["If enabled then the filter will activate if the unit is not casting anything."] = true
+L["If enabled then the filter will activate if the unit is not channeling anything."] = true
+L["If enabled then the filter will only activate if the level of the unit is equal to or higher than this value."] = "如果選中則過濾器只會在單位等級大於等於該值的時候啟動."
+L["If enabled then the filter will only activate if the level of the unit is equal to or lower than this value."] = "如果選中則過濾器只會在單位等級小於等於該值的時候啟動."
+L["If enabled then the filter will only activate if the level of the unit matches this value."] = "如果選中則過濾器只會在單位等級符合該值的時候啟動"
+L["If enabled then the filter will only activate if the level of the unit matches your own."] = "如果選中則過濾器只會在單位等級符合你的等級的時候啟動"
+L["If enabled then the filter will only activate if the unit is casting interruptible spells."] = "如果選中則過濾器只會在單位施放可打斷技能的時候啟動"
+L["If enabled then the filter will only activate if the unit is casting not interruptible spells."] = "如果選中則過濾器只會在單位施放不可打斷技能的時候啟動"
+L["If enabled then the filter will only activate if the unit is not casting or channeling one of the selected spells."] = "如果選中則過濾器只會在單位未施放或引導任一勾選的技能時啟動."
+L["If enabled then the filter will only activate when you are in combat."] = "如果選中則過濾器只會在你在戰鬥中的時候啟動."
+L["If enabled then the filter will only activate when you are not targeting the unit."] = "如果選中則過濾器只會在你沒有選中單位的時候啟動."
+L["If enabled then the filter will only activate when you are out of combat."] = "如果選中則過濾器只會在你不在戰鬥中的時候啟動."
+L["If enabled then the filter will only activate when you are targeting the unit."] = "如果選中則過濾器只會在你選中單位的時候啟動."
+L["If enabled then the filter will only activate when you have a target."] = true
+L["If not set to 0 then override the size of the aura icon to this."] = "若設為 0, 光環圖示大小將不會變更為此值."
+L["If the aura is listed with a number then you need to use that to remove it from the list."] = "如果光環在列表之中有和一個數字同時設定, 你需要用它來將其移出列表"
+L["If this list is empty, and if 'Interruptible' is checked, then the filter will activate on any type of cast that can be interrupted."] = "如果列表為空, 並且'可打斷'被選中, 那麼過濾器會在任何可被打斷的施法時啟動"
+L["If this threshold is used then the health of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = "如果這個閾值被設置則單位的血量需要比設定值更高才會將過濾器啟動. 設為0以禁用."
+L["If this threshold is used then the health of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = "如果這個閾值被設置則單位的血量需要比設定值更低才會將過濾器啟動. 設為0以禁用."
+L["If this threshold is used then the power of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."] = "如果這個閾值被設置則單位的能量需要比設定值更高才會將過濾器啟動. 設為0以禁用."
+L["If this threshold is used then the power of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."] = "如果這個閾值被設置則單位的能量需要比設定值更低才會將過濾器啟動. 設為0以禁用."
+L["If you have a lot of 3D Portraits active then it will likely have a big impact on your FPS. Disable some portraits if you experience FPS issues."] = "如果你同時激活了很多3D頭像你很可能有FPS的影響.如果你有這方面的問題請禁用一部分頭像"
+L["If you have any plugins supporting this feature installed you can find them in the selection dropdown to the right."] = "如果你安裝了任何支援此功能的插件, 你可以在右邊的下拉選單中找到它"
+L["If you unlock actionbars then trying to move a spell might instantly cast it if you cast spells on key press instead of key release."] = "如果你將快捷列解鎖後嘗試移動技能, 技能可能會馬上施放因為你使用按下施法而非釋放施法"
+L["Ignore UI Scale Popup"] = "忽略介面縮放彈窗"
+L["Ignore mouse events."] = "忽略滑鼠事件."
+L["Ignored Items and Search Syntax (Global)"] = "忽略的物品與搜尋語法 (全局)"
+L["Ignored Items and Search Syntax (Profile)"] = "忽略的物品與搜尋語法 (個人)"
+L["Import Profile"] = "導入配置文件"
+L["Importing"] = "正在導入"
+L["Inactivity Timer"] = true
+L["Index"] = "索引"
+L["Indicate whether buffs you cast yourself should be separated before or after."] = "將你自身施放的增益放於整體增益最前方或或最後方."
+L["InfoPanel Border"] = "信息面板邊框"
+L["Information Panel"] = "信息面板"
+L["Inherit Global Fade"] = "繼承全局漸隱"
+L["Inherit the global fade, mousing over, targetting, setting focus, losing health, entering combat will set the remove transparency. Otherwise it will use the transparency level in the general actionbar settings for global fade alpha."] = "繼承全局漸隱, 當滑鼠滑過, 設為目標, 設為焦點, 損失血量, 進入戰鬥時都會變為不透明, 除此之外將會使用在全局快捷列中的所設定的全局漸隱透明度"
+L["Inset"] = "插入"
+L["Inside Information Panel"] = "插入信息面板"
+L["Install"] = "安裝"
+L["Instance Difficulty"] = "副本難度"
+L["Instance Type"] = "副本類型"
+L["Interruptable"] = "可斷法的施法顏色"
+L["Interruptible"] = "可打斷"
+L["Invert Colors"] = "反轉顏色"
+L["Invert Grouping Order"] = "反轉隊伍排序"
+L["Invert foreground and background colors."] = "反轉前景色和後景色"
+L["Is Casting Anything"] = "施法中"
+L["Is Channeling Anything"] = "引導中"
+L["Is Targeted"] = "目標"
+L["Item Count Font"] = "物品記數字型"
+L["Item Count"] = "物品數量"
+L["Item Level Threshold"] = "物品等級閾值"
+L["Item Level"] = "物品等級"
+L["JustifyH"] = "橫向字體對齊"
+L["Key Down"] = "按下施法"
+L["Keybind Mode"] = "快捷鍵綁定模式"
+L["Keybind Text Position"] = "快捷鍵文字位置"
+L["Keybind Text X-Offset"] = "快捷鍵文字X軸偏移"
+L["Keybind Text Y-Offset"] = "快捷鍵文字Y軸偏移"
+L["Keybind Text"] = "快捷鍵文字"
+L["Keyword Alert"] = "關鍵字警報"
+L["Keywords"] = "關鍵字"
+L["LBF Support"] = true
+L["LEVEL_BOSS"] = "為團隊首領框架設定等級為-1, 也可以設定為0來關閉."
+L["LFD Frame"] = true
+L["LFG Queue"] = "隨機隊列"
+L["LFR Frame"] = true
+L["Latency"] = "延遲"
+L["Leatherworking"] = "製皮"
+L["Left Only"] = "僅顯示左框背景"
+L["Left to Right"] = "左到右"
+L["Left"] = "左"
+L["Limit the number of rows or columns."] = "最大行數或列數."
+L["List of words to color in chat if found in a message. If you wish to add multiple words you must seperate the word with a comma. To search for your current name you can use %MYNAME%.\n\nExample:\n%MYNAME%, ElvUI, RBGs, Tank"] = "如果在對話信息中發現如下文字會自動上色該文字. 如果你需要添加多個詞必須用逗號分開. 如要搜尋角色名稱可使用%MYNAME %.\n\n例如:\n%MYNAME%, ElvUI, RBGs, Tank"
+L["Location Text"] = "所在位置文字"
+L["Lock Positions"] = "鎖定位置"
+L["Log Taints"] = "錯誤記錄"
+L["Log the main chat frames history. So when you reloadui or log in and out you see the history from your last session."] = "記錄對話歷史,當你重載,登錄和退出時會恢復你最後一次會話"
+L["Login Message"] = "登入資訊"
+L["Loot Frames"] = "拾取框架"
+L["Loot Roll"] = "擲骰"
+L["Losing Threat"] = "丟失仇恨"
+L["Low Health Threshold"] = "低生命值閾值"
+L["Low Threat"] = "低仇恨"
+L["Low Threshold"] = "冷卻時間低閾值"
+L["Lower numbers mean a higher priority. Filters are processed in order from 1 to 100."] = "更低的數值意味著更高的優先順序. 過濾器將按照1至100的順序進行."
+L["MM:SS Threshold"] = "MM:SS(分:秒) 閾值"
+L["MM:SS"] = "MM:SS(分:秒)"
+L["Macro Text"] = "巨集名稱"
+L["Magic Effect"] = true
+L["Main Tanks / Main Assist"] = "主坦克 / 主助理"
+L["Main backdrop color of the UI."] = "介面背景主色"
+L["Main border color of the UI."] = "介面邊框主色"
+L["Main statusbar texture."] = "主狀態條材質"
+L["Make textures transparent."] = "材質透明"
+L["Make the unitframe glow yellow when it is below this percent of health, it will glow red when the health value is half of this value."] = "姓名板在此設定值下會變黃色, 在設定值一半以下會變紅色"
+L["Make the world map smaller."] = "讓世界地圖更小."
+L["Map Opacity When Moving"] = "移動時地圖透明度"
+L["Maps"] = "地圖"
+L["Match Frame Width"] = "匹配視窗寬度"
+L["Match Player Level"] = "符合玩家等級"
+L["Max Alpha"] = "最大透明度"
+L["Max Bars"] = "最多"
+L["Max Lines"] = true
+L["Max Overflow"] = "最大治療吸收盾"
+L["Max Wraps"] = "每行最大數"
+L["Max amount of overflow allowed to extend past the end of the health bar."] = "顯示在生命值條末端的治療吸收盾的最大量"
+L["Maximum Duration"] = "最大持續時間"
+L["Maximum Level"] = "最高等級"
+L["Maximum Time Left"] = "最大時間剩餘"
+L["Media"] = "材質"
+L["Method to sort by."] = "排序方式"
+L["Middle Click - Set Focus"] = "滑鼠中鍵 - 設置焦點"
+L["Middle clicking the unit frame will cause your focus to match the unit."] = "滑鼠中鍵點擊單位框架設置焦點."
+L["Middle"] = "中間"
+L["Min Alpha"] = "最小透明度"
+L["Minimap Mouseover"] = "小地圖滑鼠滑過"
+L["Minimap Panels"] = "小地圖欄"
+L["Minimum Duration"] = "最低持續時間"
+L["Minimum Level"] = "最低等級"
+L["Minimum Time Left"] = "最小時間剩餘"
+L["Mining"] = "採礦"
+L["Minutes"] = "分"
+L["Mirror Timers"] = "鏡像計時器"
+L["Misc Frames"] = "其他"
+L["Missing"] = "缺失"
+L["Modulating Blend"] = "無視 Alpha 通道混合"
+L["Module Control"] = "模組控制"
+L["Module Copy"] = "模組複製"
+L["Module Reset"] = "模組重置"
+L["Money Format"] = "金幣格式"
+L["Mouse Over"] = "滑鼠滑過顯示"
+L["Mouseover Glow"] = "滑鼠指向發光"
+L["Mouseover Highlight"] = "滑鼠指向高亮"
+L["Mouseover"] = "滑鼠滑過顯示"
+L["Multi-Monitor Support"] = "多顯示器支援"
+L["Multiply the backdrops height or width by this value. This is usefull if you wish to have more than one bar behind a backdrop."] = "根據此值增加背景的高度或寬度. 一般用來設定在一個背景框裡放置多條快捷列."
+L["NPC IDs"] = "NPC的ID"
+L["Name Color"] = "姓名顏色"
+L["Name Colored Glow"] = "姓名顏色高亮"
+L["Name Font"] = "名稱字體"
+L["Name Only"] = "僅姓名"
+L["Name"] = "姓名"
+L["NamePlate Style Filters"] = "姓名版樣式過濾器"
+L["NamePlates"] = "姓名板(血條)"
+L["Nameplate"] = "姓名板"
+L["Neutral"] = "中立"
+L["Never Hide"] = "從不隱藏"
+L["No Alert In Combat"] = "戰鬥中不警報"
+L["No Duration"] = true
+L["No Sorting"] = "不分類"
+L["Non-Interruptable"] = "不可斷法的施法條色"
+L["Non-Target Alpha"] = "非目標透明度"
+L["Not Casting Anything"] = "不在施法中"
+L["Not Channeling Anything"] = "不在引導中"
+L["Not Spell"] = "非法術"
+L["Not Targeted"] = "非目標"
+L["Not Usable"] = "無法使用"
+L["Not valid spell id"] = "無效的技能ID"
+L["Num Rows"] = "行數"
+L["Number of Groups"] = "每隊單位數量"
+L["Number of messages you scroll for each step."] = "每次滾動的聊天資訊數目"
+L["Number of repeat characters while in combat before the chat editbox is automatically closed. Set to 0 to disable."] = "當你在戰鬥中按下技能鍵時,有可能你的輸入框還處於打開狀態,這個功能可以在你按下技能鍵並且在輸入框中輸入下列個數字符串卻沒有放出技能時幫你自動關閉輸入框. 設為0以禁用."
+L["Number of time in seconds to scroll down to the bottom of the chat window if you are not scrolled down completely."] = "對話框滾動到底部所需要的滾動時間(秒)."
+L["Objective Frame Height"] = "任務框架高度"
+L["Off Cooldown"] = "冷卻外"
+L["Offset of the powerbar to the healthbar, set to 0 to disable."] = "偏移能量條與生命條的位置, 設定為0 禁用此功能."
+L["Offset position for text."] = "偏移文本的位置."
+L["Offset"] = "偏移"
+L["On Cooldown"] = "冷卻中"
+L["Only Match SpellID"] = "僅匹配法術ID"
+L["Only show when the unit is not in range."] = "不在範圍內時顯示."
+L["Only show when you are mousing over a frame."] = "滑鼠滑過時顯示."
+L["Other Filter"] = "其他過濾器"
+L["Other's First"] = "他人光環優先"
+L["Others"] = "他人的"
+L["Out of Power"] = "施放能量不足"
+L["Out of Range"] = "超出施放範圍"
+L["Over Health Threshold"] = "高於血量閾值"
+L["Over Power Threshold"] = "高於能量閾值"
+L["Overlay Alpha"] = "重疊不透明度"
+L["Overlay"] = "重疊顯示"
+L["Overnuking"] = true
+L["Override any custom visibility setting in certain situations, EX: Only show groups 1 and 2 inside a 10 man instance."] = "複寫可見性的設定, 例如: 在10人副本里只顯示1隊和2隊."
+L["Override the default class color setting."] = "覆蓋默認職業色設置."
+L["Owners Name"] = "所有者姓名"
+L["PVP Trinket"] = "PVP 飾品"
+L["Panel Backdrop"] = "對話框背景"
+L["Panel Height"] = "對話框高度"
+L["Panel Texture (Left)"] = "對話框材質(左)"
+L["Panel Texture (Right)"] = "對話框材質(右)"
+L["Panel Transparency"] = "面板透明"
+L["Panel Width (Bags)"] = "框架寬度 (背包)"
+L["Panel Width (Bank)"] = "框架寬度 (銀行)"
+L["Panel Width"] = "對話框寛度"
+L["Panels"] = "對話框"
+L["Parent"] = "跟隨框架"
+L["Party / Raid"] = "小隊/團隊"
+L["Party Only"] = "僅小隊"
+L["Party Pets"] = "隊伍寵物"
+L["Party Targets"] = "隊伍目標"
+L["Per Row"] = "每行"
+L["Percent"] = "百分比"
+L["Personal"] = "自己的"
+L["Pet Name"] = "寵物名字"
+L["Pet"] = "寵物"
+L["PetTarget"] = "寵物目標"
+L["Petition Frame"] = "回報GM"
+L["Pick Up Action Key"] = true
+L["Player Frame Aura Bars"] = "玩家框架光環條"
+L["Player Health"] = "玩家血量"
+L["Player Out of Combat"] = "玩家戰鬥外"
+L["Player Target"] = "玩家目標"
+L["Player Titles"] = "玩家稱號"
+L["Player in Combat"] = "玩家戰鬥中"
+L["Player"] = "玩家"
+L["Plugin"] = "插件"
+L["Poison Effect"] = true
+L["Portrait"] = "頭像"
+L["Position Buffs on Debuffs"] = "增益在減益上"
+L["Position Debuffs on Buffs"] = "減益在減益上"
+L["Position of the Chat EditBox, if datatexts are disabled this will be forced to be above chat."] = "對話編輯框位置,如果底部的信息文字被禁用的話,將會強制顯示在對話框頂部."
+L["Position"] = "位置"
+L["Power Threshold"] = "能量閾值"
+L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."] = "NPC 目標將隱藏能量值文字."
+L["Power"] = "能量"
+L["Powers"] = "能量"
+L["Prevent the same messages from displaying in chat more than once within this set amount of seconds, set to zero to disable."] = "單位時間(秒) 內屏蔽重複對話信息, 設定為0 禁用此功能."
+L["Primary Texture"] = "主要材質"
+L["Priority"] = "優先級"
+L["Private (Character Settings)"] = "個人(角色配置)"
+L["Profession Bags"] = "專業背包"
+L["Profile Name"] = "配置文件名稱"
+L["Profile Specific"] = "角色專用"
+L["Profile imported successfully!"] = "配置文件導入成功"
+L["Profile"] = "配置文件"
+L["Progress Bar"] = "進度條"
+L["Puts coordinates on the world map."] = "在世界地圖上放置坐標"
+L["PvP Frames"] = "PvP框架"
+L["PvP Icon"] = "PvP和威望圖標"
+L["PvP Queue"] = true
+L["PvP Text"] = "PvP文字"
+L["Quest Frames"] = "任務"
+L["Quest Starter"] = "任務接取物品"
+L["Quiver"] = true
+L["RAID_CONTROL"] = "團隊管理"
+L["RL / ML Icons"] = "團隊隊長/裝備分配圖示"
+L["Raid Difficulty"] = "團隊難度"
+L["Raid Frame"] = "團隊框架"
+L["Raid Icon"] = "團隊圖示"
+L["Raid Only"] = "僅團隊"
+L["Raid Pet"] = "團隊寵物框架"
+L["Raid-40"] = "40人團隊框架"
+L["Raid-Wide Sorting"] = "全團隊排序"
+L["RaidDebuff Indicator"] = "團隊副本減益光環標示"
+L["Range"] = "距離"
+L["Rapidly update the health, uses more memory and cpu. Only recommended for healing."] = "實時更新生命值會佔用更多的內存的和CPU, 只推薦治療角色開啟."
+L["Reaction Castbars"] = "聲望施法條"
+L["Reaction Colors"] = "聲望顏色"
+L["Reaction Type"] = "聲望類型"
+L["Reactions"] = "陣營聲望"
+L["Ready Check Icon"] = "準備確認圖標"
+L["Realm Time"] = true
+L["Remaining / Max"] = "剩餘時間 / 最大時間"
+L["Remaining Time"] = "剩餘時間"
+L["Remaining"] = "剩餘數值"
+L["Reminder"] = true
+L["Remove Backdrop"] = "移除背景"
+L["Remove Name"] = "刪除篩選名"
+L["Remove Spell ID or Name"] = "移除法術ID或法術名"
+L["Remove Spell"] = "移除技能"
+L["Remove SpellID"] = "移除技能ID"
+L["Remove a Name from the list."] = true
+L["Remove a spell from the filter. Use the spell ID if you see the ID as part of the spell name in the filter."] = "從過濾器中移除一個技能. 當你看見有ID在過濾器中的技能名字時使用技能ID"
+L["Remove a spell from the filter."] = "從過濾器中移除一個技能."
+L["Replace Blizzard Fonts"] = "替代暴雪字體"
+L["Replaces the default Blizzard fonts on various panels and frames with the fonts chosen in the Media section of the ElvUI Options. NOTE: Any font that inherits from the fonts ElvUI usually replaces will be affected as well if you disable this. Enabled by default."] = "用ElvUI字體設置代替暴雪原有字體設置,如果禁用有可能導致你的UI出問題,默認開啟開選項."
+L["Reposition Window"] = "重置窗口位置"
+L["Require All"] = "要求全部"
+L["Require Target"] = true
+L["Require holding the Alt key down to move cursor or cycle through messages in the editbox."] = "開啟該選項使你在查看聊天歷史記錄時需要按住Alt+上下鍵,如果關閉則直接按上下鍵即可"
+L["Reset Anchors"] = "重置位置"
+L["Reset Aura Filters"] = "重置光環過濾器"
+L["Reset Editbox History"] = true
+L["Reset Filter"] = "重置過濾器"
+L["Reset History"] = true
+L["Reset Priority"] = "重置優先順序"
+L["Reset Zoom"] = "重置縮放"
+L["Reset all frames to their original positions."] = "重設所有框架至預設位置."
+L["Reset filter priority to the default state."] = "重置過濾器優先順序到預設狀態"
+L["Reset the size and position of this frame."] = "重置這個框架位置和大小"
+L["Rest Icon"] = "充分休息圖示"
+L["Restore Bar"] = "還原快捷列"
+L["Restore Defaults"] = "恢復預設"
+L["Restore the actionbars default settings"] = "恢復此快捷列的預設設定"
+L["Resurrect Icon"] = "復活圖標"
+L["Return filter to its default state."] = "返回過濾器至預設狀態"
+L["Reverse Bag Slots"] = "反向背包格子"
+L["Reverse Cooldown"] = true
+L["Reverse Style"] = "倒序風格"
+L["Reverse Toggle will enable Cooldown Text on this module when the global setting is disabled and disable them when the global setting is enabled."] = "反向開關將在全局設定為不開啟時開啟, 同樣的, 在全局設定為開啟時, 將會關閉."
+L["Reverse Toggle"] = "反向開關"
+L["Right Only"] = "僅顯示右框背景"
+L["Right Panel Height"] = "右面板高度"
+L["Right Panel Width"] = "右面板寬度"
+L["Right to Left"] = "右到左"
+L["Right"] = "右"
+L["RightClick Self-Cast"] = "右鍵自我施法"
+L["Role Icon"] = "角色定位圖示"
+L["Run the installation process."] = "執行安裝程序"
+L["Sanctuary"] = true
+L["Scale of the nameplate that is targetted."] = "縮放選定目標的姓名板"
+L["Scale"] = "縮放"
+L["Scroll Interval"] = "滾動間隔"
+L["Scroll Messages"] = "滾動資訊數目"
+L["Search Syntax"] = "搜尋語法"
+L["Search for a spell name inside of a filter."] = "在過濾器內搜尋一個法術名稱"
+L["Secondary Texture"] = "次要材質"
+L["Seconds remaining on the aura duration before the bar starts moving. Set to 0 to disable."] = true
+L["Seconds"] = "秒"
+L["Selected Text Color"] = true
+L["Selector Color"] = true
+L["Selector Style"] = true
+L["Securely Tanking"] = true
+L["Select Filter"] = "選擇過濾器"
+L["Select Spell"] = "選擇技能"
+L["Select a profile to copy from/to."] = "選擇一個設定文件來當作複製的來源或目標"
+L["Select a unit to copy settings from."] = "選擇從哪單位複制."
+L["Select the display method of the portrait."] = "選擇頭像的顯示方式"
+L["Sell Interval"] = "販賣間格"
+L["Send ADDON_ACTION_BLOCKED errors to the Lua Error frame. These errors are less important in most cases and will not effect your game performance. Also a lot of these errors cannot be fixed. Please only report these errors if you notice a Defect in gameplay."] = "發送ADDON_ACTION_BLOCKED錯誤至Lua錯誤框, 這些錯誤並不重要, 不會影響你的遊戲體驗. 並且很多這類錯誤無法被修復. 請只將影響遊戲體驗的錯誤發送給我們."
+L["Sends your current profile to your target."] = "發送你的配置文件到當前目標."
+L["Sends your filter settings to your target."] = "發送你的過濾器配置到當前目標."
+L["Separate Panel Sizes"] = "分離框架大小"
+L["Seperate"] = "光環分離"
+L["Set Settings to Default"] = "恢復默認設置"
+L["Set the alpha level of portrait when frame is overlayed."] = "當框體被遮擋時頭像的不透明度."
+L["Set the filter type. Blacklist will hide any auras in the list and show all others. Whitelist will show any auras in the filter and hide all others."] = "設置過濾器類型. 黑名單將隱藏列表內的任何光環而顯示其他. 白名單將顯示過濾器內的任何光環而隱藏其他所有光環."
+L["Set the font outline."] = "字體描邊設定."
+L["Set the font size for everything in UI. Note: This doesn't effect somethings that have their own seperate options (UnitFrame Font, Datatext Font, ect..)"] = "設定介面上所有字體的尺寸, 但不包含本身有獨立設定的字體(如單位框架字體、資訊文字字體等...)"
+L["Set the font size for unitframes."] = "設定單位框架字體尺寸."
+L["Set the order that the group will sort."] = "設定組排序的順序."
+L["Set the orientation of the UnitFrame."] = "設置框架的方向"
+L["Set the priority order of the spell, please note that prioritys are only used for the raid debuff module, not the standard buff/debuff module. If you want to disable set to zero."] = "設定該法術的優先順序. 請注意, 優先級只用於Raid Debuff模塊, 而不是標準的Buff/Debuff模塊. 設定為0 禁用此功能."
+L["Set the size of the individual auras."] = "設定每個光環的尺寸."
+L["Set the size of your bag buttons."] = "設定你的背包格子大小."
+L["Set the type of auras to show when a unit is a foe."] = "當單位是敵對時設定光環顯示的類型."
+L["Set the type of auras to show when a unit is friendly."] = "當單位是友好時設定光環顯示的類型."
+L["Set to either stack nameplates vertically or allow them to overlap."] = "設置將姓名板垂直排列或者允許重疊"
+L["Sets the font instance's horizontal text alignment style."] = "設定橫向字體的對齊方式."
+L["Share Current Profile"] = "分享當前的配置文件"
+L["Share Filters"] = "分享過濾器配置"
+L["Short (Whole Numbers)"] = "短 (完整數字)"
+L["Short Channels"] = "隱藏頻道名稱"
+L["Shortcut to 'Filters' section of the config."] = "一個到'過濾器'功能表的快速鍵"
+L["Shortcut to global filters."] = "全局過濾器快速鍵"
+L["Shortcuts"] = "快速鍵"
+L["Shorten the channel names in chat."] = "在對話視窗中隱藏頻道名稱."
+L["Should tooltip be anchored to mouse cursor"] = "提示錨定在滑鼠"
+L["Show Aura From Other Players"] = "顯示其他玩家的光環"
+L["Show Auras"] = "顯示光環"
+L["Show Bind on Equip/Use Text"] = "顯示裝綁文字"
+L["Show Both"] = "全部顯示"
+L["Show Coins"] = "顯示硬幣"
+L["Show Dispellable Debuffs"] = "顯示無法驅散的debuff"
+L["Show Empty Buttons"] = "顯示空白按鈕"
+L["Show For DPS"] = "為輸出顯示"
+L["Show For Healers"] = "為治療顯示"
+L["Show For Tanks"] = "為坦克顯示"
+L["Show Icon"] = "顯示图示"
+L["Show Junk Icon"] = "顯示垃圾圖示"
+L["Show Quality Color"] = "顯示品質圖標"
+L["Show Quest Icon"] = true
+L["Show When Not Active"] = "顯示當前無效的光環"
+L["Show an incoming heal prediction bar on the unitframe. Also display a slightly different colored bar for incoming overheals."] = "在單位框架中顯示即將回复的的預測治療量, 過量治療則以不同顏色顯示. "
+L["Show the castbar icon desaturated if a spell is not interruptible."] = "在法術不可被打斷時顯示去色圖標。"
+L["Show/Hide Test Frame"] = "顯示/關閉測試框架"
+L["Side Arrows"] = "側面箭頭"
+L["Size Override"] = "尺寸覆蓋"
+L["Size and Positions"] = "大小和位置"
+L["Size of the indicator icon."] = "提示圖示尺寸"
+L["Size"] = "尺寸"
+L["Skin Backdrop (No Borders)"] = "美化背景(無邊界)"
+L["Skin Backdrop"] = "美化背景"
+L["Skin the blizzard chat bubbles."] = "美化暴雪對話泡泡."
+L["Skins"] = "美化外觀"
+L["Small Panels"] = "迷你面板"
+L["Smaller World Map"] = "縮小世界地圖"
+L["Smart Aura Position"] = "智能光環位置"
+L["Smart Raid Filter"] = "智能團隊過濾"
+L["Smart"] = "智慧"
+L["Smooth Bars"] = "條平滑化"
+L["Smooth"] = "平滑"
+L["Smoothing Amount"] = "平滑程度"
+L["Socket Frame"] = "珠寶插槽"
+L["Sort By"] = "排序"
+L["Sort Direction"] = "排序方向"
+L["Sort Inverted"] = "倒序排列"
+L["Sort Method"] = "分類方式"
+L["Soul Bag"] = true
+L["Spaced"] = "留空"
+L["Spacing"] = "間隙"
+L["Spam Interval"] = "洗頻訊息間隔"
+L["Spark"] = "火花"
+L["Spell/Item IDs"] = "技能/物品ID"
+L["Split"] = "分割"
+L["Stable"] = "獸欄"
+L["Stack Counter"] = "層數計數"
+L["Stack Text Position"] = "層數文字位置"
+L["Stack Text X-Offset"] = "層數文字X軸偏移"
+L["Stack Text Y-Offset"] = "層數文字Y軸偏移"
+L["Stack Threshold"] = "層數閾值"
+L["Start Near Center"] = "由中心開始"
+L["StatusBar Texture"] = "狀態條材質"
+L["Statusbar Fill Orientation"] = "狀態條填充方向"
+L["Statusbar"] = true
+L["Sticky Chat"] = "記憶對話頻道"
+L["Strata and Level"] = "框架層級和層次"
+L["Style Filter"] = "樣式過濾器"
+L["Style"] = "風格"
+L["Tab Font Outline"] = "分頁字體描邊"
+L["Tab Font Size"] = "分頁字體尺寸"
+L["Tab Font"] = "分頁字體"
+L["Tab Panel Transparency"] = "標籤面板透明"
+L["Tab Panel"] = "標籤面板"
+L["Tab Selector"] = true
+L["Tabard Frame"] = "外袍"
+L["Table"] = "表"
+L["Tank Target"] = "坦克目標"
+L["Tank"] = "坦克"
+L["Tapped"] = "被攻擊"
+L["Target Indicator Color"] = "目標指示器顏色"
+L["Target Info"] = "目標信息"
+L["Target On Mouse-Down"] = "滑鼠按下設為目標"
+L["Target Scale"] = "目標縮放"
+L["Target units on mouse down rather than mouse up. \n\n|cffFF0000Warning: If you are using the addon 'Clique' you may have to adjust your clique settings when changing this."] = "按下滑鼠時設為目標,而不是鬆開滑鼠按鍵時. \n\n|cffFF0000警告: 如果使用'Clique'等點擊施法插件, 你可能需要調整這些插件的設置."
+L["Target/Low Health Indicator"] = "目標指示器"
+L["TargetTarget"] = "目標的目標"
+L["TargetTargetTarget"] = "目標的目標的目標"
+L["Targeted Glow"] = "目標發光"
+L["Targeting"] = "當前目標"
+L["Testing:"] = "測試:"
+L["Text Fade"] = true
+L["Text Color"] = "文字顔色"
+L["Text Font Size"] = "字體大小"
+L["Text Format"] = "文字格式"
+L["Text Position"] = "文字位置"
+L["Text Threshold"] = "文本閾值"
+L["Text Toggle On NPC"] = "NPC 文字顯示開關"
+L["Text xOffset"] = "文字X軸偏移"
+L["Text yOffset"] = "文字Y軸偏移"
+L["Text"] = "文本"
+L["Texture"] = "材質"
+L["Textured Icon"] = "圖示紋理"
+L["Textures"] = "材質"
+L["The Portrait will overlay the Healthbar. This will be automatically happen if the Frame Orientation is set to Middle."] = "頭像將會覆蓋于生命條之上. 如果框架方向設為中的話, 這將會自動啟用."
+L["The Thin Border Theme option will change the overall apperance of your UI. Using Thin Border Theme is a slight performance increase over the traditional layout."] = "細邊框主題會改變所有的外觀,使用細邊框主題會略微提升性能"
+L["The amount of buttons to display per row."] = "每行所顯示的按鈕數量."
+L["The amount of buttons to display."] = "快捷列按鈕顯示數量."
+L["The button you must hold down in order to drag an ability to another action button."] = "需按住此按鈕, 才可將技能拖曳至另一快捷鈕中."
+L["The debuff needs to reach this amount of stacks before it is shown. Set to 0 to always show the debuff."] = "減益需要達到這個數量的層數才會顯示. 設為0來一直顯示它."
+L["The direction that the bag frames be (Horizontal or Vertical)."] = "背包框架排序方向 (水平或垂直)."
+L["The direction that the bag frames will grow from the anchor."] = "新增的背包框架將從錨點依此方向增加."
+L["The direction the auras will grow and then the direction they will grow after they reach the wrap after limit."] = "光環增加的方向與到達每行最大數後換行增加的方向"
+L["The display format of the currency icons that get displayed below the main bag. (You have to be watching a currency for this to display)"] = "背包主框架下方的兌換通貨圖示顯示格式.需先設定監控特定兌換通貨, 才會顯示於背包框架."
+L["The display format of the money text that is shown at the top of the main bag."] = "在背包主框架上方的金幣顯示格式"
+L["The display format of the money text that is shown in the gold datatext and its tooltip."] = "在信息文字中顯示的金錢格式"
+L["The first button anchors itself to this point on the bar."] = "快捷列第一個按鈕的所在位置."
+L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."] = "為了顯示設定過的過濾器下面的巨集必須啟用."
+L["The font that appears on the text above players heads. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "玩家頭頂姓名的字體. |cffFF0000警告: 你需要重新開啟遊戲或重新登錄才能使用此功能.|r"
+L["The font that combat text will use. |cffFF0000WARNING: This requires a game restart or re-log for this change to take effect.|r"] = "戰鬥資訊將使用此字體, |cffFF0000警告:需重啟遊戲或重新登入才可使此變更生效.|r"
+L["The font that the core of the UI will use."] = "核心UI 所使用的字體."
+L["The font that the unitframes will use."] = "單位框架字體."
+L["The frame is not shown unless you mouse over the frame."] = "僅於滑鼠移經快捷列時顯示框架."
+L["The initial group will start near the center and grow out."] = "最初的隊伍由中心開始增長."
+L["The minimum item level required for it to be shown."] = "顯示的最低物品等級"
+L["The name you have selected is already in use by another element."] = "你所選的名稱已經被另一組件佔用."
+L["The object you want to attach to."] = "你想依附的目標."
+L["The size of the action buttons."] = "快捷列按鈕尺寸."
+L["The size of the individual buttons on the bag frame."] = "背包框架單個格子的大小."
+L["The size of the individual buttons on the bank frame."] = "銀行框架單個格子的大小."
+L["The spacing between buttons."] = "兩個按鈕間的距離."
+L["The spacing between the backdrop and the buttons."] = "背景與按鈕之間的間隙"
+L["The texture that will be used mainly for statusbars."] = "此材質主用於狀態列上."
+L["The unit prefixes you want to use when values are shortened in ElvUI. This is mostly used on UnitFrames."] = "在ElvUI中數值單位的縮寫. 該選項主要應用在單位框架."
+L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."] = "這些過濾器不像常規過濾器那樣使用一個法術列表, 而是使用魔獸API和部分代碼邏輯來決定光環顯示與否."
+L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."] = "這些過濾器使用一個法術清單來決定光環顯示與否. 這些過濾器的內容可以在設置中的'過濾器'選項中更改."
+L["Thin Border Theme"] = "細邊框主題"
+L["Thin Borders"] = "細邊框"
+L["This dictates the size of the icon when it is not attached to the castbar."] = "指定未吸附在施法條內時圖示的尺寸"
+L["This feature will allow you to transfer settings to other characters."] = "此功能將使你設置轉移給其他角色."
+L["This is for Customized Icons in your Interface/Icons folder."] = "取決於你是否在 Interface/Icons 資料夾中放置了自定義圖標"
+L["This opens the UnitFrames Color settings. These settings affect all unitframes."] = "這將開啟單位框架顏色設置.這些設置會影響所有單位框架"
+L["This option allows the overlay to span the whole health, including the background."] = "這將允許覆蓋層在包括背景的整個生命條之上."
+L["This section will allow you to copy settings to a select module from or to a different profile."] = "這個部分允許你複製到或是匯入其他的設定文件所選擇的部分的模組設定"
+L["This section will help reset specfic settings back to default."] = "這個部分會幫助你重置指定的模組設定回預設值"
+L["This selects the Chat Frame to use as the output of ElvUI messages."] = "選擇ElvUI訊息輸出的聊天視窗"
+L["This setting controls the size of text in item comparison tooltips."] = "設置對比框中的文字大小"
+L["This setting will be updated upon changing stances."] = "此設定將在切換姿態時更新"
+L["This texture will get used on objects like chat windows and dropdown menus."] = "主要用於對話視窗及下拉選單等物件的材質."
+L["This will override the global cooldown settings."] = "這將覆蓋全局的冷卻設定."
+L["This will prevent the UI Scale Popup from being shown when changing the game window size."] = "在修改遊戲窗口大小時的介面縮放彈窗將不會彈出"
+L["This will reset the contents of this filter back to default. Any spell you have added to this filter will be removed."] = "這會重置這個過濾器到初始狀態. 你添加到這個過濾器的任何技能都會被刪除."
+L["Threat Display Mode"] = "仇恨顯示模式"
+L["Threat Health"] = "仇恨血量"
+L["Threat Power"] = "仇恨能量"
+L["Threat"] = "仇恨"
+L["Threshold (in minutes) before text is shown in the HH:MM format. Set to -1 to never change to this format."] = "低於設定的閾值(單位:分)時, 將會採用 HH:MM 的格式. 設定為 -1 可禁用改格式"
+L["Threshold (in seconds) before text is shown in the MM:SS format. Set to -1 to never change to this format."] = "低於設定的閾值(單位:秒)時, 將會採用 MM:SS 的格式. 設定為 -1 可禁用改格式"
+L["Threshold before text goes into decimal form. Set to -1 to disable decimals."] = "文字變為小數時的閾值.設為-1以禁用小數"
+L["Threshold before text turns red and is in decimal form. Set to -1 for it to never turn red"] = "冷卻時間低於此秒數後將變為紅色數字, 並以小數顯示, 設為- 1 冷卻時間將不會變為紅色."
+L["Threshold before the icon will fade out and back in. Set to -1 to disable."] = "圖示會漸隱再出現的閾值. 設成-1來停用"
+L["Ticks"] = "週期傷害"
+L["Time Format"] = true
+L["Time Indicator Colors"] = "時間指示器顏色"
+L["Time Remaining Reverse"] = "剩餘時間反轉"
+L["Time Remaining"] = "剩餘時間"
+L["Time To Hold"] = "停留時間"
+L["Time xOffset"] = "時間X軸偏移"
+L["Time yOffset"] = "時間Y軸偏移"
+L["Time"] = "時間"
+L["Timestamp Color"] = "時間戳顏色"
+L["Toggle Anchors"] = "解鎖元件定位"
+L["Toggle Off While In Combat"] = "戰鬥時關閉"
+L["Toggle On While In Combat"] = "戰鬥時啟用"
+L["Toggle Tutorials"] = "教學開關"
+L["Toggle showing of the left and right chat panels."] = "顯示/隱藏左、右對話框背景."
+L["Toggle the chat tab panel backdrop."] = "顯示/隱藏對話框架標籤面板背景."
+L["Toggles the display of the actionbars backdrop."] = "顯示/隱藏快捷列背景框."
+L["Tooltip Font Settings"] = "提示文字設置"
+L["Top Arrow"] = "頂部箭頭"
+L["Top Left"] = "左上"
+L["Top Panel"] = "頂部面板"
+L["Top Right"] = "右上"
+L["Top to Bottom"] = "頂部至底部"
+L["Top"] = "上"
+L["TopLeftMiniPanel"] = "小地圖左上 (內側)"
+L["TopMiniPanel"] = "小地圖上方 (內側)"
+L["TopRightMiniPanel"] = "小地圖右上 (內側)"
+L["Totem"] = true
+L["Trainer Frame"] = "訓練師"
+L["Transparency level when not in combat, no target exists, full health, not casting, and no focus target exists."] = "當非戰鬥, 沒有目標, 滿血, 未施法且沒有焦點目標存在時的透明度"
+L["Transparent Backdrops"] = true
+L["Transparent Buttons"] = true
+L["Transparent"] = "透明"
+L["Triggers"] = "觸發器"
+L["Turtle Color"] = "減傷類的顏色"
+L["Tutorial Frame"] = true
+L["URL Links"] = "網址連結"
+L["Under Health Threshold"] = "低於血量閾值"
+L["Under Power Threshold"] = "低於能量閾值"
+L["Uniform Threshold"] = "統一閾值"
+L["Unique Units"] = true
+L["Unit Prefix Style"] = "單位縮寫"
+L["Unit Target"] = "單位目標"
+L["Unit Type"] = "單位類型"
+L["UnitFrames"] = "單位框架"
+L["Unlock various elements of the UI to be repositioned."] = "解鎖介面上的各種元件, 以便更改位置."
+L["Up"] = "上"
+L["Usable"] = "可以使用"
+L["Use Alt Key"] = "使用 Alt 鍵"
+L["Use Class Color"] = "使用職業顏色"
+L["Use Custom Level"] = "使用自訂層次"
+L["Use Custom Strata"] = "使用自訂層級"
+L["Use Dead Backdrop"] = "死亡背景"
+L["Use Default"] = "自定義默認值"
+L["Use Indicator Color"] = "使用指示器顏色"
+L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."] = "使用 Shift + 左键 来切换友方狀態, 敵方狀態及正常狀態. 正常狀態將允許在所有單位上設為啟用的過濾器.友方狀態僅允許用於友方單位的過濾器, 敵方狀態僅允許用於敵方單位的過濾器."
+L["Use Target Scale"] = "使用目標縮放"
+L["Use Threat Color"] = "使用仇恨顏色"
+L["Use class color for the names of players when they are mentioned."] = "當玩家名字被提及時使用職業顏色"
+L["Use coin icons instead of colored text."] = "使用硬幣圖示取代上色文字"
+L["Use drag and drop to rearrange filter priority or right click to remove a filter."] = "使用拖拽的方式調整過濾器優先順序, 或者右鍵移除一個過濾器"
+L["Use the Name Color of the unit for the Name Glow."] = true
+L["Use the custom backdrop color instead of a multiple of the main color."] = "使用自定義的背景色而不是多種主色."
+L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."] = "使用配置文件內的增益指示器而不是全域的"
+L["Use thin borders on certain unitframe elements."] = "使用細邊框"
+L["Use this backdrop color for units that are dead or ghosts."] = "死亡或靈魂狀態背景"
+L["Used as RaidDebuff Indicator"] = "作為團隊 Debuff 指示器"
+L["Value Color"] = "數值顏色"
+L["Value must be a number"] = "數值必須為一個數字"
+L["Vehicle Seat Indicator Size"] = "載具座位指示器大小"
+L["Vehicle"] = "載具"
+L["Vendor Gray Detailed Report"] = "詳細報告灰色物品售賣"
+L["Vendor Grays"] = "出售灰色物品"
+L["Version"] = "版本"
+L["Vertical Fill Direction"] = "垂直填充方向"
+L["Vertical Spacing"] = "垂直間隔"
+L["Vertical"] = "垂直"
+L["Visibility State"] = "顯示狀態"
+L["Visibility"] = "可見性"
+L["Watch Frame"] = true
+L["What point to anchor to the frame you set to attach to."] = "增益光環框架於其依附框架的依附位置."
+L["What to attach the buff anchor frame to."] = "Buff 定位附加到的框架."
+L["What to attach the debuff anchor frame to."] = "Debuff 定位附加到的框架."
+L["When enabled active buff icons will light up instead of becoming darker, while inactive buff icons will become darker instead of being lit up."] = "當啟用時啟動的增益會以變亮取代變暗, 非啟動的增益會變暗取代變亮"
+L["When enabled it will only show spells that were added to the filter using a spell ID and not a name."] = "如果開啟將會忽略法術名只顯示用法術ID添加到過濾器的法術."
+L["When in a raid group display if anyone in your raid is targeting the current tooltip unit."] = "顯示團隊中目標與你目前浮動提示目標相同的隊友."
+L["When inside a battleground display personal scoreboard information on the main datatext bars."] = "處於戰場時, 在主資訊文字條顯示你的戰場得分訊息."
+L["When opening the Chat Editbox to type a message having this option set means it will retain the last channel you spoke in. If this option is turned off opening the Chat Editbox should always default to the SAY channel."] = "打開此選項將會保存你的輸入框為上一次輸入的頻道, 關閉此選項輸入框將始終保持在說的頻道."
+L["When true, the header includes the player when not in a raid."] = "若啟用, 隊伍中將顯示玩家."
+L["When you go AFK display the AFK screen."] = "當你離開時顯示暫離界面"
+L["Whitelist"] = "白名單"
+L["Width Multiplier"] = "寬度倍數"
+L["Width"] = "寬"
+L["Will attempt to sell another item in set interval after previous one was sold."] = "將會嘗試使用設定的時間間格後販賣下一個物品"
+L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."] = "如果沒有debuff則把buff顯示在debuff位置"
+L["Word Wrap"] = "自動換行"
+L["World Map Coordinates"] = "世界地圖坐標"
+L["World State Frame"] = true
+L["Wrap After"] = "每行光環數"
+L["X-Offset"] = "X軸偏移"
+L["Y-Offset"] = "Y軸偏移"
+L["You do not need to use 'Is Casting Anything' or 'Is Channeling Anything' for these spells to trigger."] = true
+L["You may not remove a spell from a default filter that is not customly added. Setting spell to false instead."] = "你不能移除一個內建技能, 僅能停用此技能."
+L["You must be targeting a player."] = "你必須以一名玩家為目標."
+L["You need to hold this modifier down in order to blacklist an aura by right-clicking the icon. Set to None to disable the blacklist functionality."] = "按住設置按鍵+右鍵單擊會把該玩家加入黑名單, 設為無以關閉該功能"
+L["Your Auras First"] = "自身光環優先"
+L["xOffset"] = "X軸偏移"
+L["yOffset"] = "Y軸偏移"
+
+L["ACTIONBARS_DESC"] = "修改動作條設定."
+L["AURAS_DESC"] = "小地圖旁的光環圖示設定."
+L["BAGS_DESC"] = "調整 ElvUI 背包設定."
+L["CHAT_DESC"] = "對話框架設定."
+L["COOLDOWN_DESC"] = "調整冷卻設定."
+L["DATABAR_DESC"] = "設置各種數據條"
+L["DATATEXT_DESC"] = "螢幕資訊文字顯示設定."
+L["ELVUI_DESC"] = "ElvUI 為一套功能完整, 可用來替換 WoW 原始介面的 UI 套件."
+L["NAMEPLATE_DESC"] = "修改血條設定."
+L["PANEL_DESC"] = "調整左右對話框的尺寸, 此設定將會影響對話與背包框架的尺寸."
+L["SKINS_DESC"] = "調整外觀設定."
+L["TOGGLESKIN_DESC"] = "啟用/停用此外觀."
+L["TOOLTIP_DESC"] = "浮動提示資訊設定選項."
+L["UNITFRAME_DESC"] = "修改單位框架設定."
+L["SEARCH_SYNTAX_DESC"] = [=[因為新增加的 LibItemSearch, 你現在可以使用更進階的物品搜尋. 下面是一份搜尋語法的文件. 想要看更完整的解釋請到: https://github.com/Jaliborc/LibItemSearch-1.2/wiki/Search-Syntax.
+
+條件搜尋:
+ • q:[品質] 或 quality:[品質]. 舉例, 輸入 q:史詩 會搜尋所有史詩物品.
+ • l:[裝等], lvl:[裝等] 或 level:[裝等]. 舉例, 輸入 l:30 會搜尋所有裝等30的物品.
+ • t:[類型], type:[類型] 或 slot:[類型]. 舉例, 輸入 t:武器 會搜尋所有武器.
+ • n:[名稱] 或 name:[名稱]. 舉例, 輸入 n:muffins 會搜尋所有物品名稱中含有 "muffins".
+ • s:[套裝] 或 set:[套裝]. 舉例, 輸入 s:火 會在你定義的套裝名稱起始為 火 的套裝中搜尋所有裝備.
+ • r:[等級], reg:[等級], rl:[等級], regl:[等級] or reqlvl:[等級]. 舉例, 輸入 reqlvl:30 將會搜尋全部裝等需求等級為 30 的物品.
+ • tt:[關鍵字], tip:[關鍵字] 或 tooltip:[關鍵字]. 舉例, tt:綁定 會搜尋所有物品提示中含有綁定兩字的物品 如 帳號綁定, 裝備綁定 或 拾取綁定.
+
+
+搜尋運算子:
+ • ! : 反向搜尋. 舉例, !q:史詩 會搜尋所有不是史詩的物品
+ • | : 聯集搜尋. 輸入 q:史詩 | t:武器 會搜尋所有史詩物品 或是 武器.
+ • & : 交集搜尋. 舉例, q:史詩 & t:武器 會搜尋所有既是史詩 也是 武器的物品
+ • >, <, <=, => : 在數值搜尋時進行比較. 舉例, 輸入 lvl: >30 會搜尋所有裝等大於30的物品.
+
+
+以下的關鍵字也可以被使用:
+ • soulbound, bound, bop : 拾取綁定.
+ • bou : 使用後綁定.
+ • boe : 裝備後綁定.
+ • boa : 帳號綁定.
+ • quest : 任務綁定.]=]
+L["TEXT_FORMAT_DESC"] = [=[請填入代碼以變更文字格式。
+
+範例:
+[namecolor][name] [difficultycolor][smartlevel] [shortclassification]
+[healthcolor][health:current-max]
+[powercolor][power:current]
+
+生命/能量值格式:
+"current" - 目前數值
+"percent" - 百分比
+"current-max" - 目前數值 - 最大值, 當兩者相同時, 僅會顯示最大值
+"current-percent" - 目前數值 - 百分比
+"current-max-percent" - 目前數值 - 最大值 - 百分比, 當目前數值等同於最大值時, 僅會顯示最大值
+"deficit" - 顯示損失數值, 若未損失生命/能量值, 將不予顯示
+
+名稱格式:
+"name:veryshort" - Name restricted to 5 characters
+"name:short" - 名稱上限為 10 個字元
+"name:medium" - 名稱上限為 15 個字元
+"name:long" - 名稱上限為 20 個字元
+"name:short:translit" - Name restricted to 10 characters with transliteration
+
+若要停用此功能, 此欄位請留空。如需更多資訊, 請至 https://www.tukui.org/forum/viewtopic.php?t=6]=]
+L["NAMEPLATE_FRAMELEVEL_DESC"] = [=[If you set this to 1 then all plates triggered by this style filter will be above any of the non-triggered plates.
+
+If you set this to 2 in another style filter then all plates triggered by that filter will be above plates with frame level set to 1 and all non-triggered plates, and so on.
+
+NOTE: This setting will NOT fix the issue with clicking or mousing over nameplates that are overlapped. That issue is due to us not being able to manipulate the frame level of the clickable area for nameplates.]=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to page differently.
+ Example: '[combat] 2;']=] ] = [=[此功能與巨集概念類似, 可根據不同情況切換至不同的快捷列設定.
+例如:'[combat] 2;']=]
+
+L[ [=[This works like a macro, you can run different situations to get the actionbar to show/hide differently.
+ Example: '[combat] show;hide']=] ] = [=[此功能與巨集概念類似, 可根據不同情境, 切換顯示/隱藏快捷列.
+例如:'[combat] show;hide']=]
+
+L[ [=[Specify a filename located inside the World of Warcraft directory. Textures folder that you wish to have set as a panel background.
+
+Please Note:
+-The image size recommended is 256x128
+-You must do a complete game restart after adding a file to the folder.
+-The file type must be tga format.
+
+Example: Interface\AddOns\ElvUI\Media\Textures\Copy
+
+Or for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here.]=] ] = [=[指定一個在魔獸世界資料夾之中的文件名. 將欲設置為面板背景的材質置於材質資料夾中.
+
+請注意:
+- 影像尺寸建議為 256 x 128
+- 在此資料夾新增檔案後, 請務必重新啟動遊戲.
+- 檔案必須為 tga 格式.
+
+範例:Interface\AddOns\ElvUI\Media\Textures\Copy
+
+對多數玩家來說, 較簡易的方式是將 tga 檔放入魔獸世界資料夾中, 然後在此處輸入檔案名稱.]=]
+
+-- Global Strings
+L["ACHIEVEMENTS"] = "成就"
+L["ALT_KEY_TEXT"] = "ALT"
+L["ARENA"] = "競技場"
+L["AUCTIONS"] = "拍賣"
+L["BAGSLOT"] = "背包"
+L["BARBERSHOP"] = "美容沙龍"
+L["BATTLEGROUND"] = "戰場"
+L["BATTLEFIELDS"] = "戰場"
+L["BLOCK"] = "格擋"
+L["BOSS"] = "首領"
+L["BUFFOPTIONS_LABEL"] = "增益與減益效果"
+L["CLASS"] = "職業"
+L["CHANNEL"] = "頻道"
+L["COLOR"] = "顏色"
+L["COLORS"] = "色彩"
+L["COMBAT"] = "戰鬥"
+L["COMBAT_TEXT_RUNE_BLOOD"] = "血魄符文"
+L["COMBAT_TEXT_RUNE_DEATH"] = "死亡符文"
+L["COMBAT_TEXT_RUNE_FROST"] = "冰霜符文"
+L["COMBAT_TEXT_RUNE_UNHOLY"] = "穢邪符文"
+L["COMBO_POINTS"] = "連擊點數"
+L["CTRL_KEY"] = "CTRL"
+L["CUSTOM"] = "自訂"
+L["DAMAGER"] = "傷害輸出"
+L["DEFAULT"] = "預設值"
+L["DELETE"] = "刪除"
+L["DISABLE"] = "關閉"
+L["DRESSUP_FRAME"] = "試衣間"
+L["DUNGEON_DIFFICULTY"] = "地城難度"
+L["DUNGEONS"] = "地城"
+L["EMOTE"] = "表情指令"
+L["ENEMY"] = "敵方"
+L["ENERGY"] = "能量"
+L["FACTION_STANDING_LABEL1"] = "仇恨"
+L["FACTION_STANDING_LABEL2"] = "敵對"
+L["FACTION_STANDING_LABEL3"] = "不友好"
+L["FACTION_STANDING_LABEL4"] = "中立"
+L["FACTION_STANDING_LABEL5"] = "友好"
+L["FACTION_STANDING_LABEL6"] = "尊敬"
+L["FACTION_STANDING_LABEL7"] = "崇敬"
+L["FACTION_STANDING_LABEL8"] = "崇拜"
+L["FILTERS"] = "過濾設定"
+L["FLIGHT_MAP"] = "飛行地圖"
+L["FOCUS"] = "集中值"
+L["FONT_SIZE"] = "字體大小"
+L["FRIEND"] = "好友"
+L["FRIENDS"] = "好友"
+L["GROUP"] = "小隊"
+L["GUILD"] = "公會"
+L["GUILD_BANK"] = "公會銀行"
+L["HAPPINESS"] = "快樂值"
+L["HEALER"] = "治療者"
+L["HEALTH"] = "生命力"
+L["HIDE"] = "隱藏"
+L["INSCRIPTION"] = "銘文學"
+L["INSPECT"] = "觀察"
+L["INTERFACE_OPTIONS"] = "介面選項"
+L["INTERRUPTED"] = "被打斷"
+L["ITEM_BIND_QUEST"] = "任務物品"
+L["ITEMS"] = "物品"
+L["KEY_BINDINGS"] = "按鍵設定"
+L["LANGUAGE"] = "語言"
+L["LEAVE_VEHICLE"] = "離開載具"
+L["LEVEL"] = "等級"
+L["LOCK_ACTIONBAR_TEXT"] = "鎖定快捷列"
+L["LOOT"] = "拾取"
+L["MACROS"] = "巨集設定"
+L["MAIL_LABEL"] = "郵件"
+L["MANA"] = "法力"
+L["MAP_FADE_TEXT"] = "移動時淡化地圖"
+L["MERCHANT"] = "商人"
+L["MINIMAP_LABEL"] = "小地圖"
+L["MISCELLANEOUS"] = "雜項"
+L["NAME"] = "名稱"
+L["NONE"] = "無"
+L["OFFICER"] = "幹部"
+L["OPACITY"] = "透明度"
+L["OPTION_TOOLTIP_ACTION_BUTTON_USE_KEY_DOWN"] = "快捷鍵按鍵設定會在按下按鍵時生效, 而不是在鬆開按鍵的時候."
+L["OPTION_TOOLTIP_TIMESTAMPS"] = "選擇在對話訊息中時間標記的格式."
+L["PARTY"] = "隊伍"
+L["PET"] = "寵物"
+L["PLAYER"] = "玩家"
+L["PLAYER_DIFFICULTY1"] = "普通模式"
+L["PLAYER_DIFFICULTY2"] = "英雄模式"
+L["RAGE"] = "怒氣"
+L["RAID"] = "團隊"
+L["RAID_TARGET_1"] = "星星"
+L["RAID_TARGET_2"] = "圈圈"
+L["RAID_TARGET_3"] = "鑽石"
+L["RAID_TARGET_4"] = "三角"
+L["RAID_TARGET_5"] = "月亮"
+L["RAID_TARGET_6"] = "方形"
+L["RAID_TARGET_7"] = "十字"
+L["RAID_TARGET_8"] = "頭顱"
+L["REPUTATION"] = "聲望"
+L["ROLE"] = "角色"
+L["RUNIC_POWER"] = "符能"
+L["SAY"] = "說"
+L["SHIFT_KEY"] = "SHIFT"
+L["SHORT"] = "矮"
+L["SHOW"] = "顯示"
+L["SPEED"] = "速度"
+L["SPELLBOOK"] = "法術書"
+L["TALENTS"] = "天賦"
+L["TANK"] = "坦克"
+L["TARGET"] = "選取目標"
+L["TIMEMANAGER_TITLE"] = "時鐘"
+L["TIMESTAMPS_LABEL"] = "對話時間標記"
+L["TRADE"] = "交易"
+L["TRADESKILLS"] = "交易技能"
+L["TUTORIAL_TITLE47"] = "圖騰列"
+L["UI_SCALE"] = "使用者介面縮放"
+L["UNIT_NAMEPLATES_TYPES"] = "名條排列類型"
+L["UNIT_NAMEPLATES_TYPE_1"] = "重疊名條"
+L["UNIT_NAMEPLATES_TYPE_2"] = "堆疊名條"
+L["WHISPER"] = "悄悄話"
+L["WORLD_MAP"] = "地圖"
+L["XPBAR_LABEL"] = "經驗條"
+L["YELL"] = "大喊"
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Maps.lua b/ElvUI_OptionsUI/Maps.lua
new file mode 100644
index 0000000..dee609f
--- /dev/null
+++ b/ElvUI_OptionsUI/Maps.lua
@@ -0,0 +1,581 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+local WM = E:GetModule("WorldMap")
+local MM = E:GetModule("Minimap")
+local AB = E:GetModule("ActionBars")
+
+E.Options.args.maps = {
+ type = "group",
+ name = L["Maps"],
+ childGroups = "tab",
+ args = {
+ worldMap = {
+ order = 1,
+ type = "group",
+ name = L["WORLD_MAP"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["WORLD_MAP"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.private.worldmap[info[#info]] end,
+ set = function(info, value) E.private.worldmap[info[#info]] = value; E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ generalGroup = {
+ order = 3,
+ type = "group",
+ name = L["General"],
+ guiInline = true,
+ args = {
+ smallerWorldMap = {
+ order = 1,
+ type = "toggle",
+ name = L["Smaller World Map"],
+ desc = L["Make the world map smaller."],
+ get = function(info) return E.global.general.smallerWorldMap end,
+ set = function(info, value) E.global.general.smallerWorldMap = value E:StaticPopup_Show("GLOBAL_RL") end,
+ disabled = function() return not WM.Initialized end
+ },
+ fadeMapWhenMoving = {
+ order = 2,
+ type = "toggle",
+ name = L["MAP_FADE_TEXT"],
+ get = function(info) return E.global.general.fadeMapWhenMoving end,
+ set = function(info, value) E.global.general.fadeMapWhenMoving = value WM:UpdateMapAlpha() end
+ },
+ mapAlphaWhenMoving = {
+ order = 3,
+ type = "range",
+ name = L["Map Opacity When Moving"],
+ isPercent = true,
+ min = 0, max = 1, step = 0.01,
+ get = function(info) return E.global.general.mapAlphaWhenMoving end,
+ set = function(info, value) E.global.general.mapAlphaWhenMoving = value WM:UpdateMapAlpha() end,
+ disabled = function() return not E.global.general.fadeMapWhenMoving end
+ }
+ }
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = "\n"
+ },
+ coordinatesGroup = {
+ order = 5,
+ type = "group",
+ name = L["World Map Coordinates"],
+ guiInline = true,
+ disabled = function() return not WM.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Puts coordinates on the world map."],
+ get = function(info) return E.global.general.WorldMapCoordinates.enable end,
+ set = function(info, value) E.global.general.WorldMapCoordinates.enable = value E:StaticPopup_Show("GLOBAL_RL") end
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = " "
+ },
+ position = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ get = function(info) return E.global.general.WorldMapCoordinates.position end,
+ set = function(info, value) E.global.general.WorldMapCoordinates.position = value WM:PositionCoords() end,
+ disabled = function() return not E.global.general.WorldMapCoordinates.enable end,
+ values = {
+ ["TOP"] = "TOP",
+ ["TOPLEFT"] = "TOPLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT",
+ ["BOTTOM"] = "BOTTOM",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT"
+ }
+ },
+ xOffset = {
+ order = 4,
+ type = "range",
+ name = L["X-Offset"],
+ get = function(info) return E.global.general.WorldMapCoordinates.xOffset end,
+ set = function(info, value) E.global.general.WorldMapCoordinates.xOffset = value WM:PositionCoords() end,
+ disabled = function() return not E.global.general.WorldMapCoordinates.enable end,
+ min = -200, max = 200, step = 1
+ },
+ yOffset = {
+ order = 5,
+ type = "range",
+ name = L["Y-Offset"],
+ get = function(info) return E.global.general.WorldMapCoordinates.yOffset end,
+ set = function(info, value) E.global.general.WorldMapCoordinates.yOffset = value WM:PositionCoords() end,
+ disabled = function() return not E.global.general.WorldMapCoordinates.enable end,
+ min = -200, max = 200, step = 1
+ }
+ }
+ }
+ }
+ },
+ minimap = {
+ order = 2,
+ type = "group",
+ name = L["MINIMAP_LABEL"],
+ get = function(info) return E.db.general.minimap[info[#info]] end,
+ childGroups = "tab",
+ args = {
+ minimapHeader = {
+ order = 1,
+ type = "header",
+ name = L["MINIMAP_LABEL"]
+ },
+ generalGroup = {
+ order = 2,
+ type = "group",
+ name = L["General"],
+ guiInline = true,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Enable/Disable the minimap. |cffFF0000Warning: This will prevent you from seeing the consolidated buffs bar, and prevent you from seeing the minimap datatexts.|r"],
+ get = function(info) return E.private.general.minimap[info[#info]] end,
+ set = function(info, value) E.private.general.minimap[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ size = {
+ order = 2,
+ type = "range",
+ name = L["Size"],
+ desc = L["Adjust the size of the minimap."],
+ min = 120, max = 250, step = 1,
+ get = function(info) return E.db.general.minimap[info[#info]] end,
+ set = function(info, value) E.db.general.minimap[info[#info]] = value MM:UpdateSettings() end,
+ disabled = function() return not E.private.general.minimap.enable end
+ }
+ }
+ },
+ locationTextGroup = {
+ order = 3,
+ type = "group",
+ name = L["Location Text"],
+ args = {
+ locationHeader = {
+ order = 1,
+ type = "header",
+ name = L["Location Text"]
+ },
+ locationText = {
+ order = 2,
+ type = "select",
+ name = L["Location Text"],
+ desc = L["Change settings for the display of the location text that is on the minimap."],
+ get = function(info) return E.db.general.minimap.locationText end,
+ set = function(info, value) E.db.general.minimap.locationText = value MM:UpdateSettings() MM:Update_ZoneText() end,
+ values = {
+ ["MOUSEOVER"] = L["Minimap Mouseover"],
+ ["SHOW"] = L["Always Display"],
+ ["HIDE"] = L["HIDE"]
+ },
+ disabled = function() return not E.private.general.minimap.enable end
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = "\n"
+ },
+ locationFont = {
+ order = 4,
+ type = "select",
+ dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font,
+ set = function(info, value) E.db.general.minimap.locationFont = value MM:Update_ZoneText() end,
+ disabled = function() return not E.private.general.minimap.enable end
+ },
+ locationFontSize = {
+ order = 5,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 6, max = 36, step = 1,
+ set = function(info, value) E.db.general.minimap.locationFontSize = value MM:Update_ZoneText() end,
+ disabled = function() return not E.private.general.minimap.enable end
+ },
+ locationFontOutline = {
+ order = 6,
+ type = "select",
+ name = L["Font Outline"],
+ set = function(info, value) E.db.general.minimap.locationFontOutline = value MM:Update_ZoneText() end,
+ disabled = function() return not E.private.general.minimap.enable end,
+ values = C.Values.FontFlags
+ }
+ }
+ },
+ zoomResetGroup = {
+ order = 4,
+ type = "group",
+ name = L["Reset Zoom"],
+ args = {
+ zoomResetHeader = {
+ order = 1,
+ type = "header",
+ name = L["Reset Zoom"]
+ },
+ enableZoomReset = {
+ order = 2,
+ type = "toggle",
+ name = L["Reset Zoom"],
+ get = function(info) return E.db.general.minimap.resetZoom.enable end,
+ set = function(info, value) E.db.general.minimap.resetZoom.enable = value MM:UpdateSettings() end,
+ disabled = function() return not E.private.general.minimap.enable end
+ },
+ zoomResetTime = {
+ order = 3,
+ type = "range",
+ name = L["Seconds"],
+ min = 1, max = 15, step = 1,
+ get = function(info) return E.db.general.minimap.resetZoom.time end,
+ set = function(info, value) E.db.general.minimap.resetZoom.time = value MM:UpdateSettings() end,
+ disabled = function() return (not E.db.general.minimap.resetZoom.enable or not E.private.general.minimap.enable) end
+ }
+ }
+ },
+ icons = {
+ order = 5,
+ type = "group",
+ name = L["Buttons"],
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Buttons"]
+ },
+ calendar = {
+ order = 1,
+ type = "group",
+ name = L["Calendar"],
+ get = function(info) return E.db.general.minimap.icons.calendar[info[#info]] end,
+ set = function(info, value) E.db.general.minimap.icons.calendar[info[#info]] = value MM:UpdateSettings() end,
+ disabled = function() return not E.private.general.minimap.enable end,
+ args = {
+ calendarHeader = {
+ order = 1,
+ type = "header",
+ name = L["Calendar"]
+ },
+ hideCalendar = {
+ order = 2,
+ type = "toggle",
+ name = L["HIDE"],
+ get = function(info) return E.private.general.minimap.hideCalendar end,
+ set = function(info, value) E.private.general.minimap.hideCalendar = value MM:UpdateSettings() end,
+ width = "full"
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = "",
+ width = "full"
+ },
+ position = {
+ order = 4,
+ type = "select",
+ name = L["Position"],
+ disabled = function() return E.private.general.minimap.hideCalendar end,
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"],
+ ["TOP"] = L["Top"],
+ ["BOTTOM"] = L["Bottom"],
+ ["TOPLEFT"] = L["Top Left"],
+ ["TOPRIGHT"] = L["Top Right"],
+ ["BOTTOMLEFT"] = L["Bottom Left"],
+ ["BOTTOMRIGHT"] = L["Bottom Right"]
+ }
+ },
+ scale = {
+ order = 5,
+ type = "range",
+ name = L["Scale"],
+ min = 0.5, max = 2, step = 0.05,
+ disabled = function() return E.private.general.minimap.hideCalendar end
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -50, max = 50, step = 1,
+ disabled = function() return E.private.general.minimap.hideCalendar end
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -50, max = 50, step = 1,
+ disabled = function() return E.private.general.minimap.hideCalendar end
+ }
+ }
+ },
+ mail = {
+ order = 3,
+ type = "group",
+ name = L["MAIL_LABEL"],
+ get = function(info) return E.db.general.minimap.icons.mail[info[#info]] end,
+ set = function(info, value) E.db.general.minimap.icons.mail[info[#info]] = value MM:UpdateSettings() end,
+ disabled = function() return not E.private.general.minimap.enable end,
+ args = {
+ mailHeader = {
+ order = 1,
+ type = "header",
+ name = L["MAIL_LABEL"]
+ },
+ position = {
+ order = 2,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"],
+ ["TOP"] = L["Top"],
+ ["BOTTOM"] = L["Bottom"],
+ ["TOPLEFT"] = L["Top Left"],
+ ["TOPRIGHT"] = L["Top Right"],
+ ["BOTTOMLEFT"] = L["Bottom Left"],
+ ["BOTTOMRIGHT"] = L["Bottom Right"]
+ }
+ },
+ scale = {
+ order = 3,
+ type = "range",
+ name = L["Scale"],
+ min = 0.5, max = 2, step = 0.05
+ },
+ xOffset = {
+ order = 4,
+ type = "range",
+ name = L["X-Offset"],
+ min = -50, max = 50, step = 1
+ },
+ yOffset = {
+ order = 5,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -50, max = 50, step = 1
+ }
+ }
+ },
+ lfgEye = {
+ order = 4,
+ type = "group",
+ name = L["LFG Queue"],
+ get = function(info) return E.db.general.minimap.icons.lfgEye[info[#info]] end,
+ set = function(info, value) E.db.general.minimap.icons.lfgEye[info[#info]] = value MM:UpdateSettings() end,
+ disabled = function() return not E.private.general.minimap.enable end,
+ args = {
+ lfgEyeHeader = {
+ order = 1,
+ type = "header",
+ name = L["LFG Queue"]
+ },
+ position = {
+ order = 2,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"],
+ ["TOP"] = L["Top"],
+ ["BOTTOM"] = L["Bottom"],
+ ["TOPLEFT"] = L["Top Left"],
+ ["TOPRIGHT"] = L["Top Right"],
+ ["BOTTOMLEFT"] = L["Bottom Left"],
+ ["BOTTOMRIGHT"] = L["Bottom Right"]
+ }
+ },
+ scale = {
+ order = 3,
+ type = "range",
+ name = L["Scale"],
+ min = 0.5, max = 2, step = 0.05
+ },
+ xOffset = {
+ order = 4,
+ type = "range",
+ name = L["X-Offset"],
+ min = -50, max = 50, step = 1
+ },
+ yOffset = {
+ order = 5,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -50, max = 50, step = 1
+ }
+ }
+ },
+ battlefield = {
+ order = 5,
+ type = "group",
+ name = L["PvP Queue"],
+ get = function(info) return E.db.general.minimap.icons.battlefield[info[#info]] end,
+ set = function(info, value) E.db.general.minimap.icons.battlefield[info[#info]] = value MM:UpdateSettings() end,
+ disabled = function() return not E.private.general.minimap.enable end,
+ args = {
+ battlefieldHeader = {
+ order = 1,
+ type = "header",
+ name = L["PvP Queue"]
+ },
+ position = {
+ order = 2,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"],
+ ["TOP"] = L["Top"],
+ ["BOTTOM"] = L["Bottom"],
+ ["TOPLEFT"] = L["Top Left"],
+ ["TOPRIGHT"] = L["Top Right"],
+ ["BOTTOMLEFT"] = L["Bottom Left"],
+ ["BOTTOMRIGHT"] = L["Bottom Right"]
+ }
+ },
+ scale = {
+ order = 3,
+ type = "range",
+ name = L["Scale"],
+ min = 0.5, max = 2, step = 0.05
+ },
+ xOffset = {
+ order = 4,
+ type = "range",
+ name = L["X-Offset"],
+ min = -50, max = 50, step = 1
+ },
+ yOffset = {
+ order = 5,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -50, max = 50, step = 1
+ }
+ }
+ },
+ difficulty = {
+ order = 6,
+ type = "group",
+ name = L["Instance Difficulty"],
+ get = function(info) return E.db.general.minimap.icons.difficulty[info[#info]] end,
+ set = function(info, value) E.db.general.minimap.icons.difficulty[info[#info]] = value MM:UpdateSettings() end,
+ disabled = function() return not E.private.general.minimap.enable end,
+ args = {
+ difficultyHeader = {
+ order = 1,
+ type = "header",
+ name = L["Instance Difficulty"]
+ },
+ position = {
+ order = 2,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"],
+ ["TOP"] = L["Top"],
+ ["BOTTOM"] = L["Bottom"],
+ ["TOPLEFT"] = L["Top Left"],
+ ["TOPRIGHT"] = L["Top Right"],
+ ["BOTTOMLEFT"] = L["Bottom Left"],
+ ["BOTTOMRIGHT"] = L["Bottom Right"]
+ }
+ },
+ scale = {
+ order = 3,
+ type = "range",
+ name = L["Scale"],
+ min = 0.5, max = 2, step = 0.05
+ },
+ xOffset = {
+ order = 4,
+ type = "range",
+ name = L["X-Offset"],
+ min = -50, max = 50, step = 1
+ },
+ yOffset = {
+ order = 5,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -50, max = 50, step = 1
+ }
+ }
+ },
+ vehicleLeave = {
+ order = 7,
+ type = "group",
+ name = L["LEAVE_VEHICLE"],
+ get = function(info) return E.db.general.minimap.icons.vehicleLeave[info[#info]] end,
+ set = function(info, value) E.db.general.minimap.icons.vehicleLeave[info[#info]] = value AB:UpdateVehicleLeave() end,
+ disabled = function() return not E.private.general.minimap.enable end,
+ args = {
+ vehicleLeaveHeader = {
+ order = 1,
+ type = "header",
+ name = L["LEAVE_VEHICLE"]
+ },
+ hide = {
+ order = 2,
+ type = "toggle",
+ name = L["HIDE"]
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = "",
+ width = "full"
+ },
+ position = {
+ order = 4,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"],
+ ["TOP"] = L["Top"],
+ ["BOTTOM"] = L["Bottom"],
+ ["TOPLEFT"] = L["Top Left"],
+ ["TOPRIGHT"] = L["Top Right"],
+ ["BOTTOMLEFT"] = L["Bottom Left"],
+ ["BOTTOMRIGHT"] = L["Bottom Right"]
+ }
+ },
+ scale = {
+ order = 5,
+ type = "range",
+ name = L["Scale"],
+ min = 0.5, max = 2, step = 0.05,
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -50, max = 50, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -50, max = 50, step = 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/ModuleControl.lua b/ElvUI_OptionsUI/ModuleControl.lua
new file mode 100644
index 0000000..ee5dc4a
--- /dev/null
+++ b/ElvUI_OptionsUI/ModuleControl.lua
@@ -0,0 +1,602 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local _, L = unpack(select(2, ...))
+local UF = E:GetModule("UnitFrames")
+local MC = E:GetModule("ModuleCopy")
+
+--Actionbars
+local function CreateActionbarsConfig()
+ local config = MC:CreateModuleConfigGroup(L["ActionBars"], "actionbar")
+ for i = 1, 6 do
+ config.args["bar"..i] = {
+ order = i + 1,
+ type = "toggle",
+ name = L["Bar "]..i,
+ get = function(info) return E.global.profileCopy.actionbar[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.actionbar[info[#info]] = value end
+ }
+ end
+ config.args.barPet = {
+ order = 8,
+ type = "toggle",
+ name = L["Pet Bar"],
+ get = function(info) return E.global.profileCopy.actionbar[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.actionbar[info[#info]] = value end
+ }
+ config.args.stanceBar = {
+ order = 9,
+ type = "toggle",
+ name = L["Stance Bar"],
+ get = function(info) return E.global.profileCopy.actionbar[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.actionbar[info[#info]] = value end
+ }
+ config.args.microbar = {
+ order = 10,
+ type = "toggle",
+ name = L["Micro Bar"],
+ get = function(info) return E.global.profileCopy.actionbar[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.actionbar[info[#info]] = value end
+ }
+ config.args.cooldown = {
+ order = 11,
+ type = "toggle",
+ name = L["Cooldown Text"],
+ get = function(info) return E.global.profileCopy.actionbar[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.actionbar[info[#info]] = value end
+ }
+
+ return config
+end
+
+--Auras
+local function CreateAurasConfig()
+ local config = MC:CreateModuleConfigGroup(L["Auras"], "auras")
+ config.args.buffs = {
+ order = 2,
+ type = "toggle",
+ name = L["Buffs"],
+ get = function(info) return E.global.profileCopy.auras[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.auras[info[#info]] = value end
+ }
+ config.args.debuffs = {
+ order = 3,
+ type = "toggle",
+ name = L["Debuffs"],
+ get = function(info) return E.global.profileCopy.auras[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.auras[info[#info]] = value end
+ }
+ config.args.cooldown = {
+ order = 4,
+ type = "toggle",
+ name = L["Cooldown Text"],
+ get = function(info) return E.global.profileCopy.auras[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.auras[info[#info]] = value end
+ }
+
+ return config
+end
+
+--Bags
+local function CreateBagsConfig()
+ local config = MC:CreateModuleConfigGroup(L["Bags"], "bags")
+ config.args.bagBar = {
+ order = 2,
+ type = "toggle",
+ name = L["Bag-Bar"],
+ get = function(info) return E.global.profileCopy.bags[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.bags[info[#info]] = value end
+ }
+ config.args.cooldown = {
+ order = 3,
+ type = "toggle",
+ name = L["Cooldown Text"],
+ get = function(info) return E.global.profileCopy.bags[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.bags[info[#info]] = value end
+ }
+ config.args.split = {
+ order = 4,
+ type = "toggle",
+ name = L["Split"],
+ get = function(info) return E.global.profileCopy.bags[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.bags[info[#info]] = value end
+ }
+ config.args.vendorGrays = {
+ order = 5,
+ type = "toggle",
+ name = L["Vendor Grays"],
+ get = function(info) return E.global.profileCopy.bags[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.bags[info[#info]] = value end
+ }
+
+ return config
+end
+
+--Chat
+local function CreateChatConfig()
+ local config = MC:CreateModuleConfigGroup(L["Chat"], "chat")
+
+ return config
+end
+
+--Cooldowns
+local function CreateCooldownConfig()
+ local config = MC:CreateModuleConfigGroup(L["Cooldown Text"], "cooldown")
+ config.args.fonts = {
+ order = 2,
+ type = "toggle",
+ name = L["Fonts"],
+ get = function(info) return E.global.profileCopy.cooldown[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.cooldown[info[#info]] = value end
+ }
+
+ return config
+end
+
+--DataBars
+local function CreateDatatbarsConfig()
+ local config = MC:CreateModuleConfigGroup(L["DataBars"], "databars")
+
+ config.args.experience = {
+ order = 2,
+ type = "toggle",
+ name = L["XPBAR_LABEL"],
+ get = function(info) return E.global.profileCopy.databars[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.databars[info[#info]] = value end
+ }
+ config.args.reputation = {
+ order = 3,
+ type = "toggle",
+ name = L["REPUTATION"],
+ get = function(info) return E.global.profileCopy.databars[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.databars[info[#info]] = value end
+ }
+
+ return config
+end
+
+--DataTexts
+local function CreateDatatextsConfig()
+ local config = MC:CreateModuleConfigGroup(L["DataTexts"], "datatexts")
+ config.args.panels = {
+ order = 2,
+ type = "toggle",
+ name = L["Panels"],
+ get = function(info) return E.global.profileCopy.datatexts[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.datatexts[info[#info]] = value end
+ }
+
+ return config
+end
+
+--General
+local function CreateGeneralConfig()
+ local config = MC:CreateModuleConfigGroup(L["General"], "general")
+ config.args.minimap = {
+ order = 2,
+ type = "toggle",
+ name = L["MINIMAP_LABEL"],
+ get = function(info) return E.global.profileCopy.general[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.general[info[#info]] = value end
+ }
+ config.args.threat = {
+ order = 3,
+ type = "toggle",
+ name = L["Threat"],
+ get = function(info) return E.global.profileCopy.general[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.general[info[#info]] = value end
+ }
+ config.args.totems = {
+ order = 4,
+ type = "toggle",
+ name = L["Class Totems"],
+ get = function(info) return E.global.profileCopy.general[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.general[info[#info]] = value end
+ }
+
+ return config
+end
+
+--NamePlates
+local function CreateNamePlatesConfig()
+ local config = MC:CreateModuleConfigGroup(L["NamePlates"], "nameplates")
+ config.args.cooldown = {
+ order = 2,
+ type = "toggle",
+ name = L["Cooldown Text"],
+ get = function(info) return E.global.profileCopy.nameplates[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.nameplates[info[#info]] = value end
+ }
+ config.args.reactions = {
+ order = 3,
+ type = "toggle",
+ name = L["Reaction Colors"],
+ get = function(info) return E.global.profileCopy.nameplates[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.nameplates[info[#info]] = value end
+ }
+ config.args.threat = {
+ order = 4,
+ type = "toggle",
+ name = L["Threat"],
+ get = function(info) return E.global.profileCopy.nameplates[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.nameplates[info[#info]] = value end
+ }
+ config.args.units = {
+ order = 5,
+ type = "group",
+ guiInline = true,
+ name = L["NamePlates"],
+ get = function(info) return E.global.profileCopy.nameplates[info[#info - 1]][info[#info]] end,
+ set = function(info, value) E.global.profileCopy.nameplates[info[#info - 1]][info[#info]] = value end,
+ args = {
+ ["FRIENDLY_PLAYER"] = {
+ order = 1,
+ type = "toggle",
+ name = L["Friendly Player Frames"]
+ },
+ ["ENEMY_PLAYER"] = {
+ order = 2,
+ type = "toggle",
+ name = L["Enemy Player Frames"]
+ },
+ ["FRIENDLY_NPC"] = {
+ order = 3,
+ type = "toggle",
+ name = L["Friendly NPC Frames"]
+ },
+ ["ENEMY_NPC"] = {
+ order = 4,
+ type = "toggle",
+ name = L["Enemy NPC Frames"]
+ }
+ }
+ }
+
+ return config
+end
+
+--Tooltip
+local function CreateTooltipConfig()
+ local config = MC:CreateModuleConfigGroup(L["Tooltip"], "tooltip")
+ config.args.visibility = {
+ order = 2,
+ type = "toggle",
+ name = L["Visibility"],
+ get = function(info) return E.global.profileCopy.tooltip[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.tooltip[info[#info]] = value end
+ }
+ config.args.healthBar = {
+ order = 3,
+ type = "toggle",
+ name = L["Health Bar"],
+ get = function(info) return E.global.profileCopy.tooltip[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.tooltip[info[#info]] = value end
+ }
+
+ return config
+end
+
+--UnitFrames
+local function CreateUnitframesConfig()
+ local config = MC:CreateModuleConfigGroup(L["UnitFrames"], "unitframe")
+ config.args.cooldown = {
+ order = 2,
+ type = "toggle",
+ name = L["Cooldown Text"],
+ get = function(info) return E.global.profileCopy.unitframe[info[#info]] end,
+ set = function(info, value) E.global.profileCopy.unitframe[info[#info]] = value end
+ }
+ config.args.colors = {
+ order = 3,
+ type = "group",
+ guiInline = true,
+ name = L["COLORS"],
+ get = function(info) return E.global.profileCopy.unitframe[info[#info - 1]][info[#info]] end,
+ set = function(info, value) E.global.profileCopy.unitframe[info[#info - 1]][info[#info]] = value end,
+ args = {
+ ["general"] = {
+ order = 1,
+ type = "toggle",
+ name = L["General"]
+ },
+ ["power"] = {
+ order = 2,
+ type = "toggle",
+ name = L["Powers"]
+ },
+ ["reaction"] = {
+ order = 3,
+ type = "toggle",
+ name = L["Reactions"]
+ },
+ ["healPrediction"] = {
+ order = 4,
+ type = "toggle",
+ name = L["Heal Prediction"]
+ },
+ ["classResources"] = {
+ order = 5,
+ type = "toggle",
+ name = L["Class Resources"]
+ },
+ ["frameGlow"] = {
+ order = 6,
+ type = "toggle",
+ name = L["Frame Glow"]
+ },
+ ["debuffHighlight"] = {
+ order = 7,
+ type = "toggle",
+ name = L["Debuff Highlighting"]
+ }
+ }
+ }
+ config.args.units = {
+ order = 4,
+ type = "group",
+ guiInline = true,
+ name = L["UnitFrames"],
+ get = function(info) return E.global.profileCopy.unitframe[info[#info - 1]][info[#info]] end,
+ set = function(info, value) E.global.profileCopy.unitframe[info[#info - 1]][info[#info]] = value end,
+ args = {
+ ["player"] = {
+ order = 1,
+ type = "toggle",
+ name = L["PLAYER"]
+ },
+ ["target"] = {
+ order = 2,
+ type = "toggle",
+ name = L["TARGET"]
+ },
+ ["targettarget"] = {
+ order = 3,
+ type = "toggle",
+ name = L["TargetTarget"]
+ },
+ ["targettargettarget"] = {
+ order = 4,
+ type = "toggle",
+ name = L["TargetTargetTarget"]
+ },
+ ["focus"] = {
+ order = 5,
+ type = "toggle",
+ name = L["FOCUS"]
+ },
+ ["focustarget"] = {
+ order = 6,
+ type = "toggle",
+ name = L["FocusTarget"]
+ },
+ ["pet"] = {
+ order = 7,
+ type = "toggle",
+ name = L["Pet"]
+ },
+ ["pettarget"] = {
+ order = 8,
+ type = "toggle",
+ name = L["PetTarget"]
+ },
+ ["party"] = {
+ order = 9,
+ type = "toggle",
+ name = L["PARTY"]
+ },
+ ["raid"] = {
+ order = 10,
+ type = "toggle",
+ name = L["RAID"]
+ },
+ ["raid40"] = {
+ order = 11,
+ type = "toggle",
+ name = L["Raid-40"]
+ },
+ ["raidpet"] = {
+ order = 12,
+ type = "toggle",
+ name = L["Raid Pet"]
+ },
+ ["tank"] = {
+ order = 13,
+ type = "toggle",
+ name = L["Tank"]
+ },
+ ["assist"] = {
+ order = 14,
+ type = "toggle",
+ name = L["Assist"]
+ }
+ }
+ }
+
+ return config
+end
+
+E.Options.args.modulecontrol= {
+ order = -2,
+ type = "group",
+ name = L["Module Control"],
+ childGroups = "tab",
+ args = {
+ modulecopy = {
+ type = "group",
+ name = L["Module Copy"],
+ order = 1,
+ childGroups = "select",
+ handler = E.Options.args.profiles.handler,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Module Copy"]
+ },
+ intro = {
+ order = 1,
+ type = "description",
+ name = L["This section will allow you to copy settings to a select module from or to a different profile."]
+ },
+ pluginInfo = {
+ order = 2,
+ type = "description",
+ name = L["If you have any plugins supporting this feature installed you can find them in the selection dropdown to the right."]
+ },
+ profile = {
+ order = 3,
+ type = "select",
+ name = L["Profile"],
+ desc = L["Select a profile to copy from/to."],
+ get = function(info) return E.global.profileCopy.selected end,
+ set = function(info, value) E.global.profileCopy.selected = value end,
+ values = E.Options.args.profiles.args.copyfrom.values,
+ disabled = E.Options.args.profiles.args.copyfrom.disabled,
+ arg = E.Options.args.profiles.args.copyfrom.arg
+ },
+ elvui = {
+ order = 10,
+ type = "group",
+ name = E.title,
+ childGroups = "tab",
+ disabled = E.Options.args.profiles.args.copyfrom.disabled,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Core |cff1784d1E|r|cffe5e3e3lvUI|r options."],
+ },
+ actionbar = CreateActionbarsConfig(),
+ auras = CreateAurasConfig(),
+ bags = CreateBagsConfig(),
+ chat = CreateChatConfig(),
+ cooldown = CreateCooldownConfig(),
+ databars = CreateDatatbarsConfig(),
+ datatexts = CreateDatatextsConfig(),
+ general = CreateGeneralConfig(),
+ nameplates = CreateNamePlatesConfig(),
+ tooltip = CreateTooltipConfig(),
+ uniframes = CreateUnitframesConfig()
+ }
+ },
+ movers = {
+ order = 20,
+ type = "group",
+ name = L["Movers"],
+ desc = L["On screen positions for different elements."],
+ childGroups = "tab",
+ disabled = E.Options.args.profiles.args.copyfrom.disabled,
+ args = MC:CreateMoversConfigGroup()
+ }
+ }
+ },
+ modulereset = {
+ type = "group",
+ name = L["Module Reset"],
+ order = 2,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Module Reset"]
+ },
+ intro = {
+ order = 1,
+ type = "description",
+ name = L["This section will help reset specfic settings back to default."]
+ },
+ space1 = {
+ order = 2,
+ type = "description",
+ name = ""
+ },
+ general = {
+ order = 3,
+ type = "execute",
+ name = L["General"],
+ confirm = true,
+ confirmText = L["Are you sure you want to reset General settings?"],
+ func = function() E:CopyTable(E.db.general, P.general) end
+ },
+ actionbar = {
+ order = 5,
+ type = "execute",
+ name = L["ActionBars"],
+ confirm = true,
+ confirmText = L["Are you sure you want to reset ActionBars settings?"],
+ func = function() E:CopyTable(E.db.actionbar, P.actionbar) end
+ },
+ bags = {
+ order = 6,
+ type = "execute",
+ name = L["Bags"],
+ confirm = true,
+ confirmText = L["Are you sure you want to reset Bags settings?"],
+ func = function() E:CopyTable(E.db.bags, P.bags) end
+ },
+ auras = {
+ order = 7,
+ type = "execute",
+ name = L["Auras"],
+ confirm = true,
+ confirmText = L["Are you sure you want to reset Auras settings?"],
+ func = function() E:CopyTable(E.db.auras, P.auras) end
+ },
+ chat = {
+ order = 8,
+ type = "execute",
+ name = L["Chat"],
+ confirm = true,
+ confirmText = L["Are you sure you want to reset Chat settings?"],
+ func = function() E:CopyTable(E.db.chat, P.chat) end
+ },
+ cooldown = {
+ order = 9,
+ type = "execute",
+ name = L["Cooldown Text"],
+ confirm = true,
+ confirmText = L["Are you sure you want to reset Cooldown settings?"],
+ func = function() E:CopyTable(E.db.cooldown, P.cooldown) end
+ },
+ databars = {
+ order = 10,
+ type = "execute",
+ name = L["DataBars"],
+ confirm = true,
+ confirmText = L["Are you sure you want to reset DataBars settings?"],
+ func = function() E:CopyTable(E.db.databars, P.databars) end
+ },
+ datatexts = {
+ order = 11,
+ type = "execute",
+ name = L["DataTexts"],
+ confirm = true,
+ confirmText = L["Are you sure you want to reset DataTexts settings?"],
+ func = function() E:CopyTable(E.db.datatexts, P.datatexts) end
+ },
+ nameplates = {
+ order = 12,
+ type = "execute",
+ name = L["NamePlates"],
+ confirm = true,
+ confirmText = L["Are you sure you want to reset NamePlates settings?"],
+ func = function() E:CopyTable(E.db.nameplates, P.nameplates) end
+ },
+ tooltip = {
+ order = 13,
+ type = "execute",
+ name = L["Tooltip"],
+ confirm = true,
+ confirmText = L["Are you sure you want to reset Tooltip settings?"],
+ func = function() E:CopyTable(E.db.tooltip, P.tooltip) end
+ },
+ uniframes = {
+ order = 14,
+ type = "execute",
+ name = L["UnitFrames"],
+ confirm = true,
+ confirmText = L["Are you sure you want to reset UnitFrames settings?"],
+ func = function() E:CopyTable(E.db.unitframe, P.unitframe) UF:Update_AllFrames() end
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Nameplates.lua b/ElvUI_OptionsUI/Nameplates.lua
new file mode 100644
index 0000000..bc302ba
--- /dev/null
+++ b/ElvUI_OptionsUI/Nameplates.lua
@@ -0,0 +1,4156 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+local NP = E:GetModule("NamePlates")
+local ACD = E.Libs.AceConfigDialog
+
+local next, ipairs, pairs, type, tonumber = next, ipairs, pairs, type, tonumber
+local tremove, tinsert, tconcat = tremove, tinsert, table.concat
+local format, match, gsub, strsplit = string.format, string.match, string.gsub, strsplit
+
+local GetSpellInfo = GetSpellInfo
+
+local positionValues = {
+ BOTTOMLEFT = "BOTTOMLEFT",
+ BOTTOMRIGHT = "BOTTOMRIGHT",
+ LEFT = "LEFT",
+ RIGHT = "RIGHT",
+ TOPLEFT = "TOPLEFT",
+ TOPRIGHT = "TOPRIGHT"
+}
+
+local raidTargetIcon = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_%s:0|t %s"
+local selectedNameplateFilter
+
+local totemsColor = {
+ ["fire"] = "|cffff8f8f",
+ ["earth"] = "|cffffb31f",
+ ["water"] = "|cff2b76ff",
+ ["air"] = "|cffb8d1ff"
+}
+
+local carryFilterFrom, carryFilterTo
+
+local function filterMatch(s,v)
+ local m1, m2, m3, m4 = "^"..v.."$", "^"..v..",", ","..v.."$", ","..v..","
+ return (match(s, m1) and m1) or (match(s, m2) and m2) or (match(s, m3) and m3) or (match(s, m4) and v..",")
+end
+
+local function filterPriority(auraType, unit, value, remove, movehere)
+ if not auraType or not value then return end
+ local filter = E.db.nameplates.units[unit] and E.db.nameplates.units[unit][auraType] and E.db.nameplates.units[unit][auraType].filters and E.db.nameplates.units[unit][auraType].filters.priority
+ if not filter then return end
+ local found = filterMatch(filter, E:EscapeString(value))
+ if found and movehere then
+ local tbl, sv, sm = {strsplit(",",filter)}
+ for i in ipairs(tbl) do
+ if tbl[i] == value then sv = i elseif tbl[i] == movehere then sm = i end
+ if sv and sm then break end
+ end
+ tremove(tbl, sm)
+ tinsert(tbl, sv, movehere)
+ E.db.nameplates.units[unit][auraType].filters.priority = tconcat(tbl,",")
+ elseif found and remove then
+ E.db.nameplates.units[unit][auraType].filters.priority = gsub(filter, found, "")
+ elseif not found and not remove then
+ E.db.nameplates.units[unit][auraType].filters.priority = (filter == "" and value) or (filter..","..value)
+ end
+end
+
+local function UpdateInstanceDifficulty()
+ if E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.party then
+ E.Options.args.nameplate.args.filters.args.triggers.args.instanceType.args.dungeonDifficulty = {
+ order = 10,
+ type = "group",
+ name = L["DUNGEON_DIFFICULTY"],
+ desc = L["Check these to only have the filter active in certain difficulties. If none are checked, it is active in all difficulties."],
+ guiInline = true,
+ get = function(info) return E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceDifficulty.dungeon[info[#info]] end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceDifficulty.dungeon[info[#info]] = value
+ UpdateInstanceDifficulty()
+ NP:ConfigureAll()
+ end,
+ args = {
+ normal = {
+ order = 1,
+ type = "toggle",
+ name = L["PLAYER_DIFFICULTY1"]
+ },
+ heroic = {
+ order = 2,
+ type = "toggle",
+ name = L["PLAYER_DIFFICULTY2"]
+ }
+ }
+ }
+ else
+ E.Options.args.nameplate.args.filters.args.triggers.args.instanceType.args.dungeonDifficulty = nil
+ end
+
+ if E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.raid then
+ E.Options.args.nameplate.args.filters.args.triggers.args.instanceType.args.raidDifficulty = {
+ order = 11,
+ type = "group",
+ name = L["Raid Difficulty"],
+ desc = L["Check these to only have the filter active in certain difficulties. If none are checked, it is active in all difficulties."],
+ guiInline = true,
+ get = function(info) return E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceDifficulty.raid[info[#info]] end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceDifficulty.raid[info[#info]] = value
+ UpdateInstanceDifficulty()
+ NP:ConfigureAll()
+ end,
+ args = {
+ normal = {
+ order = 1,
+ type = "toggle",
+ name = L["PLAYER_DIFFICULTY1"]
+ },
+ heroic = {
+ order = 2,
+ type = "toggle",
+ name = L["PLAYER_DIFFICULTY2"]
+ }
+ }
+ }
+ else
+ E.Options.args.nameplate.args.filters.args.triggers.args.instanceType.args.raidDifficulty = nil
+ end
+end
+
+local function UpdateStyleLists()
+ if E.global.nameplates.filters[selectedNameplateFilter] and E.global.nameplates.filters[selectedNameplateFilter].triggers and E.global.nameplates.filters[selectedNameplateFilter].triggers.names then
+ E.Options.args.nameplate.args.filters.args.triggers.args.names.args.names = {
+ order = 50,
+ type = "group",
+ name = "",
+ guiInline = true,
+ args = {}
+ }
+ if next(E.global.nameplates.filters[selectedNameplateFilter].triggers.names) then
+ for name in pairs(E.global.nameplates.filters[selectedNameplateFilter].triggers.names) do
+ E.Options.args.nameplate.args.filters.args.triggers.args.names.args.names.args[name] = {
+ order = -1,
+ type = "toggle",
+ name = name,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers and E.global.nameplates.filters[selectedNameplateFilter].triggers.names and E.global.nameplates.filters[selectedNameplateFilter].triggers.names[name]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.names[name] = value
+ NP:ConfigureAll()
+ end
+ }
+ end
+ end
+ end
+ if E.global.nameplates.filters[selectedNameplateFilter] and E.global.nameplates.filters[selectedNameplateFilter].triggers.casting and E.global.nameplates.filters[selectedNameplateFilter].triggers.casting.spells then
+ E.Options.args.nameplate.args.filters.args.triggers.args.casting.args.spells = {
+ order = 50,
+ type = "group",
+ name = "",
+ guiInline = true,
+ args = {}
+ }
+ if next(E.global.nameplates.filters[selectedNameplateFilter].triggers.casting.spells) then
+ local spell, spellName, notDisabled
+ for name in pairs(E.global.nameplates.filters[selectedNameplateFilter].triggers.casting.spells) do
+ spell = name
+ if tonumber(spell) then
+ spellName = GetSpellInfo(spell)
+ notDisabled = (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable)
+ if spellName then
+ if notDisabled then
+ spell = format("|cFFffff00%s|r |cFFffffff(%d)|r", spellName, spell)
+ else
+ spell = format("%s (%d)", spellName, spell)
+ end
+ end
+ end
+ E.Options.args.nameplate.args.filters.args.triggers.args.casting.args.spells.args[name] = {
+ order = -1,
+ type = "toggle",
+ name = spell,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers and E.global.nameplates.filters[selectedNameplateFilter].triggers.casting.spells and E.global.nameplates.filters[selectedNameplateFilter].triggers.casting.spells[name]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.casting.spells[name] = value
+ NP:ConfigureAll()
+ end
+ }
+ end
+ end
+ end
+
+ if E.global.nameplates.filters[selectedNameplateFilter] and E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns and E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns.names then
+ E.Options.args.nameplate.args.filters.args.triggers.args.cooldowns.args.names = {
+ order = 50,
+ type = "group",
+ name = "",
+ guiInline = true,
+ args = {}
+ }
+ if next(E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns.names) then
+ local spell, spellName, notDisabled
+ for name in pairs(E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns.names) do
+ spell = name
+ if tonumber(spell) then
+ spellName = GetSpellInfo(spell)
+ notDisabled = (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable)
+ if spellName then
+ if notDisabled then
+ spell = format("|cFFffff00%s|r |cFFffffff(%d)|r", spellName, spell)
+ else
+ spell = format("%s (%d)", spellName, spell)
+ end
+ end
+ end
+ E.Options.args.nameplate.args.filters.args.triggers.args.cooldowns.args.names.args[name] = {
+ order = -1,
+ type = "select",
+ name = spell,
+ values = {
+ ["DISABLED"] = L["DISABLE"],
+ ["ONCD"] = L["On Cooldown"],
+ ["OFFCD"] = L["Off Cooldown"]
+ },
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers and E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns.names and E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns.names[name]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns.names[name] = value
+ NP:ConfigureAll()
+ end
+ }
+ end
+ end
+ end
+
+ if E.global.nameplates.filters[selectedNameplateFilter] and E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs and E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.names then
+ E.Options.args.nameplate.args.filters.args.triggers.args.buffs.args.names = {
+ order = 50,
+ type = "group",
+ name = "",
+ guiInline = true,
+ args = {}
+ }
+ if next(E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.names) then
+ local spell, spellName, notDisabled
+ for name in pairs(E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.names) do
+ spell = name
+ if tonumber(spell) then
+ spellName = GetSpellInfo(spell)
+ notDisabled = (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable)
+ if spellName then
+ if notDisabled then
+ spell = format("|cFFffff00%s|r |cFFffffff(%d)|r", spellName, spell)
+ else
+ spell = format("%s (%d)", spellName, spell)
+ end
+ end
+ end
+ E.Options.args.nameplate.args.filters.args.triggers.args.buffs.args.names.args[name] = {
+ order = -1,
+ type = "toggle",
+ name = spell,
+ textWidth = true,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers and E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.names and E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.names[name]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.names[name] = value
+ NP:ConfigureAll()
+ end
+ }
+ end
+ end
+ end
+
+ if E.global.nameplates.filters[selectedNameplateFilter] and E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs and E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.names then
+ E.Options.args.nameplate.args.filters.args.triggers.args.debuffs.args.names = {
+ order = 50,
+ type = "group",
+ name = "",
+ guiInline = true,
+ args = {}
+ }
+ if next(E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.names) then
+ local spell, spellName, notDisabled
+ for name in pairs(E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.names) do
+ spell = name
+ if tonumber(spell) then
+ spellName = GetSpellInfo(spell)
+ notDisabled = (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable)
+ if spellName then
+ if notDisabled then
+ spell = format("|cFFffff00%s|r |cFFffffff(%d)|r", spellName, spell)
+ else
+ spell = format("%s (%d)", spellName, spell)
+ end
+ end
+ end
+ E.Options.args.nameplate.args.filters.args.triggers.args.debuffs.args.names.args[name] = {
+ textWidth = true,
+ order = -1,
+ type = "toggle",
+ name = spell,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers and E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.names and E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.names[name]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.names[name] = value
+ NP:ConfigureAll()
+ end
+ }
+ end
+ end
+ end
+
+ if E.global.nameplates.filters[selectedNameplateFilter] and E.global.nameplates.filters[selectedNameplateFilter].triggers.totems then
+ for totemSchool in pairs(G.nameplates.totemTypes) do
+ local titemSchoolLoc, order
+
+ if totemSchool == "fire" then
+ titemSchoolLoc, order = BINDING_NAME_MULTICASTACTIONBUTTON10, 51
+ elseif totemSchool == "earth" then
+ titemSchoolLoc, order = BINDING_NAME_MULTICASTACTIONBUTTON1, 50
+ elseif totemSchool == "water" then
+ titemSchoolLoc, order = BINDING_NAME_MULTICASTACTIONBUTTON11, 52
+ elseif totemSchool == "air" then
+ titemSchoolLoc, order = BINDING_NAME_MULTICASTACTIONBUTTON12, 53
+ elseif totemSchool == "other" then
+ titemSchoolLoc, order = OTHER, 54
+ end
+
+ E.Options.args.nameplate.args.filters.args.triggers.args.totems.args[totemSchool] = {
+ order = order,
+ type = "group",
+ name = (totemsColor[totemSchool] or "")..titemSchoolLoc,
+ guiInline = true,
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].triggers.totems.enable end,
+ args = {}
+ }
+ end
+
+ for totem, data in pairs(NP.TriggerConditions.totems) do
+ E.Options.args.nameplate.args.filters.args.triggers.args.totems.args[data[2]].args[totem] = {
+ textWidth = true,
+ order = -1,
+ type = "toggle",
+ name = data[1],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers and E.global.nameplates.filters[selectedNameplateFilter].triggers.totems and E.global.nameplates.filters[selectedNameplateFilter].triggers.totems[totem]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.totems[totem] = value
+ NP:ConfigureAll()
+ end
+ }
+ end
+ end
+
+ if E.global.nameplates.filters[selectedNameplateFilter] and E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits then
+ for unitType in pairs(G.nameplates.uniqueUnitTypes) do
+ local name, order
+
+ if unitType == "pvp" then
+ name, order = "PvP", 50
+ elseif unitType == "pve" then
+ name, order = "PvE", 51
+ end
+
+ E.Options.args.nameplate.args.filters.args.triggers.args.uniqueUnits.args[unitType] = {
+ order = order,
+ type = "group",
+ name = name,
+ guiInline = true,
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits.enable end,
+ args = {}
+ }
+ end
+
+ for unit, data in pairs(NP.TriggerConditions.uniqueUnits) do
+ E.Options.args.nameplate.args.filters.args.triggers.args.uniqueUnits.args[data[2]].args[unit] = {
+ textWidth = true,
+ order = -1,
+ type = "toggle",
+ name = data[1],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers and E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits and E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits[unit]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits[unit] = value
+ NP:ConfigureAll()
+ end
+ }
+ end
+ end
+end
+
+local function UpdateFilterGroup()
+ if not selectedNameplateFilter or not E.global.nameplates.filters[selectedNameplateFilter] then
+ E.Options.args.nameplate.args.filters.args.header = nil
+ E.Options.args.nameplate.args.filters.args.actions = nil
+ E.Options.args.nameplate.args.filters.args.triggers = nil
+ end
+ if selectedNameplateFilter and E.global.nameplates.filters[selectedNameplateFilter] then
+ E.Options.args.nameplate.args.filters.args.header = {
+ order = 4,
+ type = "header",
+ name = selectedNameplateFilter
+ }
+ E.Options.args.nameplate.args.filters.args.triggers = {
+ order = 5,
+ type = "group",
+ name = L["Triggers"],
+ args = {
+ enable = {
+ order = 0,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info)
+ return (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable)
+ end,
+ set = function(info, value)
+ if not E.db.nameplates then E.db.nameplates = {} end
+ if not E.db.nameplates.filters then E.db.nameplates.filters = {} end
+ if not E.db.nameplates.filters[selectedNameplateFilter] then E.db.nameplates.filters[selectedNameplateFilter] = {} end
+ if not E.db.nameplates.filters[selectedNameplateFilter].triggers then E.db.nameplates.filters[selectedNameplateFilter].triggers = {} end
+ E.db.nameplates.filters[selectedNameplateFilter].triggers.enable = value
+ UpdateStyleLists() --we need this to recolor the spellid based on wether or not the filter is disabled
+ NP:ConfigureAll()
+ end
+ },
+ priority = {
+ order = 1,
+ type = "range",
+ name = L["Filter Priority"],
+ desc = L["Lower numbers mean a higher priority. Filters are processed in order from 1 to 100."],
+ min = 1, max = 100, step = 1,
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.priority or 1
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.priority = value
+ NP:ConfigureAll()
+ end
+ },
+ resetFilter = {
+ order = 2,
+ type = "execute",
+ name = L["Clear Filter"],
+ desc = L["Return filter to its default state."],
+ func = function()
+ local filter = {}
+ if G.nameplates.filters[selectedNameplateFilter] then
+ filter = E:CopyTable(filter, G.nameplates.filters[selectedNameplateFilter])
+ end
+ NP:StyleFilterCopyDefaults(filter)
+ E.global.nameplates.filters[selectedNameplateFilter] = filter
+ UpdateStyleLists()
+ UpdateInstanceDifficulty()
+ NP:ConfigureAll()
+ end
+ },
+ spacer1 = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ names = {
+ order = 4,
+ type = "group",
+ name = L["NAME"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ addName = {
+ order = 1,
+ type = "input",
+ name = L["Add Name"],
+ desc = L["Add a Name to the list."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then
+ return
+ end
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.names[value] = true
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end
+ },
+ removeName = {
+ order = 2,
+ type = "input",
+ name = L["Remove Name"],
+ desc = L["Remove a Name from the list."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then
+ return
+ end
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.names[value] = nil
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ targeting = {
+ order = 5,
+ type = "group",
+ name = L["Targeting"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers[info[#info]]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ disabled = function()
+ return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter]
+ and E.db.nameplates.filters[selectedNameplateFilter].triggers
+ and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable)
+ end,
+ args = {
+ isTarget = {
+ order = 1,
+ type = "toggle",
+ name = L["Is Targeted"],
+ desc = L["If enabled then the filter will only activate when you are targeting the unit."]
+ },
+ notTarget = {
+ order = 2,
+ type = "toggle",
+ name = L["Not Targeted"],
+ desc = L["If enabled then the filter will only activate when you are not targeting the unit."]
+ },
+ requireTarget = {
+ order = 3,
+ type = "toggle",
+ name = L["Require Target"],
+ desc = L["If enabled then the filter will only activate when you have a target."]
+ },
+ }
+ },
+ casting = {
+ order = 6,
+ type = "group",
+ name = L["Casting"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.casting[info[#info]]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.casting[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ disabled = function()
+ return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and
+ E.db.nameplates.filters[selectedNameplateFilter].triggers and
+ E.db.nameplates.filters[selectedNameplateFilter].triggers.enable)
+ end,
+ args = {
+ types = {
+ name = "",
+ type = "group",
+ guiInline = true,
+ order = 2,
+ args = {
+ isCasting = {
+ type = "toggle",
+ order = 1,
+ name = L["Is Casting Anything"],
+ desc = L["If enabled then the filter will activate if the unit is casting anything."]
+ },
+ notCasting = {
+ type = "toggle",
+ order = 2,
+ name = L["Not Casting Anything"],
+ desc = L["If enabled then the filter will activate if the unit is not casting anything."]
+ },
+ isChanneling = {
+ type = "toggle",
+ order = 3,
+ customWidth = 200,
+ name = L["Is Channeling Anything"],
+ desc = L["If enabled then the filter will activate if the unit is channeling anything."]
+ },
+ notChanneling = {
+ type = "toggle",
+ order = 4,
+ customWidth = 200,
+ name = L["Not Channeling Anything"],
+ desc = L["If enabled then the filter will activate if the unit is not channeling anything."]
+ },
+ spacer1 = {
+ order = 5,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ interruptible = {
+ type = "toggle",
+ order = 6,
+ name = L["Interruptible"],
+ desc = L["If enabled then the filter will only activate if the unit is casting interruptible spells."]
+ },
+ notInterruptible = {
+ type = "toggle",
+ order = 7,
+ name = L["Non-Interruptable"],
+ desc = L["If enabled then the filter will only activate if the unit is casting not interruptible spells."]
+ }
+ }
+ },
+ addSpell = {
+ order = 9,
+ name = L["Add Spell ID or Name"],
+ type = "input",
+ get = function(info)
+ return ""
+ end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then return end
+
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.casting.spells[value] = true
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end
+ },
+ removeSpell = {
+ order = 10,
+ name = L["Remove Spell ID or Name"],
+ desc = L["If the aura is listed with a number then you need to use that to remove it from the list."],
+ type = "input",
+ get = function(info)
+ return ""
+ end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then return end
+
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.casting.spells[value] = nil
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end
+ },
+ description1 = {
+ order = 12,
+ type = "description",
+ name = L["You do not need to use 'Is Casting Anything' or 'Is Channeling Anything' for these spells to trigger."]
+ },
+ description2 = {
+ order = 13,
+ type = "description",
+ name = L["If this list is empty, and if 'Interruptible' is checked, then the filter will activate on any type of cast that can be interrupted."]
+ },
+ notSpell = {
+ type = "toggle",
+ order = -2,
+ name = L["Not Spell"],
+ desc = L["If enabled then the filter will only activate if the unit is not casting or channeling one of the selected spells."]
+ }
+ }
+ },
+ combat = {
+ order = 7,
+ type = "group",
+ name = L["COMBAT"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ inCombat = {
+ order = 1,
+ type = "toggle",
+ name = L["Player in Combat"],
+ desc = L["If enabled then the filter will only activate when you are in combat."],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.inCombat
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.inCombat = value
+ NP:ConfigureAll()
+ end
+ },
+ outOfCombat = {
+ order = 2,
+ type = "toggle",
+ name = L["Player Out of Combat"],
+ desc = L["If enabled then the filter will only activate when you are out of combat."],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.outOfCombat
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.outOfCombat = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ role = {
+ order = 8,
+ type = "group",
+ name = L["ROLE"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ tank = {
+ order = 1,
+ type = "toggle",
+ name = L["TANK"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.role.tank
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.role.tank = value
+ NP:ConfigureAll()
+ end,
+ },
+ healer = {
+ order = 2,
+ type = "toggle",
+ name = L["HEALER"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.role.healer
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.role.healer = value
+ NP:ConfigureAll()
+ end
+ },
+ damager = {
+ order = 3,
+ type = "toggle",
+ name = L["DAMAGER"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.role.damager
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.role.damager = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ health = {
+ order = 9,
+ type = "group",
+ name = L["Health Threshold"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.healthThreshold
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.healthThreshold = value
+ NP:ConfigureAll()
+ end
+ },
+ usePlayer = {
+ order = 2,
+ type = "toggle",
+ name = L["Player Health"],
+ desc = L["Enabling this will check your health amount."],
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].triggers.healthThreshold end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.healthUsePlayer
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.healthUsePlayer = value
+ NP:ConfigureAll()
+ end
+ },
+ spacer1 = {
+ order = 3,
+ type = "description",
+ name = " "
+ },
+ underHealthThreshold = {
+ order = 4,
+ type = "range",
+ name = L["Under Health Threshold"],
+ desc = L["If this threshold is used then the health of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."],
+ min = 0, max = 1, step = 0.01,
+ isPercent = true,
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].triggers.healthThreshold end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.underHealthThreshold or 0
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.underHealthThreshold = value
+ NP:ConfigureAll()
+ end
+ },
+ overHealthThreshold = {
+ order = 5,
+ type = "range",
+ name = L["Over Health Threshold"],
+ desc = L["If this threshold is used then the health of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."],
+ min = 0, max = 1, step = 0.01,
+ isPercent = true,
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].triggers.healthThreshold end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.overHealthThreshold or 0
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.overHealthThreshold = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ power = {
+ order = 10,
+ type = "group",
+ name = L["Power Threshold"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ powerThreshold = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Enabling this will check your power amount."],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.powerThreshold
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.powerThreshold = value
+ NP:ConfigureAll()
+ end
+ },
+ spacer1 = {
+ order = 2,
+ type = "description",
+ name = " "
+ },
+ underPowerThreshold = {
+ order = 3,
+ type = "range",
+ name = L["Under Power Threshold"],
+ desc = L["If this threshold is used then the power of the unit needs to be lower than this value in order for the filter to activate. Set to 0 to disable."],
+ min = 0, max = 1, step = 0.01,
+ isPercent = true,
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].triggers.powerThreshold end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.underPowerThreshold or 0
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.underPowerThreshold = value
+ NP:ConfigureAll()
+ end
+ },
+ overPowerThreshold = {
+ order = 4,
+ type = "range",
+ name = L["Over Power Threshold"],
+ desc = L["If this threshold is used then the power of the unit needs to be higher than this value in order for the filter to activate. Set to 0 to disable."],
+ min = 0, max = 1, step = 0.01,
+ isPercent = true,
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].triggers.powerThreshold end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.overPowerThreshold or 0
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.overPowerThreshold = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ levels = {
+ order = 11,
+ type = "group",
+ name = L["LEVEL"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.level
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.level = value
+ NP:ConfigureAll()
+ end
+ },
+ matchLevel = {
+ order = 2,
+ type = "toggle",
+ name = L["Match Player Level"],
+ desc = L["If enabled then the filter will only activate if the level of the unit matches your own."],
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].triggers.level end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.mylevel
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.mylevel = value
+ NP:ConfigureAll()
+ end
+ },
+ spacer1 = {
+ order = 3,
+ type = "description",
+ name = L["LEVEL_BOSS"],
+ },
+ minLevel = {
+ order = 4,
+ type = "range",
+ name = L["Minimum Level"],
+ desc = L["If enabled then the filter will only activate if the level of the unit is equal to or higher than this value."],
+ min = -1, max = MAX_PLAYER_LEVEL+3, step = 1,
+ disabled = function() return not (E.global.nameplates.filters[selectedNameplateFilter].triggers.level and not E.global.nameplates.filters[selectedNameplateFilter].triggers.mylevel) end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.minlevel or 0
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.minlevel = value
+ NP:ConfigureAll()
+ end
+ },
+ maxLevel = {
+ order = 5,
+ type = "range",
+ name = L["Maximum Level"],
+ desc = L["If enabled then the filter will only activate if the level of the unit is equal to or lower than this value."],
+ min = -1, max = MAX_PLAYER_LEVEL+3, step = 1,
+ disabled = function() return not (E.global.nameplates.filters[selectedNameplateFilter].triggers.level and not E.global.nameplates.filters[selectedNameplateFilter].triggers.mylevel) end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.maxlevel or 0
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.maxlevel = value
+ NP:ConfigureAll()
+ end
+ },
+ currentLevel = {
+ order = 6,
+ type = "range",
+ name = L["Current Level"],
+ desc = L["If enabled then the filter will only activate if the level of the unit matches this value."],
+ min = -1, max = MAX_PLAYER_LEVEL+3, step = 1,
+ disabled = function() return not (E.global.nameplates.filters[selectedNameplateFilter].triggers.level and not E.global.nameplates.filters[selectedNameplateFilter].triggers.mylevel) end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.curlevel or 0
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.curlevel = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ cooldowns = {
+ order = 12,
+ type = "group",
+ name = L["Cooldowns"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ mustHaveAll = {
+ order = 1,
+ type = "toggle",
+ name = L["Require All"],
+ desc = L["If enabled then it will require all cooldowns to activate the filter. Otherwise it will only require any one of the cooldowns to activate it."],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns and E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns.mustHaveAll
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns.mustHaveAll = value
+ NP:ConfigureAll()
+ end
+ },
+ spacer1 = {
+ order = 5,
+ type = "description",
+ name = " "
+ },
+ addCooldown = {
+ order = 6,
+ type = "input",
+ name = L["Add Spell ID or Name"],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then
+ return
+ end
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns.names[value] = "ONCD"
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end
+ },
+ removeCooldown = {
+ order = 7,
+ type = "input",
+ name = L["Remove Spell ID or Name"],
+ desc = L["If the aura is listed with a number then you need to use that to remove it from the list."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then
+ return
+ end
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.cooldowns.names[value] = nil
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ buffs = {
+ order = 13,
+ type = "group",
+ name = L["Buffs"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ mustHaveAll = {
+ order = 1,
+ type = "toggle",
+ name = L["Require All"],
+ desc = L["If enabled then it will require all auras to activate the filter. Otherwise it will only require any one of the auras to activate it."],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs and E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.mustHaveAll
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.mustHaveAll = value
+ NP:ConfigureAll()
+ end
+ },
+ missing = {
+ order = 2,
+ type = "toggle",
+ name = L["Missing"],
+ desc = L["If enabled then it checks if auras are missing instead of being present on the unit."],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs and E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.missing
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.missing = value
+ NP:ConfigureAll()
+ end
+ },
+ minTimeLeft = {
+ order = 3,
+ type = "range",
+ name = L["Minimum Time Left"],
+ desc = L["Apply this filter if a buff has remaining time greater than this. Set to zero to disable."],
+ min = 0, max = 10800, step = 1,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs and E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.minTimeLeft
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.minTimeLeft = value
+ NP:ConfigureAll()
+ end
+ },
+ maxTimeLeft = {
+ order = 4,
+ type = "range",
+ name = L["Maximum Time Left"],
+ desc = L["Apply this filter if a buff has remaining time less than this. Set to zero to disable."],
+ min = 0, max = 10800, step = 1,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs and E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.maxTimeLeft
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.maxTimeLeft = value
+ NP:ConfigureAll()
+ end
+ },
+ spacer1 = {
+ order = 5,
+ type = "description",
+ name = " "
+ },
+ addBuff = {
+ order = 6,
+ type = "input",
+ name = L["Add Spell ID or Name"],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then
+ return
+ end
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.names[value] = true
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end
+ },
+ removeBuff = {
+ order = 7,
+ type = "input",
+ name = L["Remove Spell ID or Name"],
+ desc = L["If the aura is listed with a number then you need to use that to remove it from the list."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then
+ return
+ end
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.buffs.names[value] = nil
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ debuffs = {
+ order = 14,
+ type = "group",
+ name = L["Debuffs"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ mustHaveAll = {
+ order = 1,
+ name = L["Require All"],
+ desc = L["If enabled then it will require all auras to activate the filter. Otherwise it will only require any one of the auras to activate it."],
+ type = "toggle",
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs and E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.mustHaveAll
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.mustHaveAll = value
+ NP:ConfigureAll()
+ end
+ },
+ missing = {
+ order = 2,
+ type = "toggle",
+ name = L["Missing"],
+ desc = L["If enabled then it checks if auras are missing instead of being present on the unit."],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs and E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.missing
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.missing = value
+ NP:ConfigureAll()
+ end
+ },
+ minTimeLeft = {
+ order = 3,
+ type = "range",
+ name = L["Minimum Time Left"],
+ desc = L["Apply this filter if a debuff has remaining time greater than this. Set to zero to disable."],
+ min = 0, max = 10800, step = 1,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs and E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.minTimeLeft
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.minTimeLeft = value
+ NP:ConfigureAll()
+ end
+ },
+ maxTimeLeft = {
+ order = 4,
+ type = "range",
+ name = L["Maximum Time Left"],
+ desc = L["Apply this filter if a debuff has remaining time less than this. Set to zero to disable."],
+ min = 0, max = 10800, step = 1,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs and E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.maxTimeLeft
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.maxTimeLeft = value
+ NP:ConfigureAll()
+ end
+ },
+ spacer1 = {
+ order = 5,
+ type = "description",
+ name = " "
+ },
+ addDebuff = {
+ order = 6,
+ type = "input",
+ name = L["Add Spell ID or Name"],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then
+ return
+ end
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.names[value] = true
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end
+ },
+ removeDebuff = {
+ order = 7,
+ type = "input",
+ name = L["Remove Spell ID or Name"],
+ desc = L["If the aura is listed with a number then you need to use that to remove it from the list."],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then
+ return
+ end
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.debuffs.names[value] = nil
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ nameplateType = {
+ order = 15,
+ type = "group",
+ name = L["Unit Type"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ enable = {
+ order = 0,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType and E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType.enable
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType.enable = value
+ NP:ConfigureAll()
+ end
+ },
+ types = {
+ order = 1,
+ type = "group",
+ name = "",
+ guiInline = true,
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) or not E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType.enable end,
+ args = {
+ friendlyPlayer = {
+ order = 1,
+ type = "toggle",
+ name = L["FRIENDLY_PLAYER"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType.friendlyPlayer
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType.friendlyPlayer = value
+ NP:ConfigureAll()
+ end
+ },
+ friendlyNPC = {
+ order = 2,
+ type = "toggle",
+ name = L["FRIENDLY_NPC"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType.friendlyNPC
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType.friendlyNPC = value
+ NP:ConfigureAll()
+ end
+ },
+ enemyPlayer = {
+ order = 3,
+ type = "toggle",
+ name = L["ENEMY_PLAYER"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType.enemyPlayer
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType.enemyPlayer = value
+ NP:ConfigureAll()
+ end
+ },
+ enemyNPC = {
+ order = 4,
+ type = "toggle",
+ name = L["ENEMY_NPC"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType.enemyNPC
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.nameplateType.enemyNPC = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ }
+ }
+ },
+ reactionType = {
+ order = 16,
+ type = "group",
+ name = L["Reaction Type"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ enable = {
+ order = 0,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.reactionType and E.global.nameplates.filters[selectedNameplateFilter].triggers.reactionType.enable
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.reactionType.enable = value
+ NP:ConfigureAll()
+ end
+ },
+ types = {
+ order = 1,
+ type = "group",
+ name = "",
+ guiInline = true,
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) or not E.global.nameplates.filters[selectedNameplateFilter].triggers.reactionType.enable end,
+ args = {
+ hostile = {
+ order = 1,
+ type = "toggle",
+ name = L["FACTION_STANDING_LABEL2"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.reactionType.hostile
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.reactionType.hostile = value
+ NP:ConfigureAll()
+ end
+ },
+ neutral = {
+ order = 2,
+ type = "toggle",
+ name = L["FACTION_STANDING_LABEL4"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.reactionType.neutral
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.reactionType.neutral = value
+ NP:ConfigureAll()
+ end
+ },
+ friendly = {
+ order = 3,
+ type = "toggle",
+ name = L["FACTION_STANDING_LABEL5"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.reactionType.friendly
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.reactionType.friendly = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ }
+ }
+ },
+ instanceType = {
+ order = 17,
+ type = "group",
+ name = L["Instance Type"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ none = {
+ order = 1,
+ type = "toggle",
+ name = L["NONE"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.none
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.none = value
+ NP:ConfigureAll()
+ end
+ },
+ sanctuary = {
+ order = 1,
+ type = "toggle",
+ name = L["Sanctuary"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.sanctuary
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.sanctuary = value
+ NP:ConfigureAll()
+ end
+ },
+ party = {
+ order = 2,
+ type = "toggle",
+ name = L["DUNGEONS"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.party
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.party = value
+ UpdateInstanceDifficulty()
+ NP:ConfigureAll()
+ end
+ },
+ raid = {
+ order = 3,
+ type = "toggle",
+ name = L["RAID"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.raid
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.raid = value
+ UpdateInstanceDifficulty()
+ NP:ConfigureAll()
+ end
+ },
+ arena = {
+ order = 4,
+ type = "toggle",
+ name = L["ARENA"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.arena
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.arena = value
+ NP:ConfigureAll()
+ end
+ },
+ pvp = {
+ order = 5,
+ type = "toggle",
+ name = L["BATTLEFIELDS"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.pvp
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.instanceType.pvp = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ raidTarget = {
+ order = 27,
+ type = "group",
+ name = L["BINDING_HEADER_RAID_TARGET"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.raidTarget[info[#info]]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.raidTarget[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ disabled = function()
+ return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and
+ E.db.nameplates.filters[selectedNameplateFilter].triggers and
+ E.db.nameplates.filters[selectedNameplateFilter].triggers.enable)
+ end,
+ args = {
+ types = {
+ name = "",
+ type = "group",
+ guiInline = true,
+ order = 2,
+ args = {
+ star = {
+ type = "toggle",
+ order = 1,
+ name = format(raidTargetIcon, 1, L["RAID_TARGET_1"])
+ },
+ circle = {
+ type = "toggle",
+ order = 2,
+ name = format(raidTargetIcon, 2, L["RAID_TARGET_2"])
+ },
+ diamond = {
+ type = "toggle",
+ order = 3,
+ name = format(raidTargetIcon, 3, L["RAID_TARGET_3"])
+ },
+ triangle = {
+ type = "toggle",
+ order = 4,
+ name = format(raidTargetIcon, 4, L["RAID_TARGET_4"])
+ },
+ moon = {
+ type = "toggle",
+ order = 5,
+ name = format(raidTargetIcon, 5, L["RAID_TARGET_5"])
+ },
+ square = {
+ type = "toggle",
+ order = 6,
+ name = format(raidTargetIcon, 6, L["RAID_TARGET_6"])
+ },
+ cross = {
+ type = "toggle",
+ order = 7,
+ name = format(raidTargetIcon, 7, L["RAID_TARGET_7"])
+ },
+ skull = {
+ type = "toggle",
+ order = 8,
+ name = format(raidTargetIcon, 8, L["RAID_TARGET_8"])
+ }
+ }
+ }
+ }
+ },
+ totems = {
+ order = 28,
+ type = "group",
+ name = L["Totem"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.totems[info[#info]]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.totems[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ disabled = function()
+ return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and
+ E.db.nameplates.filters[selectedNameplateFilter].triggers and
+ E.db.nameplates.filters[selectedNameplateFilter].triggers.enable)
+ end,
+ args = {
+ enable = {
+ order = 0,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.totems and E.global.nameplates.filters[selectedNameplateFilter].triggers.totems.enable
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.totems.enable = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ uniqueUnits = {
+ order = 28,
+ type = "group",
+ name = L["Unique Units"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits[info[#info]]
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ disabled = function()
+ return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and
+ E.db.nameplates.filters[selectedNameplateFilter].triggers and
+ E.db.nameplates.filters[selectedNameplateFilter].triggers.enable)
+ end,
+ args = {
+ enable = {
+ order = 0,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits and E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits.enable
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits.enable = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ }
+ }
+ }
+ E.Options.args.nameplate.args.filters.args.actions = {
+ order = 6,
+ type = "group",
+ name = L["Actions"],
+ disabled = function() return not (E.db.nameplates and E.db.nameplates.filters and E.db.nameplates.filters[selectedNameplateFilter] and E.db.nameplates.filters[selectedNameplateFilter].triggers and E.db.nameplates.filters[selectedNameplateFilter].triggers.enable) end,
+ args = {
+ hide = {
+ order = 1,
+ type = "toggle",
+ name = L["Hide Frame"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.hide
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.hide = value
+ NP:ConfigureAll()
+ end
+ },
+ nameOnly = {
+ order = 2,
+ type = "toggle",
+ name = L["Name Only"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.nameOnly
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.nameOnly = value
+ NP:ConfigureAll()
+ end,
+ disabled = function() return E.global.nameplates.filters[selectedNameplateFilter].actions.hide end
+ },
+ icon = {
+ order = 3,
+ type = "toggle",
+ name = L["Icon"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.icon
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.icon = value
+ NP:ConfigureAll()
+ end,
+ disabled = function()
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.hide or not (E.global.nameplates.filters[selectedNameplateFilter].triggers.totems.enable or E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits.enable)
+ end
+ },
+ iconOnly = {
+ order = 3,
+ type = "toggle",
+ name = L["Icon Only"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.iconOnly
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.iconOnly = value
+ NP:ConfigureAll()
+ end,
+ disabled = function()
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.hide or not (E.global.nameplates.filters[selectedNameplateFilter].triggers.totems.enable or E.global.nameplates.filters[selectedNameplateFilter].triggers.uniqueUnits.enable)
+ end
+ },
+ spacer1 = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ scale = {
+ order = 5,
+ type = "range",
+ name = L["Scale"],
+ disabled = function() return E.global.nameplates.filters[selectedNameplateFilter].actions.hide end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.scale or 1
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.scale = value
+ NP:ConfigureAll()
+ end,
+ min = 0.35, max = 1.5, step = 0.01
+ },
+ alpha = {
+ order = 6,
+ type = "range",
+ name = L["Alpha"],
+ disabled = function() return E.global.nameplates.filters[selectedNameplateFilter].actions.hide end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.alpha or -1
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.alpha = value
+ NP:ConfigureAll()
+ end,
+ min = -1, max = 100, step = 1
+ },
+ frameLevel = {
+ order = 7,
+ name = L["Frame Level"],
+ desc = L["NAMEPLATE_FRAMELEVEL_DESC"],
+ type = "range",
+ min = 0, max = 10, step = 1,
+ disabled = function() return E.global.nameplates.filters[selectedNameplateFilter].actions.hide end,
+ get = function(info) return E.global.nameplates.filters[selectedNameplateFilter].actions.frameLevel or 0 end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.frameLevel = value
+ NP:ConfigureAll()
+ end,
+ },
+ color = {
+ order = 10,
+ type = "group",
+ name = L["COLOR"],
+ guiInline = true,
+ disabled = function() return E.global.nameplates.filters[selectedNameplateFilter].actions.hide end,
+ args = {
+ health = {
+ order = 1,
+ type = "toggle",
+ name = L["HEALTH"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.color.health
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.color.health = value
+ NP:ConfigureAll()
+ end
+ },
+ healthColor = {
+ order = 2,
+ type = "color",
+ name = L["Health Color"],
+ hasAlpha = true,
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].actions.color.health end,
+ get = function(info)
+ local t = E.global.nameplates.filters[selectedNameplateFilter].actions.color.healthColor
+ return t.r, t.g, t.b, t.a, 136/255, 255/255, 102/255, 1
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.global.nameplates.filters[selectedNameplateFilter].actions.color.healthColor
+ t.r, t.g, t.b, t.a = r, g, b, a
+ NP:ConfigureAll()
+ end
+ },
+ spacer1 = {
+ order = 3,
+ type = "description",
+ name = " ",
+ },
+ border = {
+ order = 4,
+ type = "toggle",
+ name = L["Border"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.color.border
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.color.border = value
+ NP:ConfigureAll()
+ end
+ },
+ borderColor = {
+ order = 5,
+ type = "color",
+ name = L["Border Color"],
+ hasAlpha = true,
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].actions.color.border end,
+ get = function(info)
+ local t = E.global.nameplates.filters[selectedNameplateFilter].actions.color.borderColor
+ return t.r, t.g, t.b, t.a, 0, 0, 0, 1
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.global.nameplates.filters[selectedNameplateFilter].actions.color.borderColor
+ t.r, t.g, t.b, t.a = r, g, b, a
+ NP:ConfigureAll()
+ end
+ },
+ spacer2 = {
+ order = 6,
+ type = "description",
+ name = " "
+ },
+ name = {
+ order = 7,
+ type = "toggle",
+ name = L["NAME"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.color.name
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.color.name = value
+ NP:ConfigureAll()
+ end
+ },
+ nameColor = {
+ order = 8,
+ type = "color",
+ name = L["Name Color"],
+ hasAlpha = true,
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].actions.color.name end,
+ get = function(info)
+ local t = E.global.nameplates.filters[selectedNameplateFilter].actions.color.nameColor
+ return t.r, t.g, t.b, t.a, 200/255, 200/255, 200/255, 1
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.global.nameplates.filters[selectedNameplateFilter].actions.color.nameColor
+ t.r, t.g, t.b, t.a = r, g, b, a
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ texture = {
+ order = 20,
+ type = "group",
+ name = L["Texture"],
+ guiInline = true,
+ disabled = function() return E.global.nameplates.filters[selectedNameplateFilter].actions.hide end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.texture.enable
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.texture.enable = value
+ NP:ConfigureAll()
+ end
+ },
+ texture = {
+ order = 2,
+ type = "select",
+ dialogControl = "LSM30_Statusbar",
+ name = L["Texture"],
+ values = AceGUIWidgetLSMlists.statusbar,
+ disabled = function() return not E.global.nameplates.filters[selectedNameplateFilter].actions.texture.enable end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.texture.texture
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.texture.texture = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ flashing = {
+ order = 30,
+ type = "group",
+ name = L["Flash"],
+ guiInline = true,
+ disabled = function() return E.global.nameplates.filters[selectedNameplateFilter].actions.hide end,
+ args = {
+ enable = {
+ name = L["Enable"],
+ order = 1,
+ type = "toggle",
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.flash.enable
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.flash.enable = value
+ NP:ConfigureAll()
+ end
+ },
+ speed = {
+ order = 2,
+ type = "range",
+ name = L["SPEED"],
+ disabled = function() return E.global.nameplates.filters[selectedNameplateFilter].actions.hide end,
+ get = function(info)
+ return E.global.nameplates.filters[selectedNameplateFilter].actions.flash.speed or 4
+ end,
+ set = function(info, value)
+ E.global.nameplates.filters[selectedNameplateFilter].actions.flash.speed = value
+ NP:ConfigureAll()
+ end,
+ min = 1, max = 10, step = 1
+ },
+ color = {
+ order = 3,
+ type = "color",
+ name = L["COLOR"],
+ hasAlpha = true,
+ disabled = function() return E.global.nameplates.filters[selectedNameplateFilter].actions.hide end,
+ get = function(info)
+ local t = E.global.nameplates.filters[selectedNameplateFilter].actions.flash.color
+ return t.r, t.g, t.b, t.a, 104/255, 138/255, 217/255, 1
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.global.nameplates.filters[selectedNameplateFilter].actions.flash.color
+ t.r, t.g, t.b, t.a = r, g, b, a
+ NP:ConfigureAll()
+ end
+ }
+ }
+ }
+ }
+ }
+
+ UpdateInstanceDifficulty()
+ UpdateStyleLists()
+ end
+end
+
+local ORDER = 100
+local function GetUnitSettings(unit, name)
+ local copyValues = {}
+ for x, y in pairs(NP.db.units) do
+ if type(y) == "table" and x ~= unit then
+ copyValues[x] = L[x]
+ end
+ end
+ local group = {
+ order = ORDER,
+ type = "group",
+ name = name,
+ childGroups = "tab",
+ get = function(info) return E.db.nameplates.units[unit][info[#info]] end,
+ set = function(info, value) E.db.nameplates.units[unit][info[#info]] = value NP:ConfigureAll() end,
+ disabled = function() return not E.NamePlates.Initialized end,
+ args = {
+ showTestFrame = {
+ order = -10,
+ name = L["Show/Hide Test Frame"],
+ type = "execute",
+ func = function(info)
+ NP:TogleTestFrame(unit)
+ end
+ },
+ copySettings = {
+ order = -9,
+ type = "select",
+ name = L["Copy Settings From"],
+ desc = L["Copy settings from another unit."],
+ values = copyValues,
+ get = function() return "" end,
+ set = function(info, value)
+ NP:CopySettings(value, unit)
+ NP:ConfigureAll()
+ end
+ },
+ defaultSettings = {
+ order = -8,
+ type = "execute",
+ name = L["Default Settings"],
+ desc = L["Set Settings to Default"],
+ func = function(info)
+ NP:ResetSettings(unit)
+ NP:ConfigureAll()
+ end
+ },
+ healthGroup = {
+ order = 1,
+ type = "group",
+ name = L["HEALTH"],
+ get = function(info) return E.db.nameplates.units[unit].health[info[#info]] end,
+ set = function(info, value) E.db.nameplates.units[unit].health[info[#info]] = value NP:ConfigureAll() end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["HEALTH"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 4, max = 20, step = 1
+ },
+ width = {
+ order = 4,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 200, step = 1
+ },
+ textGroup = {
+ order = 5,
+ type = "group",
+ name = L["Text"],
+ guiInline = true,
+ get = function(info)
+ return E.db.nameplates.units[unit].health.text[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].health.text[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ format = {
+ order = 2,
+ type = "select",
+ name = L["Format"],
+ values = {
+ ["CURRENT"] = L["Current"],
+ ["CURRENT_MAX"] = L["Current / Max"],
+ ["CURRENT_PERCENT"] = L["Current - Percent"],
+ ["CURRENT_MAX_PERCENT"] = L["Current - Max | Percent"],
+ ["PERCENT"] = L["Percent"],
+ ["DEFICIT"] = L["Deficit"]
+ }
+ },
+ position = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["CENTER"] = "CENTER",
+ ["TOPLEFT"] = "TOPLEFT",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT"
+ }
+ },
+ parent = {
+ order = 4,
+ type = "select",
+ name = L["Parent"],
+ values = {
+ ["Nameplate"] = L["Nameplate"],
+ ["Health"] = L["Health"]
+ }
+ },
+ xOffset = {
+ order = 5,
+ type = "range",
+ name = L["X-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ yOffset = {
+ order = 6,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ fontGroup = {
+ type = "group",
+ order = 7,
+ name = L["Fonts"],
+ guiInline = true,
+ get = function(info)
+ return E.db.nameplates.units[unit].health.text[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].health.text[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ font = {
+ order = 1,
+ type = "select",
+ name = L["Font"],
+ dialogControl = "LSM30_Font",
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontSize = {
+ order = 2,
+ name = L["FONT_SIZE"],
+ type = "range",
+ min = 4, max = 32, step = 1
+ },
+ fontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ castGroup = {
+ order = 2,
+ type = "group",
+ name = L["Cast Bar"],
+ get = function(info) return E.db.nameplates.units[unit].castbar[info[#info]] end,
+ set = function(info, value) E.db.nameplates.units[unit].castbar[info[#info]] = value; NP:ConfigureAll() end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Cast Bar"]
+ },
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ timeToHold = {
+ order = 2,
+ type = "range",
+ name = L["Time To Hold"],
+ desc = L["How many seconds the castbar should stay visible after the cast failed or was interrupted."],
+ min = 0, max = 4, step = 0.1
+ },
+ width = {
+ order = 3,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 250, step = 1
+ },
+ height = {
+ order = 4,
+ type = "range",
+ name = L["Height"],
+ min = 4, max = 20, step = 1
+ },
+ xOffset = {
+ order = 5,
+ type = "range",
+ name = L["X-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ yOffset = {
+ order = 6,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ textGroup = {
+ order = 7,
+ type = "group",
+ name = L["Text"],
+ get = function(info)
+ return E.db.nameplates.units[unit].castbar[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].castbar[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ guiInline = true,
+ args = {
+ hideSpellName = {
+ order = 1,
+ type = "toggle",
+ name = L["Hide Spell Name"]
+ },
+ hideTime = {
+ order = 2,
+ type = "toggle",
+ name = L["Hide Time"]
+ },
+ textPosition = {
+ order = 3,
+ type = "select",
+ name = L["Text Position"],
+ values = {
+ ["ONBAR"] = L["Cast Bar"],
+ ["ABOVE"] = L["Above"],
+ ["BELOW"] = L["Below"]
+ }
+ },
+ castTimeFormat = {
+ order = 4,
+ type = "select",
+ name = L["Cast Time Format"],
+ values = {
+ ["CURRENT"] = L["Current"],
+ ["CURRENTMAX"] = L["Current / Max"],
+ ["REMAINING"] = L["Remaining"],
+ ["REMAININGMAX"] = L["Remaining / Max"]
+ }
+ },
+ channelTimeFormat = {
+ order = 5,
+ type = "select",
+ name = L["Channel Time Format"],
+ values = {
+ ["CURRENT"] = L["Current"],
+ ["CURRENTMAX"] = L["Current / Max"],
+ ["REMAINING"] = L["Remaining"],
+ ["REMAININGMAX"] = L["Remaining / Max"]
+ }
+ }
+ }
+ },
+ iconGroup = {
+ order = 8,
+ name = L["Icon"],
+ type = "group",
+ get = function(info)
+ return E.db.nameplates.units[unit].castbar[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].castbar[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ guiInline = true,
+ args = {
+ showIcon = {
+ order = 11,
+ type = "toggle",
+ name = L["Show Icon"]
+ },
+ iconPosition = {
+ order = 12,
+ type = "select",
+ name = L["Icon Position"],
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"]
+ }
+ },
+ iconSize = {
+ order = 13,
+ name = L["Icon Size"],
+ type = "range",
+ min = 4, max = 40, step = 1
+ },
+ iconOffsetX = {
+ order = 14,
+ name = L["X-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ },
+ iconOffsetY = {
+ order = 15,
+ name = L["Y-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ }
+ }
+ },
+ fontGroup = {
+ type = "group",
+ order = 30,
+ name = L["Font"],
+ guiInline = true,
+ get = function(info)
+ return E.db.nameplates.units[unit].castbar[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].castbar[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ font = {
+ order = 1,
+ type = "select",
+ name = L["Font"],
+ dialogControl = "LSM30_Font",
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontSize = {
+ order = 2,
+ name = L["FONT_SIZE"],
+ type = "range",
+ min = 4, max = 60, step = 1
+ },
+ fontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ }
+ }
+ }
+ }
+ },
+ buffsGroup = {
+ order = 3,
+ type = "group",
+ name = L["Buffs"],
+ get = function(info)
+ return E.db.nameplates.units[unit].buffs[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].buffs[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Buffs"]
+ },
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ perrow = {
+ order = 2,
+ type = "range",
+ name = L["Per Row"],
+ min = 1, max = 20, step = 1,
+ },
+ numrows = {
+ order = 3,
+ type = "range",
+ name = L["Num Rows"],
+ min = 1, max = 10, step = 1
+ },
+ size = {
+ order = 4,
+ type = "range",
+ name = L["Icon Size"],
+ min = 6, max = 60, step = 1
+ },
+ spacing = {
+ order = 5,
+ type = "range",
+ name = L["Spacing"],
+ min = 0, max = 60, step = 1
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ anchorPoint = {
+ order = 8,
+ type = "select",
+ name = L["Anchor Point"],
+ desc = L["What point to anchor to the frame you set to attach to."],
+ values = positionValues
+ },
+ attachTo = {
+ order = 9,
+ type = "select",
+ name = L["Attach To"],
+ values = {
+ ["FRAME"] = L["Nameplate"]
+ }
+ },
+ growthX = {
+ order = 10,
+ type = "select",
+ name = L["Growth X-Direction"],
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"]
+ }
+ },
+ growthY = {
+ order = 11,
+ type = "select",
+ name = L["Growth Y-Direction"],
+ values = {
+ ["UP"] = L["Up"],
+ ["DOWN"] = L["Down"]
+ }
+ },
+ cooldownOrientation = {
+ order = 12,
+ type = "select",
+ name = L["Cooldown Orientation"],
+ values = {
+ ["VERTICAL"] = L["Vertical"],
+ ["HORIZONTAL"] = L["Horizontal"]
+ }
+ },
+ reverseCooldown = {
+ order = 13,
+ type = "toggle",
+ name = L["Reverse Cooldown"],
+ },
+ stacks = {
+ order = 14,
+ type = "group",
+ name = L["Stack Counter"],
+ guiInline = true,
+ get = function(info, value)
+ return E.db.nameplates.units[unit].buffs[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].buffs[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ countFont = {
+ order = 1,
+ type = "select",
+ name = L["Font"],
+ dialogControl = "LSM30_Font",
+ values = AceGUIWidgetLSMlists.font
+ },
+ countFontSize = {
+ order = 2,
+ name = L["FONT_SIZE"],
+ type = "range",
+ min = 4, max = 20, step = 1 -- max 20 cause otherwise it looks weird
+ },
+ countFontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ },
+ countPosition = {
+ order = 4,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOP"] = "TOP",
+ ["LEFT"] = "LEFT",
+ ["BOTTOM"] = "BOTTOM",
+ ["CENTER"] = "CENTER",
+ ["TOPLEFT"] = "TOPLEFT",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT",
+ ["RIGHT"] = "RIGHT",
+ ["TOPRIGHT"] = "TOPRIGHT"
+ }
+ },
+ countXOffset = {
+ order = 5,
+ name = L["X-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ },
+ countYOffset = {
+ order = 6,
+ name = L["Y-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ }
+ }
+ },
+ duration = {
+ order = 15,
+ type = "group",
+ name = L["Duration"],
+ guiInline = true,
+ get = function(info)
+ return E.db.nameplates.units[unit].buffs[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].buffs[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ durationFont = {
+ order = 1,
+ type = "select",
+ name = L["Font"],
+ dialogControl = "LSM30_Font",
+ values = AceGUIWidgetLSMlists.font
+ },
+ durationFontSize = {
+ order = 2,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 20, step = 1 -- max 20 cause otherwise it looks weird
+ },
+ durationFontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ },
+ durationPosition = {
+ order = 4,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOP"] = "TOP",
+ ["LEFT"] = "LEFT",
+ ["BOTTOM"] = "BOTTOM",
+ ["CENTER"] = "CENTER",
+ ["TOPLEFT"] = "TOPLEFT",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT",
+ ["RIGHT"] = "RIGHT",
+ ["TOPRIGHT"] = "TOPRIGHT"
+ }
+ },
+ durationXOffset = {
+ order = 5,
+ name = L["X-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ },
+ durationYOffset = {
+ order = 6,
+ name = L["Y-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ }
+ }
+ },
+ filtersGroup = {
+ order = 16,
+ name = L["FILTERS"],
+ type = "group",
+ guiInline = true,
+ get = function(info)
+ return E.db.nameplates.units[unit].buffs.filters[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].buffs.filters[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ minDuration = {
+ order = 1,
+ type = "range",
+ name = L["Minimum Duration"],
+ desc = L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."],
+ min = 0, max = 10800, step = 1
+ },
+ maxDuration = {
+ order = 2,
+ type = "range",
+ name = L["Maximum Duration"],
+ desc = L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."],
+ min = 0, max = 10800, step = 1
+ },
+ jumpToFilter = {
+ order = 3,
+ type = "execute",
+ name = L["Filters Page"],
+ desc = L["Shortcut to global filters."],
+ func = function()
+ ACD:SelectGroup("ElvUI", "filters")
+ end
+ },
+ spacer1 = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ specialFilters = {
+ order = 5,
+ type = "select",
+ sortByValue = true,
+ name = L["Add Special Filter"],
+ desc = L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."],
+ values = function()
+ local filters = {}
+ local list = E.global.nameplates.specialFilters
+ if not (list and next(list)) then return filters end
+
+ for filter in pairs(list) do
+ filters[filter] = L[filter]
+ end
+ return filters
+ end,
+ set = function(info, value)
+ filterPriority("buffs", unit, value)
+ NP:ConfigureAll()
+ end
+ },
+ filter = {
+ order = 6,
+ type = "select",
+ name = L["Add Regular Filter"],
+ desc = L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."],
+ values = function()
+ local filters = {}
+ local list = E.global.unitframe.aurafilters
+ if not (list and next(list)) then return filters end
+
+ for filter in pairs(list) do
+ filters[filter] = filter
+ end
+ return filters
+ end,
+ set = function(info, value)
+ filterPriority("buffs", unit, value)
+ NP:ConfigureAll()
+ end
+ },
+ resetPriority = {
+ order = 7,
+ type = "execute",
+ name = L["Reset Priority"],
+ desc = L["Reset filter priority to the default state."],
+ func = function()
+ E.db.nameplates.units[unit].buffs.filters.priority = P.nameplates.units[unit].buffs.filters.priority
+ NP:ConfigureAll()
+ end
+ },
+ filterPriority = {
+ order = 8,
+ type = "multiselect",
+ name = L["Filter Priority"],
+ dragdrop = true,
+ dragOnLeave = E.noop, --keep this here
+ dragOnEnter = function(info)
+ carryFilterTo = info.obj.value
+ end,
+ dragOnMouseDown = function(info)
+ carryFilterFrom, carryFilterTo = info.obj.value, nil
+ end,
+ dragOnMouseUp = function(info)
+ filterPriority("buffs", unit, carryFilterTo, nil, carryFilterFrom) --add it in the new spot
+ carryFilterFrom, carryFilterTo = nil, nil
+ end,
+ dragOnClick = function(info)
+ filterPriority("buffs", unit, carryFilterFrom, true)
+ end,
+ stateSwitchGetText = function(_, text)
+ local SF, localized = E.global.unitframe.specialFilters[text], L[text]
+ local blockText = SF and localized and text:match("^block") and localized:gsub("^%[.-]%s?", "")
+ return (blockText and format("|cFF999999%s|r %s", L["BLOCK"], blockText)) or localized or text
+ end,
+ stateSwitchOnClick = function()
+ filterPriority("buffs", unit, carryFilterFrom, nil, nil, true)
+ end,
+ values = function()
+ local str = E.db.nameplates.units[unit].buffs.filters.priority
+ if str == "" then return {} end
+ return {strsplit(",", str)}
+ end,
+ get = function(_, value)
+ local str = E.db.nameplates.units[unit].buffs.filters.priority
+ if str == "" then return end
+ local tbl = {strsplit(",", str)}
+ return tbl[value]
+ end,
+ set = function()
+ NP:ConfigureAll()
+ end
+ },
+ spacer3 = {
+ order = 9,
+ type = "description",
+ name = L["Use drag and drop to rearrange filter priority or right click to remove a filter."] ..
+ "\n" ..
+ L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."]
+ }
+ }
+ }
+ }
+ },
+ debuffsGroup = {
+ order = 4,
+ type = "group",
+ name = L["Debuffs"],
+ get = function(info)
+ return E.db.nameplates.units[unit].debuffs[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].debuffs[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Debuffs"]
+ },
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ perrow = {
+ order = 2,
+ type = "range",
+ name = L["Per Row"],
+ min = 1, max = 20, step = 1,
+ },
+ numrows = {
+ order = 3,
+ type = "range",
+ name = L["Num Rows"],
+ min = 1, max = 10, step = 1
+ },
+ size = {
+ order = 4,
+ type = "range",
+ name = L["Icon Size"],
+ min = 6, max = 60, step = 1
+ },
+ spacing = {
+ order = 5,
+ type = "range",
+ name = L["Spacing"],
+ min = 0, max = 60, step = 1
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ anchorPoint = {
+ order = 8,
+ type = "select",
+ name = L["Anchor Point"],
+ desc = L["What point to anchor to the frame you set to attach to."],
+ values = positionValues
+ },
+ attachTo = {
+ order = 9,
+ type = "select",
+ name = L["Attach To"],
+ values = {
+ ["FRAME"] = L["Nameplate"],
+ ["BUFFS"] = L["Buffs"],
+ }
+ },
+ growthX = {
+ order = 10,
+ type = "select",
+ name = L["Growth X-Direction"],
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"]
+ }
+ },
+ growthY = {
+ order = 11,
+ type = "select",
+ name = L["Growth Y-Direction"],
+ values = {
+ ["UP"] = L["Up"],
+ ["DOWN"] = L["Down"]
+ }
+ },
+ cooldownOrientation = {
+ order = 12,
+ type = "select",
+ name = L["Cooldown Orientation"],
+ values = {
+ ["VERTICAL"] = L["Vertical"],
+ ["HORIZONTAL"] = L["Horizontal"]
+ }
+ },
+ reverseCooldown = {
+ order = 13,
+ type = "toggle",
+ name = L["Reverse Cooldown"],
+ },
+ stacks = {
+ order = 14,
+ type = "group",
+ name = L["Stack Counter"],
+ guiInline = true,
+ get = function(info, value)
+ return E.db.nameplates.units[unit].debuffs[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].debuffs[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ countFont = {
+ order = 1,
+ type = "select",
+ name = L["Font"],
+ dialogControl = "LSM30_Font",
+ values = AceGUIWidgetLSMlists.font
+ },
+ countFontSize = {
+ order = 2,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 20, step = 1 -- max 20 cause otherwise it looks weird
+ },
+ countFontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ },
+ countPosition = {
+ order = 4,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOP"] = "TOP",
+ ["LEFT"] = "LEFT",
+ ["BOTTOM"] = "BOTTOM",
+ ["CENTER"] = "CENTER",
+ ["TOPLEFT"] = "TOPLEFT",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT",
+ ["RIGHT"] = "RIGHT",
+ ["TOPRIGHT"] = "TOPRIGHT"
+ }
+ },
+ countXOffset = {
+ order = 5,
+ name = L["X-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ },
+ countYOffset = {
+ order = 6,
+ name = L["Y-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ }
+ }
+ },
+ duration = {
+ order = 15,
+ type = "group",
+ name = L["Duration"],
+ guiInline = true,
+ get = function(info)
+ return E.db.nameplates.units[unit].debuffs[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].debuffs[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ durationFont = {
+ order = 1,
+ type = "select",
+ name = L["Font"],
+ dialogControl = "LSM30_Font",
+ values = AceGUIWidgetLSMlists.font
+ },
+ durationFontSize = {
+ order = 2,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 20, step = 1 -- max 20 cause otherwise it looks weird
+ },
+ durationFontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ },
+ durationPosition = {
+ order = 4,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOP"] = "TOP",
+ ["LEFT"] = "LEFT",
+ ["BOTTOM"] = "BOTTOM",
+ ["CENTER"] = "CENTER",
+ ["TOPLEFT"] = "TOPLEFT",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT",
+ ["RIGHT"] = "RIGHT",
+ ["TOPRIGHT"] = "TOPRIGHT"
+ }
+ },
+ durationXOffset = {
+ order = 5,
+ name = L["X-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ },
+ durationYOffset = {
+ order = 6,
+ name = L["Y-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ }
+ }
+ },
+ filtersGroup = {
+ order = 16,
+ type = "group",
+ name = L["FILTERS"],
+ get = function(info)
+ return E.db.nameplates.units[unit].debuffs.filters[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].debuffs.filters[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ guiInline = true,
+ args = {
+ minDuration = {
+ order = 1,
+ type = "range",
+ name = L["Minimum Duration"],
+ desc = L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."],
+ min = 0, max = 10800, step = 1
+ },
+ maxDuration = {
+ order = 2,
+ type = "range",
+ name = L["Maximum Duration"],
+ desc = L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."],
+ min = 0, max = 10800, step = 1
+ },
+ jumpToFilter = {
+ order = 3,
+ type = "execute",
+ name = L["Filters Page"],
+ desc = L["Shortcut to global filters."],
+ func = function()
+ ACD:SelectGroup("ElvUI", "filters")
+ end
+ },
+ spacer1 = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ specialFilters = {
+ order = 5,
+ type = "select",
+ sortByValue = true,
+ name = L["Add Special Filter"],
+ desc = L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."],
+ values = function()
+ local filters = {}
+ local list = E.global.nameplates.specialFilters
+ if not (list and next(list)) then return filters end
+
+ for filter in pairs(list) do
+ filters[filter] = L[filter]
+ end
+ return filters
+ end,
+ set = function(info, value)
+ filterPriority("debuffs", unit, value)
+ NP:ConfigureAll()
+ end
+ },
+ filter = {
+ order = 6,
+ type = "select",
+ name = L["Add Regular Filter"],
+ desc = L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."],
+ values = function()
+ local filters = {}
+ local list = E.global.unitframe.aurafilters
+ if not (list and next(list)) then return filters end
+
+ for filter in pairs(list) do
+ filters[filter] = filter
+ end
+ return filters
+ end,
+ set = function(info, value)
+ filterPriority("debuffs", unit, value)
+ NP:ConfigureAll()
+ end
+ },
+ resetPriority = {
+ order = 7,
+ type = "execute",
+ name = L["Reset Priority"],
+ desc = L["Reset filter priority to the default state."],
+ func = function()
+ E.db.nameplates.units[unit].debuffs.filters.priority = P.nameplates.units[unit].debuffs.filters.priority
+ NP:ConfigureAll()
+ end
+ },
+ filterPriority = {
+ order = 8,
+ type = "multiselect",
+ name = L["Filter Priority"],
+ dragdrop = true,
+ dragOnLeave = E.noop, --keep this here
+ dragOnEnter = function(info)
+ carryFilterTo = info.obj.value
+ end,
+ dragOnMouseDown = function(info)
+ carryFilterFrom, carryFilterTo = info.obj.value, nil
+ end,
+ dragOnMouseUp = function(info)
+ filterPriority("debuffs", unit, carryFilterTo, nil, carryFilterFrom) --add it in the new spot
+ carryFilterFrom, carryFilterTo = nil, nil
+ end,
+ dragOnClick = function(info)
+ filterPriority("debuffs", unit, carryFilterFrom, true)
+ end,
+ stateSwitchGetText = function(_, text)
+ local SF, localized = E.global.unitframe.specialFilters[text], L[text]
+ local blockText = SF and localized and text:match("^block") and localized:gsub("^%[.-]%s?", "")
+ return (blockText and format("|cFF999999%s|r %s", L["BLOCK"], blockText)) or localized or text
+ end,
+ stateSwitchOnClick = function(info)
+ filterPriority("debuffs", unit, carryFilterFrom, nil, nil, true)
+ end,
+ values = function()
+ local str = E.db.nameplates.units[unit].debuffs.filters.priority
+ if str == "" then return {} end
+ return {strsplit(",", str)}
+ end,
+ get = function(info, value)
+ local str = E.db.nameplates.units[unit].debuffs.filters.priority
+ if str == "" then return end
+ local tbl = {strsplit(",", str)}
+ return tbl[value]
+ end,
+ set = function(info)
+ NP:ConfigureAll()
+ end
+ },
+ spacer3 = {
+ order = 9,
+ type = "description",
+ name = L["Use drag and drop to rearrange filter priority or right click to remove a filter."] ..
+ "\n" ..
+ L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."]
+ }
+ }
+ }
+ }
+ },
+ levelGroup = {
+ order = 5,
+ name = L["LEVEL"],
+ type = "group",
+ get = function(info)
+ return E.db.nameplates.units[unit].level[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].level[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["LEVEL"]
+ },
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ fontGroup = {
+ type = "group",
+ order = 2,
+ name = L["Fonts"],
+ guiInline = true,
+ get = function(info)
+ return E.db.nameplates.units[unit].level[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].level[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ font = {
+ order = 1,
+ type = "select",
+ name = L["Font"],
+ dialogControl = "LSM30_Font",
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontSize = {
+ order = 2,
+ name = L["FONT_SIZE"],
+ type = "range",
+ min = 4, max = 32, step = 1
+ },
+ fontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ }
+ }
+ }
+ }
+ },
+ nameGroup = {
+ order = 6,
+ type = "group",
+ name = L["Name"],
+ get = function(info)
+ return E.db.nameplates.units[unit].name[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].name[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Name"]
+ },
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ abbrev = {
+ order = 2,
+ type = "toggle",
+ name = L["Abbreviation"]
+ },
+ fontGroup = {
+ type = "group",
+ order = 7,
+ name = L["Fonts"],
+ guiInline = true,
+ get = function(info)
+ return E.db.nameplates.units[unit].name[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].name[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ font = {
+ order = 1,
+ type = "select",
+ name = L["Font"],
+ dialogControl = "LSM30_Font",
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontSize = {
+ order = 2,
+ name = L["FONT_SIZE"],
+ type = "range",
+ min = 4, max = 32, step = 1
+ },
+ fontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ }
+ }
+ }
+ }
+ },
+ raidTargetIndicator = {
+ order = 7,
+ name = L["Raid Icon"],
+ type = "group",
+ get = function(info)
+ return E.db.nameplates.units[unit].raidTargetIndicator[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units[unit].raidTargetIndicator[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Raid Icon"]
+ },
+ size = {
+ order = 1,
+ type = "range",
+ name = L["Size"],
+ min = 12, max = 64, step = 1
+ },
+ position = {
+ order = 2,
+ type = "select",
+ name = L["Icon Position"],
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"],
+ ["TOP"] = L["Top"],
+ ["BOTTOM"] = L["Bottom"],
+ ["CENTER"] = L["Center"]
+ }
+ },
+ xOffset = {
+ order = 3,
+ name = L["X-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ },
+ yOffset = {
+ order = 4,
+ name = L["Y-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ }
+ }
+ }
+ }
+ }
+
+ if unit == "FRIENDLY_PLAYER" or unit == "ENEMY_PLAYER" then
+ if unit == "ENEMY_PLAYER" then
+ group.args.markHealers = {
+ order = 7,
+ type = "group",
+ name = L["Healer Icon"],
+ get = function(info) return E.db.nameplates.units.ENEMY_PLAYER[info[#info]] end,
+ set = function(info, value) E.db.nameplates.units.ENEMY_PLAYER[info[#info]] = value NP:PLAYER_ENTERING_WORLD() NP:ConfigureAll() end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Healer Icon"]
+ },
+ markHealers = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["Display a healer icon over known healers inside battlegrounds or arenas."]
+ }
+ }
+ }
+ end
+ group.args.healthGroup.args.useClassColor = {
+ order = 4.5,
+ type = "toggle",
+ name = L["Use Class Color"]
+ }
+ group.args.nameGroup.args.useClassColor = {
+ order = 3,
+ type = "toggle",
+ name = L["Use Class Color"]
+ }
+ elseif unit == "ENEMY_NPC" or unit == "FRIENDLY_NPC" then
+ group.args.eliteIcon = {
+ order = 7,
+ type = "group",
+ name = L["Elite Icon"],
+ get = function(info) return E.db.nameplates.units[unit].eliteIcon[info[#info]] end,
+ set = function(info, value) E.db.nameplates.units[unit].eliteIcon[info[#info]] = value NP:ConfigureAll() end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Elite Icon"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ position = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"],
+ ["TOP"] = L["Top"],
+ ["BOTTOM"] = L["Bottom"],
+ ["CENTER"] = L["Center"]
+ },
+ disabled = function() return not E.db.nameplates.units[unit].eliteIcon.enable end
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ size = {
+ order = 5,
+ type = "range",
+ name = L["Size"],
+ min = 12, max = 42, step = 1,
+ disabled = function() return not E.db.nameplates.units[unit].eliteIcon.enable end
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -100, max = 100, step = 1,
+ disabled = function() return not E.db.nameplates.units[unit].eliteIcon.enable end
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -100, max = 100, step = 1,
+ disabled = function() return not E.db.nameplates.units[unit].eliteIcon.enable end
+ }
+ }
+ }
+ group.args.iconFrame = {
+ order = 8,
+ type = "group",
+ name = L["Icon Frame"],
+ get = function(info) return E.db.nameplates.units[unit].iconFrame[info[#info]] end,
+ set = function(info, value) E.db.nameplates.units[unit].iconFrame[info[#info]] = value NP:ConfigureAll() end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Icon Frame"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ size = {
+ order = 3,
+ type = "range",
+ name = L["Size"],
+ min = 8, max = 48, step = 1,
+ },
+ position = {
+ order = 4,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["CENTER"] = "CENTER",
+ ["TOPLEFT"] = "TOPLEFT",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT",
+ ["BOTTOMRIGHT"] = "BOTTOMRIGHT"
+ }
+ },
+ parent = {
+ order = 5,
+ type = "select",
+ name = L["Parent"],
+ values = {
+ ["Nameplate"] = L["Nameplate"],
+ ["Health"] = L["Health"]
+ }
+ },
+ xOffset = {
+ order = 6,
+ name = L["X-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ },
+ yOffset = {
+ order = 7,
+ name = L["Y-Offset"],
+ type = "range",
+ min = -100, max = 100, step = 1
+ }
+ }
+ }
+ end
+
+ ORDER = ORDER + 2
+ return group
+end
+
+E.Options.args.nameplate = {
+ type = "group",
+ name = L["NamePlates"],
+ childGroups = "tree",
+ get = function(info) return E.db.nameplates[info[#info]] end,
+ set = function(info, value) E.db.nameplates[info[#info]] = value NP:ConfigureAll() end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.private.nameplates[info[#info]] end,
+ set = function(info, value) E.private.nameplates[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ intro = {
+ order = 2,
+ type = "description",
+ name = L["NAMEPLATE_DESC"]
+ },
+ header = {
+ order = 3,
+ type = "header",
+ name = L["Shortcuts"]
+ },
+ spacer1 = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ generalShortcut = {
+ order = 5,
+ type = "execute",
+ name = L["General"],
+ func = function() ACD:SelectGroup("ElvUI", "nameplate", "generalGroup", "general") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ fontsShortcut = {
+ order = 6,
+ type = "execute",
+ name = L["Fonts"],
+ func = function() ACD:SelectGroup("ElvUI", "nameplate", "generalGroup", "fontGroup") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ cooldownShortcut = {
+ order = 7,
+ type = "execute",
+ name = L["Cooldowns"],
+ func = function() ACD:SelectGroup("ElvUI", "cooldown", "nameplates") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ threatShortcut = {
+ order = 8,
+ type = "execute",
+ name = L["Threat"],
+ func = function() ACD:SelectGroup("ElvUI", "nameplate", "generalGroup", "threatGroup") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ spacer2 = {
+ order = 9,
+ type = "description",
+ name = " "
+ },
+ castBarShortcut = {
+ order = 10,
+ type = "execute",
+ name = L["Cast Bar"],
+ func = function() ACD:SelectGroup("ElvUI", "nameplate", "generalGroup", "castGroup") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ reactionShortcut = {
+ order = 12,
+ type = "execute",
+ name = L["Reaction Colors"],
+ func = function() ACD:SelectGroup("ElvUI", "nameplate", "generalGroup", "reactions") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ cutawayHealthShortcut = {
+ order = 13,
+ type = "execute",
+ name = L["Cutaway Bars"],
+ func = function() ACD:SelectGroup("ElvUI", "nameplate", "generalGroup", "cutawayHealth") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ spacer3 = {
+ order = 14,
+ type = "description",
+ name = " "
+ },
+ friendlyPlayerShortcut = {
+ order = 15,
+ type = "execute",
+ name = L["FRIENDLY_PLAYER"],
+ func = function() ACD:SelectGroup("ElvUI", "nameplate", "friendlyPlayerGroup") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ friendlyNPCShortcut = {
+ order = 16,
+ type = "execute",
+ name = L["FRIENDLY_NPC"],
+ func = function() ACD:SelectGroup("ElvUI", "nameplate", "friendlyNPCGroup") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ enemyPlayerShortcut = {
+ order = 17,
+ type = "execute",
+ name = L["ENEMY_PLAYER"],
+ func = function() ACD:SelectGroup("ElvUI", "nameplate", "enemyPlayerGroup") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ enemyNPCShortcut = {
+ order = 18,
+ type = "execute",
+ name = L["ENEMY_NPC"],
+ func = function() ACD:SelectGroup("ElvUI", "nameplate", "enemyNPCGroup") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ spacer4 = {
+ order = 19,
+ type = "description",
+ name = " "
+ },
+ filtersShortcut = {
+ order = 20,
+ type = "execute",
+ name = L["Style Filter"],
+ func = function() ACD:SelectGroup("ElvUI", "nameplate", "filters") end,
+ disabled = function() return not E.NamePlates.Initialized end
+ },
+ generalGroup = {
+ order = 21,
+ type = "group",
+ name = L["General Options"],
+ childGroups = "tab",
+ disabled = function() return not E.NamePlates.Initialized end,
+ args = {
+ general = {
+ order = 1,
+ type = "group",
+ name = L["General"],
+ get = function(info)
+ return E.db.nameplates[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ statusbar = {
+ order = 2,
+ type = "select",
+ dialogControl = "LSM30_Statusbar",
+ name = L["StatusBar Texture"],
+ values = AceGUIWidgetLSMlists.statusbar
+ },
+ motionType = {
+ order = 3,
+ type = "select",
+ name = L["UNIT_NAMEPLATES_TYPES"],
+ desc = L["Set to either stack nameplates vertically or allow them to overlap."],
+ values = {
+ ["STACKED"] = L["UNIT_NAMEPLATES_TYPE_2"],
+ ["OVERLAP"] = L["UNIT_NAMEPLATES_TYPE_1"]
+ }
+ },
+ lowHealthThreshold = {
+ order = 4,
+ name = L["Low Health Threshold"],
+ desc = L["Make the unitframe glow yellow when it is below this percent of health, it will glow red when the health value is half of this value."],
+ type = "range",
+ isPercent = true,
+ min = 0, max = 1, step = 0.01
+ },
+ showEnemyCombat = {
+ order = 5,
+ type = "select",
+ name = L["Enemy Combat Toggle"],
+ desc = L["Control enemy nameplates toggling on or off when in combat."],
+ values = {
+ ["DISABLED"] = L["DISABLE"],
+ ["TOGGLE_ON"] = L["Toggle On While In Combat"],
+ ["TOGGLE_OFF"] = L["Toggle Off While In Combat"]
+ },
+ set = function(info, value)
+ E.db.nameplates[info[#info]] = value
+ NP:PLAYER_REGEN_ENABLED()
+ end
+ },
+ showFriendlyCombat = {
+ order = 6,
+ type = "select",
+ name = L["Friendly Combat Toggle"],
+ desc = L["Control friendly nameplates toggling on or off when in combat."],
+ values = {
+ ["DISABLED"] = L["DISABLE"],
+ ["TOGGLE_ON"] = L["Toggle On While In Combat"],
+ ["TOGGLE_OFF"] = L["Toggle Off While In Combat"]
+ },
+ set = function(info, value)
+ E.db.nameplates[info[#info]] = value
+ NP:PLAYER_REGEN_ENABLED()
+ end
+ },
+ resetFilters = {
+ order = 7,
+ type = "execute",
+ name = L["Reset Aura Filters"],
+ func = function(info, value)
+ E:StaticPopup_Show("RESET_NP_AF") --reset nameplate aurafilters
+ end
+ },
+ fadeIn = {
+ order = 8,
+ type = "toggle",
+ name = L["Alpha Fading"]
+ },
+ smoothbars = {
+ order = 9,
+ type = "toggle",
+ name = L["Smooth Bars"],
+ desc = L["Bars will transition smoothly."],
+ set = function(info, value)
+ E.db.nameplates[info[#info]] = value
+ NP:ConfigureAll()
+ end
+ },
+ highlight = {
+ order = 10,
+ type = "toggle",
+ name = L["Hover Highlight"]
+ },
+ nameColoredGlow = {
+ order = 11,
+ type = "toggle",
+ name = L["Name Colored Glow"],
+ desc = L["Use the Name Color of the unit for the Name Glow."],
+ disabled = function() return not E.db.nameplates.highlight end
+ },
+ clickThrough = {
+ order = 51,
+ type = "group",
+ childGroups = "tabs",
+ name = L["Click Through"],
+ get = function(info)
+ return E.db.nameplates.clickThrough[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.clickThrough[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ friendly = {
+ order = 2,
+ type = "toggle",
+ name = L["Friendly"],
+ },
+ enemy = {
+ order = 3,
+ type = "toggle",
+ name = L["Enemy"]
+ }
+ }
+ },
+ clickableRange = {
+ order = 52,
+ type = "group",
+ childGroups = "tabs",
+ name = L["Clickable Size"],
+ args = {
+ friendly = {
+ order = 1,
+ type = "group",
+ guiInline = true,
+ name = L["Friendly"],
+ get = function(info)
+ return E.db.nameplates.plateSize[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.plateSize[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ friendlyWidth = {
+ order = 1,
+ type = "range",
+ name = L["Clickable Width / Width"],
+ desc = L["Change the width and controls how big of an area on the screen will accept clicks to target unit."],
+ min = 50,
+ max = 250,
+ step = 1
+ },
+ friendlyHeight = {
+ order = 2,
+ type = "range",
+ name = L["Clickable Height"],
+ desc = L["Controls how big of an area on the screen will accept clicks to target unit."],
+ min = 10,
+ max = 75,
+ step = 1
+ }
+ }
+ },
+ enemy = {
+ order = 2,
+ type = "group",
+ guiInline = true,
+ name = L["Enemy"],
+ get = function(info)
+ return E.db.nameplates.plateSize[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.plateSize[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ enemyWidth = {
+ order = 1,
+ type = "range",
+ name = L["Clickable Width / Width"],
+ desc = L["Change the width and controls how big of an area on the screen will accept clicks to target unit."],
+ min = 50,
+ max = 250,
+ step = 1
+ },
+ enemyHeight = {
+ order = 2,
+ type = "range",
+ name = L["Clickable Height"],
+ desc = L["Controls how big of an area on the screen will accept clicks to target unit."],
+ min = 10,
+ max = 75,
+ step = 1
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ colorsGroup = {
+ order = 2,
+ type = "group",
+ name = L["COLORS"],
+ args = {
+ general = {
+ order = 1,
+ type = "group",
+ name = L["General"],
+ guiInline = true,
+ get = function(info)
+ local t = E.db.nameplates.colors[info[#info]]
+ local d = P.nameplates.colors[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.db.nameplates.colors[info[#info]]
+ t.r, t.g, t.b, t.a = r, g, b, a
+ NP:ConfigureAll()
+ end,
+ args = {
+ glowColor = {
+ name = L["Target Indicator Color"],
+ type = "color",
+ order = 5,
+ hasAlpha = true
+ }
+ }
+ },
+ threat = {
+ order = 2,
+ type = "group",
+ name = L["Threat"],
+ guiInline = true,
+ get = function(info)
+ local t = E.db.nameplates.colors.threat[info[#info]]
+ local d = P.nameplates.colors.threat[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.db.nameplates.colors.threat[info[#info]]
+ t.r, t.g, t.b, t.a = r, g, b, a
+ NP:ConfigureAll()
+ end,
+ args = {
+ goodColor = {
+ type = "color",
+ order = 1,
+ name = L["Good Color"],
+ hasAlpha = false,
+ disabled = function()
+ return not E.db.nameplates.threat.useThreatColor
+ end
+ },
+ goodTransition = {
+ type = "color",
+ order = 2,
+ name = L["Good Transition Color"],
+ hasAlpha = false,
+ disabled = function()
+ return not E.db.nameplates.threat.useThreatColor
+ end
+ },
+ badTransition = {
+ name = L["Bad Transition Color"],
+ order = 3,
+ type = "color",
+ hasAlpha = false,
+ disabled = function()
+ return not E.db.nameplates.threat.useThreatColor
+ end
+ },
+ badColor = {
+ name = L["Bad Color"],
+ order = 4,
+ type = "color",
+ hasAlpha = false,
+ disabled = function()
+ return not E.db.nameplates.threat.useThreatColor
+ end
+ },
+ }
+ },
+ castGroup = {
+ order = 3,
+ type = "group",
+ name = L["Cast Bar"],
+ guiInline = true,
+ get = function(info)
+ local t = E.db.nameplates.colors[info[#info]]
+ local d = P.nameplates.colors[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.nameplates.colors[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ NP:ConfigureAll()
+ end,
+ args = {
+ castColor = {
+ order = 1,
+ type = "color",
+ name = L["Cast Color"],
+ hasAlpha = false
+ },
+ castNoInterruptColor = {
+ order = 2,
+ type = "color",
+ name = L["Cast No Interrupt Color"],
+ hasAlpha = false
+ },
+ castInterruptedColor = {
+ order = 3,
+ type = "color",
+ name = L["INTERRUPTED"],
+ hasAlpha = false
+ },
+ castbarDesaturate = {
+ order = 4,
+ type = "toggle",
+ name = L["Desaturated Icon"],
+ desc = L["Show the castbar icon desaturated if a spell is not interruptible."],
+ get = function(info)
+ return E.db.nameplates.colors[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.colors[info[#info]] = value
+ NP:ConfigureAll()
+ end
+ }
+ }
+ },
+ reactions = {
+ order = 4,
+ type = "group",
+ name = L["Reaction Colors"],
+ guiInline = true,
+ get = function(info)
+ local t = E.db.nameplates.colors.reactions[info[#info]]
+ local d = P.nameplates.colors.reactions[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.nameplates.colors.reactions[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ NP:ConfigureAll()
+ end,
+ args = {
+ friendlyPlayer = {
+ order = 1,
+ type = "color",
+ name = L["FRIENDLY_PLAYER"],
+ hasAlpha = false
+ },
+ bad = {
+ order = 2,
+ type = "color",
+ name = L["ENEMY"],
+ hasAlpha = false
+ },
+ neutral = {
+ order = 3,
+ type = "color",
+ name = L["Neutral"],
+ hasAlpha = false
+ },
+ good = {
+ order = 4,
+ type = "color",
+ name = L["FRIENDLY_NPC"],
+ hasAlpha = false
+ }
+ }
+ },
+ comboPoints = {
+ order = 5,
+ type = "group",
+ name = L["COMBO_POINTS"],
+ guiInline = true,
+ args = {}
+ },
+ }
+ },
+ threatGroup = {
+ order = 5,
+ type = "group",
+ name = L["Threat"],
+ get = function(info)
+ local t = E.db.nameplates.threat[info[#info]]
+ local d = P.nameplates.threat[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.nameplates.threat[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Threat"]
+ },
+ useThreatColor = {
+ order = 2,
+ type = "toggle",
+ name = L["Use Threat Color"],
+ get = function(info) return E.db.nameplates.threat.useThreatColor end,
+ set = function(info, value) E.db.nameplates.threat.useThreatColor = value end
+ },
+ goodScale = {
+ order = 3,
+ type = "range",
+ name = L["Good Scale"],
+ get = function(info) return E.db.nameplates.threat[info[#info]] end,
+ set = function(info, value) E.db.nameplates.threat[info[#info]] = value end,
+ min = 0.3, max = 2, step = 0.01,
+ isPercent = true
+ },
+ badScale = {
+ order = 4,
+ type = "range",
+ name = L["Bad Scale"],
+ get = function(info) return E.db.nameplates.threat[info[#info]] end,
+ set = function(info, value) E.db.nameplates.threat[info[#info]] = value end,
+ min = 0.3, max = 2, step = 0.01,
+ isPercent = true
+ },
+ }
+ },
+ cutawayHealth = {
+ order = 9,
+ type = "group",
+ name = L["Cutaway Bars"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Cutaway Bars"]
+ },
+ enabled = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.db.nameplates.cutawayHealth end,
+ set = function(info, value) E.db.nameplates.cutawayHealth = value end,
+ },
+ healthLength = {
+ order = 3,
+ type = "range",
+ name = L["Health Length"],
+ desc = L["How much time before the cutaway health starts to fade."],
+ min = 0.1, max = 1, step = 0.1,
+ get = function(info) return E.db.nameplates.cutawayHealthLength end,
+ set = function(info, value) E.db.nameplates.cutawayHealthLength = value end,
+ disabled = function() return not E.db.nameplates.cutawayHealth end
+ },
+ healthFadeOutTime = {
+ order = 4,
+ type = "range",
+ name = L["Fade Out"],
+ desc = L["How long the cutaway health will take to fade out."],
+ min = 0.1, max = 1, step = 0.1,
+ get = function(info) return E.db.nameplates.cutawayHealthFadeOutTime end,
+ set = function(info, value) E.db.nameplates.cutawayHealthFadeOutTime = value end,
+ disabled = function() return not E.db.nameplates.cutawayHealth end
+ }
+ }
+ }
+ }
+ },
+ friendlyPlayerGroup = GetUnitSettings("FRIENDLY_PLAYER", L["FRIENDLY_PLAYER"]),
+ friendlyNPCGroup = GetUnitSettings("FRIENDLY_NPC", L["FRIENDLY_NPC"]),
+ enemyPlayerGroup = GetUnitSettings("ENEMY_PLAYER", L["ENEMY_PLAYER"]),
+ enemyNPCGroup = GetUnitSettings("ENEMY_NPC", L["ENEMY_NPC"]),
+ targetGroup = {
+ order = 200,
+ type = "group",
+ name = L["TARGET"],
+ get = function(info)
+ return E.db.nameplates.units.TARGET[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units.TARGET[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ disabled = function()
+ return not E.NamePlates.Initialized
+ end,
+ args = {
+ useTargetScale = {
+ order = 1,
+ type = "toggle",
+ name = L["Use Target Scale"],
+ desc = L["Enable/Disable the scaling of targetted nameplates."],
+ get = function(info) return E.db.nameplates.useTargetScale end,
+ set = function(info, value)
+ E.db.nameplates.useTargetScale = value
+ NP:ConfigureAll()
+ end
+ },
+ targetScale = {
+ order = 2,
+ type = "range",
+ isPercent = true,
+ name = L["Target Scale"],
+ desc = L["Scale of the nameplate that is targetted."],
+ min = 0.3, max = 2, step = 0.01,
+ get = function(info) return E.db.nameplates.targetScale end,
+ set = function(info, value)
+ E.db.nameplates.targetScale = value
+ NP:ConfigureAll()
+ end,
+ disabled = function() return E.db.nameplates.useTargetScale ~= true end
+ },
+ nonTargetTransparency = {
+ order = 3,
+ type = "range",
+ isPercent = true,
+ name = L["Non-Target Alpha"],
+ min = 0, max = 1, step = 0.01,
+ get = function(info) return E.db.nameplates.nonTargetTransparency end,
+ set = function(info, value)
+ E.db.nameplates.nonTargetTransparency = value
+ NP:ConfigureAll()
+ end
+ },
+ spacer1 = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ glowStyle = {
+ order = 5,
+ type = "select",
+ name = L["Target/Low Health Indicator"],
+ customWidth = 225,
+ values = {
+ ["none"] = L["NONE"],
+ ["style1"] = L["Border Glow"],
+ ["style2"] = L["Background Glow"],
+ ["style3"] = L["Top Arrow"],
+ ["style4"] = L["Side Arrows"],
+ ["style5"] = L["Border Glow"].." + "..L["Top Arrow"],
+ ["style6"] = L["Background Glow"].." + "..L["Top Arrow"],
+ ["style7"] = L["Border Glow"].." + "..L["Side Arrows"],
+ ["style8"] = L["Background Glow"].." + "..L["Side Arrows"]
+ }
+ },
+ alwaysShowTargetHealth = {
+ order = 7,
+ type = "toggle",
+ name = L["Always Show Target Health"],
+ get = function(info) return E.db.nameplates.alwaysShowTargetHealth end,
+ set = function(info, value)
+ E.db.nameplates.alwaysShowTargetHealth = value
+ NP:ConfigureAll()
+ end,
+ customWidth = 200
+ },
+ comboPointsGroup = {
+ order = 8,
+ type = "group",
+ name = L["COMBO_POINTS"],
+ guiInline = true,
+ get = function(info)
+ return E.db.nameplates.units.TARGET.comboPoints[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.nameplates.units.TARGET.comboPoints[info[#info]] = value
+ NP:ConfigureAll()
+ end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ width = {
+ order = 2,
+ type = "range",
+ name = L["Width"],
+ min = 4, max = 30, step = 1,
+ disabled = function() return not E.db.nameplates.units.TARGET.comboPoints.enable end
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 4, max = 30, step = 1,
+ disabled = function() return not E.db.nameplates.units.TARGET.comboPoints.enable end
+ },
+ spacing = {
+ order = 4,
+ type = "range",
+ name = L["Spacing"],
+ min = 3, max = 20, step = 1,
+ disabled = function() return not E.db.nameplates.units.TARGET.comboPoints.enable end
+ },
+ xOffset = {
+ order = 5,
+ type = "range",
+ name = L["X-Offset"],
+ min = -100, max = 100, step = 1,
+ disabled = function() return not E.db.nameplates.units.TARGET.comboPoints.enable end
+ },
+ yOffset = {
+ order = 6,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -100, max = 100, step = 1,
+ disabled = function() return not E.db.nameplates.units.TARGET.comboPoints.enable end
+ }
+ }
+ }
+ }
+ },
+ filters = {
+ order = -99,
+ type = "group",
+ name = L["Style Filter"],
+ childGroups = "tab",
+ disabled = function() return not E.NamePlates.Initialized end,
+ args = {
+ addFilter = {
+ order = 1,
+ type = "input",
+ name = L["Create Filter"],
+ get = function(info) return "" end,
+ set = function(info, value)
+ if match(value, "^[%s%p]-$") then
+ return
+ end
+ if E.global.nameplates.filters[value] then
+ E:Print(L["Filter already exists!"])
+ return
+ end
+ local filter = {}
+ NP:StyleFilterCopyDefaults(filter)
+ E.global.nameplates.filters[value] = filter
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end
+ },
+ selectFilter = {
+ order = 2,
+ type = "select",
+ sortByValue = true,
+ name = L["Select Filter"],
+ get = function(info) return selectedNameplateFilter end,
+ set = function(info, value) selectedNameplateFilter = value UpdateFilterGroup() end,
+ values = function()
+ local filters, priority, name = {}
+ local list = E.global.nameplates.filters
+ local profile = E.db.nameplates.filters
+ if not list then return end
+ for filter, content in pairs(list) do
+ priority = (content.triggers and content.triggers.priority) or "?"
+ name = (content.triggers and profile[filter] and profile[filter].triggers and profile[filter].triggers.enable and filter) or (content.triggers and format("|cFF666666%s|r", filter)) or filter
+ filters[filter] = format("|cFFffff00(%s)|r %s", priority, name)
+ end
+ return filters
+ end
+ },
+ removeFilter = {
+ order = 3,
+ type = "execute",
+ name = L["Delete Filter"],
+ desc = L["Delete a created filter, you cannot delete pre-existing filters, only custom ones."],
+ func = function()
+ for profile in pairs(E.data.profiles) do
+ if E.data.profiles[profile].nameplates and E.data.profiles[profile].nameplates.filters and E.data.profiles[profile].nameplates.filters[selectedNameplateFilter] then
+ E.data.profiles[profile].nameplates.filters[selectedNameplateFilter] = nil
+ end
+ end
+ E.global.nameplates.filters[selectedNameplateFilter] = nil
+ selectedNameplateFilter = nil
+ UpdateFilterGroup()
+ NP:ConfigureAll()
+ end,
+ disabled = function() return G.nameplates.filters[selectedNameplateFilter] end,
+ hidden = function() return selectedNameplateFilter == nil end
+ }
+ }
+ }
+ }
+}
+
+for i = 1, 5 do
+ E.Options.args.nameplate.args.generalGroup.args.colorsGroup.args.comboPoints.args["COMBO_POINTS" .. i] = {
+ type = "color",
+ order = i,
+ name = L["COMBO_POINTS"] .. " #" .. i,
+ get = function(info)
+ local t = E.db.nameplates.colors.comboPoints[i]
+ local d = P.nameplates.colors.comboPoints[i]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.nameplates.colors.comboPoints[i]
+ t.r, t.g, t.b = r, g, b
+ NP:ConfigureAll()
+ end
+ }
+end
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Skins.lua b/ElvUI_OptionsUI/Skins.lua
new file mode 100644
index 0000000..0e80bfb
--- /dev/null
+++ b/ElvUI_OptionsUI/Skins.lua
@@ -0,0 +1,309 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local _, L = unpack(select(2, ...))
+
+E.Options.args.skins = {
+ type = "group",
+ name = L["Skins"],
+ childGroups = "tree",
+ args = {
+ intro = {
+ order = 1,
+ type = "description",
+ name = L["SKINS_DESC"]
+ },
+ blizzardEnable = {
+ order = 2,
+ type = "toggle",
+ name = L["Blizzard"],
+ get = function(info) return E.private.skins.blizzard.enable end,
+ set = function(info, value) E.private.skins.blizzard.enable = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ ace3 = {
+ order = 3,
+ type = "toggle",
+ name = "Ace3",
+ get = function(info) return E.private.skins.ace3.enable end,
+ set = function(info, value) E.private.skins.ace3.enable = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ checkBoxSkin = {
+ order = 4,
+ type = "toggle",
+ name = L["CheckBox Skin"],
+ get = function(info) return E.private.skins.checkBoxSkin end,
+ set = function(info, value) E.private.skins.checkBoxSkin = value E:StaticPopup_Show("PRIVATE_RL") end,
+ disabled = function() return not E.private.skins.ace3.enable and not E.private.skins.blizzard.enable end
+ },
+ dropdownCheckBoxSkin = {
+ order = 5,
+ type = "toggle",
+ name = L["Dropdown CheckBox Skin"],
+ get = function(info) return E.private.skins.dropdownCheckBoxSkin end,
+ set = function(info, value) E.private.skins.dropdownCheckBoxSkin = value E:StaticPopup_Show("PRIVATE_RL") end,
+ disabled = function() return not E.private.skins.ace3.enable and not E.private.skins.blizzard.enable end
+ },
+ blizzard = {
+ order = 100,
+ type = "group",
+ name = "Blizzard",
+ get = function(info) return E.private.skins.blizzard[info[#info]] end,
+ set = function(info, value) E.private.skins.blizzard[info[#info]] = value E:StaticPopup_Show("CONFIG_RL") end,
+ disabled = function() return not E.private.skins.blizzard.enable end,
+ guiInline = true,
+ args = {
+ achievement = {
+ type = "toggle",
+ name = L["ACHIEVEMENTS"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ alertframes = {
+ type = "toggle",
+ name = L["Alert Frames"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ arena = {
+ type = "toggle",
+ name = L["Arena Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ arenaregistrar = {
+ type = "toggle",
+ name = L["Arena Registrar"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ auctionhouse = {
+ type = "toggle",
+ name = L["AUCTIONS"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ bags = {
+ type = "toggle",
+ name = L["Bags"],
+ desc = L["TOGGLESKIN_DESC"],
+ disabled = function() return E.private.bags.enable end
+ },
+ barber = {
+ type = "toggle",
+ name = L["BARBERSHOP"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ bgmap = {
+ type = "toggle",
+ name = L["BG Map"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ bgscore = {
+ type = "toggle",
+ name = L["BG Score"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ binding = {
+ type = "toggle",
+ name = L["KEY_BINDINGS"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ BlizzardOptions = {
+ type = "toggle",
+ name = L["INTERFACE_OPTIONS"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ calendar = {
+ type = "toggle",
+ name = L["Calendar Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ character = {
+ type = "toggle",
+ name = L["Character Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ debug = {
+ type = "toggle",
+ name = L["Debug Tools"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ dressingroom = {
+ type = "toggle",
+ name = L["DRESSUP_FRAME"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ friends = {
+ type = "toggle",
+ name = L["FRIENDS"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ gbank = {
+ type = "toggle",
+ name = L["GUILD_BANK"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ gossip = {
+ type = "toggle",
+ name = L["Gossip Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ gmchat = {
+ type = "toggle",
+ name = L["GM Chat"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ guildregistrar = {
+ type = "toggle",
+ name = L["Guild Registrar"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ help = {
+ type = "toggle",
+ name = L["Help Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ inspect = {
+ type = "toggle",
+ name = L["INSPECT"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ lfd = {
+ type = "toggle",
+ name = L["LFD Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ lfr = {
+ type = "toggle",
+ name = L["LFR Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ loot = {
+ type = "toggle",
+ name = L["Loot Frames"],
+ desc = L["TOGGLESKIN_DESC"],
+ disabled = function() return E.private.general.loot end
+ },
+ lootRoll = {
+ type = "toggle",
+ name = L["Loot Roll"],
+ desc = L["TOGGLESKIN_DESC"],
+ disabled = function() return E.private.general.lootRoll end
+ },
+ macro = {
+ type = "toggle",
+ name = L["MACROS"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ mail = {
+ type = "toggle",
+ name = L["MAIL_LABEL"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ merchant = {
+ type = "toggle",
+ name = L["MERCHANT"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ misc = {
+ type = "toggle",
+ name = L["Misc Frames"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ mirrorTimers = {
+ type = "toggle",
+ name = L["Mirror Timers"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ petition = {
+ type = "toggle",
+ name = L["Petition Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ pvp = {
+ type = "toggle",
+ name = L["PvP Frames"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ quest = {
+ type = "toggle",
+ name = L["Quest Frames"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ raid = {
+ type = "toggle",
+ name = L["Raid Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ socket = {
+ type = "toggle",
+ name = L["Socket Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ spellbook = {
+ type = "toggle",
+ name = L["SPELLBOOK"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ stable = {
+ type = "toggle",
+ name = L["Stable"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ tabard = {
+ type = "toggle",
+ name = L["Tabard Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ talent = {
+ type = "toggle",
+ name = L["TALENTS"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ taxi = {
+ type = "toggle",
+ name = L["FLIGHT_MAP"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ timemanager = {
+ type = "toggle",
+ name = L["TIMEMANAGER_TITLE"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ tooltip = {
+ type = "toggle",
+ name = L["Tooltip"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ trade = {
+ type = "toggle",
+ name = L["TRADE"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ tradeskill = {
+ type = "toggle",
+ name = L["TRADESKILLS"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ trainer = {
+ type = "toggle",
+ name = L["Trainer Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ tutorial = {
+ type = "toggle",
+ name = L["Tutorial Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ watchframe = {
+ type = "toggle",
+ name = L["Watch Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ worldmap = {
+ type = "toggle",
+ name = L["WORLD_MAP"],
+ desc = L["TOGGLESKIN_DESC"]
+ },
+ WorldStateFrame = {
+ type = "toggle",
+ name = L["World State Frame"],
+ desc = L["TOGGLESKIN_DESC"]
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Tags.lua b/ElvUI_OptionsUI/Tags.lua
new file mode 100644
index 0000000..147e51b
--- /dev/null
+++ b/ElvUI_OptionsUI/Tags.lua
@@ -0,0 +1,72 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local _, L = unpack(select(2, ...))
+
+local format = format
+
+E.Options.args.tagGroup = {
+ order = 925,
+ type = "group",
+ name = L["Available Tags"],
+ childGroups = "tab",
+ args = {
+ link = {
+ order = 1,
+ type = "input",
+ width = "full",
+ name = L["Guide:"],
+ get = function() return "https://www.tukui.org/forum/viewtopic.php?f=9&t=6" end,
+ },
+ header = {
+ order = 2,
+ type = "header",
+ name = L["Available Tags"],
+ },
+ Colors = {
+ type = "group",
+ name = "Colors",
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = E.InfoColor.."Colors",
+ },
+ customTagColorInfo = {
+ order = 1,
+ type = "input",
+ width = "full",
+ name = "Custom color your Text: replace the XXXXXX with a Hex color code",
+ get = function() return "||cffXXXXXX [tags] or text here ||r" end
+ }
+ }
+ },
+ },
+}
+
+for Tag in next, E.oUF.Tags.Methods do
+ if not E.TagInfo[Tag] then
+ E.TagInfo[Tag] = {category = "Miscellaneous", description = ""}
+ --E:Print("['"..Tag.."'] = { category = 'Miscellaneous', description = '' }")
+ end
+
+ if not E.Options.args.tagGroup.args[E.TagInfo[Tag].category] then
+ E.Options.args.tagGroup.args[E.TagInfo[Tag].category] = {
+ type = "group",
+ name = E.TagInfo[Tag].category,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = E.InfoColor..E.TagInfo[Tag].category,
+ }
+ }
+ }
+ end
+
+ E.Options.args.tagGroup.args[E.TagInfo[Tag].category].args[Tag] = {
+ type = "input",
+ name = E.TagInfo[Tag].description,
+ order = E.TagInfo[Tag].order or nil,
+ width = "full",
+ get = function() return format("[%s]", Tag) end,
+ }
+end
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/Tooltip.lua b/ElvUI_OptionsUI/Tooltip.lua
new file mode 100644
index 0000000..c88be9c
--- /dev/null
+++ b/ElvUI_OptionsUI/Tooltip.lua
@@ -0,0 +1,367 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+local TT = E:GetModule("Tooltip")
+
+local tonumber = tonumber
+
+local GameTooltipStatusBar = GameTooltipStatusBar
+
+E.Options.args.tooltip = {
+ type = "group",
+ name = L["Tooltip"],
+ childGroups = "tab",
+ get = function(info) return E.db.tooltip[info[#info]] end,
+ set = function(info, value) E.db.tooltip[info[#info]] = value end,
+ args = {
+ intro = {
+ order = 1,
+ type = "description",
+ name = L["TOOLTIP_DESC"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.private.tooltip[info[#info]] end,
+ set = function(info, value) E.private.tooltip[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ general = {
+ order = 3,
+ type = "group",
+ name = L["General"],
+ disabled = function() return not E.Tooltip.Initialized end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ cursorAnchor = {
+ order = 2,
+ type = "toggle",
+ name = L["Cursor Anchor"],
+ desc = L["Should tooltip be anchored to mouse cursor"]
+ },
+ cursorAnchorType = {
+ order = 3,
+ type = "select",
+ name = L["Cursor Anchor Type"],
+ values = {
+ ["ANCHOR_CURSOR"] = L["ANCHOR_CURSOR"],
+ ["ANCHOR_CURSOR_LEFT"] = L["ANCHOR_CURSOR_LEFT"],
+ ["ANCHOR_CURSOR_RIGHT"] = L["ANCHOR_CURSOR_RIGHT"],
+ },
+ disabled = function() return (not E.db.tooltip.cursorAnchor) end
+ },
+ cursorAnchorX = {
+ order = 4,
+ type = "range",
+ name = L["Cursor Anchor Offset X"],
+ min = -128, max = 128, step = 1,
+ disabled = function() return (not E.db.tooltip.cursorAnchor) or (E.db.tooltip.cursorAnchorType == "ANCHOR_CURSOR") end
+ },
+ cursorAnchorY = {
+ order = 5,
+ type = "range",
+ name = L["Cursor Anchor Offset Y"],
+ min = -128, max = 128, step = 1,
+ disabled = function() return (not E.db.tooltip.cursorAnchor) or (E.db.tooltip.cursorAnchorType == "ANCHOR_CURSOR") end
+ },
+ targetInfo = {
+ order = 6,
+ type = "toggle",
+ name = L["Target Info"],
+ desc = L["When in a raid group display if anyone in your raid is targeting the current tooltip unit."]
+ },
+ alwaysShowRealm = {
+ order = 7,
+ type = "toggle",
+ name = L["Always Show Realm"],
+ },
+ playerTitles = {
+ order = 8,
+ type = "toggle",
+ name = L["Player Titles"],
+ desc = L["Display player titles."]
+ },
+ guildRanks = {
+ order = 9,
+ type = "toggle",
+ name = L["Guild Ranks"],
+ desc = L["Display guild ranks if a unit is guilded."]
+ },
+ spellID = {
+ order = 10,
+ type = "toggle",
+ name = L["Spell/Item IDs"],
+ desc = L["Display the spell or item ID when mousing over a spell or item tooltip."]
+ },
+ npcID = {
+ order = 11,
+ type = "toggle",
+ name = L["NPC IDs"],
+ desc = L["Display the npc ID when mousing over a npc tooltip."],
+ },
+ itemCount = {
+ order = 12,
+ type = "select",
+ name = L["Item Count"],
+ desc = L["Display how many of a certain item you have in your possession."],
+ values = {
+ ["BAGS_ONLY"] = L["Bags Only"],
+ ["BANK_ONLY"] = L["Bank Only"],
+ ["BOTH"] = L["Both"],
+ ["NONE"] = L["NONE"]
+ }
+ },
+ colorAlpha = {
+ order = 13,
+ type = "range",
+ name = L["OPACITY"],
+ isPercent = true,
+ min = 0, max = 1, step = 0.01,
+ },
+ fontGroup = {
+ order = 14,
+ type = "group",
+ guiInline = true,
+ name = L["Tooltip Font Settings"],
+ args = {
+ font = {
+ order = 1,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font,
+ get = function(info) return E.db.tooltip.font end,
+ set = function(info, value) E.db.tooltip.font = value TT:SetTooltipFonts() end
+ },
+ fontOutline = {
+ order = 2,
+ type = "select",
+ name = L["Font Outline"],
+ values = C.Values.FontFlags,
+ get = function(info) return E.db.tooltip.fontOutline end,
+ set = function(info, value) E.db.tooltip.fontOutline = value TT:SetTooltipFonts() end
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ headerFontSize = {
+ order = 4,
+ type = "range",
+ name = L["Header Font Size"],
+ min = 4, max = 50, step = 1,
+ get = function(info) return E.db.tooltip.headerFontSize end,
+ set = function(info, value) E.db.tooltip.headerFontSize = value TT:SetTooltipFonts() end
+ },
+ textFontSize = {
+ order = 5,
+ type = "range",
+ name = L["Text Font Size"],
+ min = 4, max = 33, step = 1,
+ get = function(info) return E.db.tooltip.textFontSize end,
+ set = function(info, value) E.db.tooltip.textFontSize = value TT:SetTooltipFonts() end
+ },
+ smallTextFontSize = {
+ order = 6,
+ type = "range",
+ name = L["Comparison Font Size"],
+ desc = L["This setting controls the size of text in item comparison tooltips."],
+ min = 4, max = 33, step = 1,
+ get = function(info) return E.db.tooltip.smallTextFontSize end,
+ set = function(info, value) E.db.tooltip.smallTextFontSize = value TT:SetTooltipFonts() end
+ }
+ }
+ },
+ factionColors = {
+ order = 15,
+ type = "group",
+ name = L["Custom Faction Colors"],
+ guiInline = true,
+ args = {
+ useCustomFactionColors = {
+ order = 1,
+ type = "toggle",
+ name = L["Custom Faction Colors"],
+ get = function(info) return E.db.tooltip.useCustomFactionColors end,
+ set = function(info, value) E.db.tooltip.useCustomFactionColors = value end
+ }
+ },
+ get = function(info)
+ local v = tonumber(info[#info])
+ local t = E.db.tooltip.factionColors[v]
+ local d = P.tooltip.factionColors[v]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local v = tonumber(info[#info])
+ local t = E.db.tooltip.factionColors[v]
+ t.r, t.g, t.b = r, g, b
+ end
+ }
+ }
+ },
+ visibility = {
+ order = 4,
+ type = "group",
+ name = L["Visibility"],
+ get = function(info) return E.db.tooltip.visibility[info[#info]] end,
+ set = function(info, value) E.db.tooltip.visibility[info[#info]] = value end,
+ disabled = function() return not E.Tooltip.Initialized end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Visibility"]
+ },
+ actionbars = {
+ order = 2,
+ type = "select",
+ name = L["ActionBars"],
+ desc = L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."],
+ values = {
+ ["ALL"] = L["Always Hide"],
+ ["NONE"] = L["Never Hide"],
+ ["SHIFT"] = L["SHIFT_KEY"],
+ ["ALT"] = L["ALT_KEY_TEXT"],
+ ["CTRL"] = L["CTRL_KEY"]
+ }
+ },
+ bags = {
+ order = 3,
+ type = "select",
+ name = L["Bags/Bank"],
+ desc = L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."],
+ values = {
+ ["ALL"] = L["Always Hide"],
+ ["NONE"] = L["Never Hide"],
+ ["SHIFT"] = L["SHIFT_KEY"],
+ ["ALT"] = L["ALT_KEY_TEXT"],
+ ["CTRL"] = L["CTRL_KEY"]
+ }
+ },
+ unitFrames = {
+ order = 4,
+ type = "select",
+ name = L["UnitFrames"],
+ desc = L["Choose when you want the tooltip to show. If a modifer is chosen, then you need to hold that down to show the tooltip."],
+ values = {
+ ["ALL"] = L["Always Hide"],
+ ["NONE"] = L["Never Hide"],
+ ["SHIFT"] = L["SHIFT_KEY"],
+ ["ALT"] = L["ALT_KEY_TEXT"],
+ ["CTRL"] = L["CTRL_KEY"]
+ }
+ },
+ combat = {
+ order = 5,
+ type = "toggle",
+ name = L["Hide In Combat"],
+ desc = L["Hide tooltip while in combat."]
+ },
+ combatOverride = {
+ order = 6,
+ type = "select",
+ name = L["Combat Override Key"],
+ desc = L["Choose when you want the tooltip to show in combat. If a modifer is chosen, then you need to hold that down to show the tooltip."],
+ disabled = function() return not E.db.tooltip.visibility.combat end,
+ values = {
+ ["ALL"] = L["Always Hide"],
+ ["SHIFT"] = L["SHIFT_KEY"],
+ ["ALT"] = L["ALT_KEY_TEXT"],
+ ["CTRL"] = L["CTRL_KEY"]
+ }
+ }
+ }
+ },
+ healthBar = {
+ order = 5,
+ type = "group",
+ name = L["Health Bar"],
+ get = function(info) return E.db.tooltip.healthBar[info[#info]] end,
+ set = function(info, value) E.db.tooltip.healthBar[info[#info]] = value end,
+ disabled = function() return not E.Tooltip.Initialized end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Health Bar"]
+ },
+ height = {
+ order = 2,
+ type = "range",
+ name = L["Height"],
+ min = 1, max = 15, step = 1,
+ set = function(info, value) E.db.tooltip.healthBar.height = value GameTooltipStatusBar:Height(value) end
+ },
+ statusPosition = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["BOTTOM"] = L["Bottom"],
+ ["TOP"] = L["Top"]
+ }
+ },
+ text = {
+ order = 4,
+ type = "toggle",
+ name = L["Text"],
+ set = function(info, value)
+ E.db.tooltip.healthBar.text = value
+ if value then
+ GameTooltipStatusBar.text:Show()
+ else
+ GameTooltipStatusBar.text:Hide()
+ end
+ end
+ },
+ font = {
+ order = 5,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font,
+ set = function(info, value)
+ E.db.tooltip.healthBar.font = value
+ GameTooltipStatusBar.text:FontTemplate(E.Libs.LSM:Fetch("font", E.db.tooltip.healthBar.font), E.db.tooltip.healthBar.fontSize, E.db.tooltip.healthBar.fontOutline)
+ end,
+ disabled = function() return not E.db.tooltip.healthBar.text end
+ },
+ fontSize = {
+ order = 6,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 33, step = 1,
+ set = function(info, value)
+ E.db.tooltip.healthBar.fontSize = value
+ GameTooltipStatusBar.text:FontTemplate(E.Libs.LSM:Fetch("font", E.db.tooltip.healthBar.font), E.db.tooltip.healthBar.fontSize, E.db.tooltip.healthBar.fontOutline)
+ end,
+ disabled = function() return not E.db.tooltip.healthBar.text end
+ },
+ fontOutline = {
+ order = 7,
+ type = "select",
+ name = L["Font Outline"],
+ values = C.Values.FontFlags,
+ set = function(info, value)
+ E.db.tooltip.healthBar.fontOutline = value
+ GameTooltipStatusBar.text:FontTemplate(E.Libs.LSM:Fetch("font", E.db.tooltip.healthBar.font), E.db.tooltip.healthBar.fontSize, E.db.tooltip.healthBar.fontOutline)
+ end,
+ disabled = function() return not E.db.tooltip.healthBar.text end
+ }
+ }
+ }
+ }
+}
+
+for i = 1, 8 do
+ E.Options.args.tooltip.args.general.args.factionColors.args[""..i] = {
+ order = i,
+ type = "color",
+ hasAlpha = false,
+ name = L["FACTION_STANDING_LABEL"..i],
+ disabled = function() return not E.Tooltip.Initialized or not E.db.tooltip.useCustomFactionColors end,
+ }
+end
\ No newline at end of file
diff --git a/ElvUI_OptionsUI/UnitFrames.lua b/ElvUI_OptionsUI/UnitFrames.lua
new file mode 100644
index 0000000..5c2d6b2
--- /dev/null
+++ b/ElvUI_OptionsUI/UnitFrames.lua
@@ -0,0 +1,8276 @@
+local E, _, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
+local C, L = unpack(select(2, ...))
+local UF = E:GetModule("UnitFrames")
+
+local _G = _G
+local select, pairs, ipairs = select, pairs, ipairs
+local tremove, tinsert, tconcat, twipe = table.remove, table.insert, table.concat, table.wipe
+local format, strmatch, gsub, strsplit = string.format, strmatch, string.gsub, strsplit
+
+local GetScreenWidth = GetScreenWidth
+local IsAddOnLoaded = IsAddOnLoaded
+
+local ACD = E.Libs.AceConfigDialog
+
+local positionValues = {
+ TOPLEFT = "TOPLEFT",
+ LEFT = "LEFT",
+ BOTTOMLEFT = "BOTTOMLEFT",
+ RIGHT = "RIGHT",
+ TOPRIGHT = "TOPRIGHT",
+ BOTTOMRIGHT = "BOTTOMRIGHT",
+ CENTER = "CENTER",
+ TOP = "TOP",
+ BOTTOM = "BOTTOM"
+}
+
+local orientationValues = {
+ --["AUTOMATIC"] = L["Automatic"], not sure if i will use this yet
+ ["LEFT"] = L["Left"],
+ ["MIDDLE"] = L["Middle"],
+ ["RIGHT"] = L["Right"]
+}
+
+local threatValues = {
+ ["GLOW"] = L["Glow"],
+ ["BORDERS"] = L["Borders"],
+ ["HEALTHBORDER"] = L["Health Border"],
+ ["INFOPANELBORDER"] = L["InfoPanel Border"],
+ ["ICONTOPLEFT"] = L["Icon: TOPLEFT"],
+ ["ICONTOPRIGHT"] = L["Icon: TOPRIGHT"],
+ ["ICONBOTTOMLEFT"] = L["Icon: BOTTOMLEFT"],
+ ["ICONBOTTOMRIGHT"] = L["Icon: BOTTOMRIGHT"],
+ ["ICONLEFT"] = L["Icon: LEFT"],
+ ["ICONRIGHT"] = L["Icon: RIGHT"],
+ ["ICONTOP"] = L["Icon: TOP"],
+ ["ICONBOTTOM"] = L["Icon: BOTTOM"],
+ ["NONE"] = L["NONE"]
+}
+
+local petAnchors = {
+ TOPLEFT = "TOPLEFT",
+ LEFT = "LEFT",
+ BOTTOMLEFT = "BOTTOMLEFT",
+ RIGHT = "RIGHT",
+ TOPRIGHT = "TOPRIGHT",
+ BOTTOMRIGHT = "BOTTOMRIGHT",
+ TOP = "TOP",
+ BOTTOM = "BOTTOM"
+}
+
+local attachToValues = {
+ ["Health"] = L["HEALTH"],
+ ["Power"] = L["Power"],
+ ["InfoPanel"] = L["Information Panel"],
+ ["Frame"] = L["Frame"]
+}
+
+local growthDirectionValues = {
+ DOWN_RIGHT = format(L["%s and then %s"], L["Down"], L["Right"]),
+ DOWN_LEFT = format(L["%s and then %s"], L["Down"], L["Left"]),
+ UP_RIGHT = format(L["%s and then %s"], L["Up"], L["Right"]),
+ UP_LEFT = format(L["%s and then %s"], L["Up"], L["Left"]),
+ RIGHT_DOWN = format(L["%s and then %s"], L["Right"], L["Down"]),
+ RIGHT_UP = format(L["%s and then %s"], L["Right"], L["Up"]),
+ LEFT_DOWN = format(L["%s and then %s"], L["Left"], L["Down"]),
+ LEFT_UP = format(L["%s and then %s"], L["Left"], L["Up"])
+}
+
+local smartAuraPositionValues = {
+ ["DISABLED"] = L["DISABLE"],
+ ["BUFFS_ON_DEBUFFS"] = L["Position Buffs on Debuffs"],
+ ["DEBUFFS_ON_BUFFS"] = L["Position Debuffs on Buffs"],
+ ["FLUID_BUFFS_ON_DEBUFFS"] = L["Fluid Position Buffs on Debuffs"],
+ ["FLUID_DEBUFFS_ON_BUFFS"] = L["Fluid Position Debuffs on Buffs"]
+}
+
+local colorOverrideValues = {
+ ["USE_DEFAULT"] = L["Use Default"],
+ ["FORCE_ON"] = L["Force On"],
+ ["FORCE_OFF"] = L["Force Off"]
+}
+
+local blendModeValues = {
+ ["DISABLE"] = L["DISABLE"],
+ ["BLEND"] = L["Blend"],
+ ["ADD"] = L["Additive Blend"],
+ ["MOD"] = L["Modulating Blend"],
+ ["ALPHAKEY"] = L["Alpha Key"],
+}
+
+local CUSTOMTEXT_CONFIGS = {}
+local carryFilterFrom, carryFilterTo
+
+local function filterMatch(s,v)
+ local m1, m2, m3, m4 = "^"..v.."$", "^"..v..",", ","..v.."$", ","..v..","
+ return (strmatch(s, m1) and m1) or (strmatch(s, m2) and m2) or (strmatch(s, m3) and m3) or (strmatch(s, m4) and v..",")
+end
+
+local function filterPriority(auraType, groupName, value, remove, movehere, friendState)
+ if not auraType or not value then return end
+ local filter = E.db.unitframe.units[groupName] and E.db.unitframe.units[groupName][auraType] and E.db.unitframe.units[groupName][auraType].priority
+ if not filter then return end
+ local found = filterMatch(filter, E:EscapeString(value))
+ if found and movehere then
+ local tbl, sv, sm = {strsplit(",",filter)}
+ for i in ipairs(tbl) do
+ if tbl[i] == value then sv = i elseif tbl[i] == movehere then sm = i end
+ if sv and sm then break end
+ end
+ tremove(tbl, sm)
+ tinsert(tbl, sv, movehere)
+ E.db.unitframe.units[groupName][auraType].priority = tconcat(tbl,",")
+ elseif found and friendState then
+ local realValue = strmatch(value, "^Friendly:([^,]*)") or strmatch(value, "^Enemy:([^,]*)") or value
+ local friend = filterMatch(filter, E:EscapeString("Friendly:"..realValue))
+ local enemy = filterMatch(filter, E:EscapeString("Enemy:"..realValue))
+ local default = filterMatch(filter, E:EscapeString(realValue))
+
+ local state =
+ (friend and (not enemy) and format("%s%s","Enemy:",realValue)) --[x] friend [ ] enemy: > enemy
+ or ((not enemy and not friend) and format("%s%s","Friendly:",realValue)) --[ ] friend [ ] enemy: > friendly
+ or (enemy and (not friend) and default and format("%s%s","Friendly:",realValue)) --[ ] friend [x] enemy: (default exists) > friendly
+ or (enemy and (not friend) and strmatch(value, "^Enemy:") and realValue) --[ ] friend [x] enemy: (no default) > realvalue
+ or (friend and enemy and realValue) --[x] friend [x] enemy: > default
+
+ if state then
+ local stateFound = filterMatch(filter, E:EscapeString(state))
+ if not stateFound then
+ local tbl, sv = {strsplit(",",filter)}
+ for i in ipairs(tbl) do
+ if tbl[i] == value then
+ sv = i
+ break
+ end
+ end
+ tinsert(tbl, sv, state)
+ tremove(tbl, sv + 1)
+ E.db.unitframe.units[groupName][auraType].priority = tconcat(tbl,",")
+ end
+ end
+ elseif found and remove then
+ E.db.unitframe.units[groupName][auraType].priority = gsub(filter, found, "")
+ elseif not found and not remove then
+ E.db.unitframe.units[groupName][auraType].priority = (filter == "" and value) or (filter..","..value)
+ end
+end
+
+-----------------------------------------------------------------------
+-- OPTIONS TABLES
+-----------------------------------------------------------------------
+local function GetOptionsTable_AuraBars(updateFunc, groupName)
+ local config = {
+ order = 800,
+ type = "group",
+ name = L["Aura Bars"],
+ get = function(info) return E.db.unitframe.units[groupName].aurabar[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].aurabar[info[#info]] = value updateFunc(UF, groupName) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Aura Bars"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ configureButton1 = {
+ order = 3,
+ type = "execute",
+ name = L["Coloring"],
+ desc = L["This opens the UnitFrames Color settings. These settings affect all unitframes."],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "generalOptionsGroup", "allColorsGroup", "auraBars") end,
+ },
+ configureButton2 = {
+ order = 4,
+ type = "execute",
+ name = L["Coloring (Specific)"],
+ func = function() E:SetToFilterConfig("AuraBar Colors") end
+ },
+ anchorPoint = {
+ order = 5,
+ type = "select",
+ name = L["Anchor Point"],
+ desc = L["What point to anchor to the frame you set to attach to."],
+ values = {
+ ["ABOVE"] = L["Above"],
+ ["BELOW"] = L["Below"]
+ }
+ },
+ attachTo = {
+ order = 6,
+ type = "select",
+ name = L["Attach To"],
+ desc = L["The object you want to attach to."],
+ values = {
+ ["FRAME"] = L["Frame"],
+ ["DEBUFFS"] = L["Debuffs"],
+ ["BUFFS"] = L["Buffs"]
+ }
+ },
+ height = {
+ order = 7,
+ type = "range",
+ name = L["Height"],
+ min = 6, max = 40, step = 1
+ },
+ maxBars = {
+ order = 8,
+ type = "range",
+ name = L["Max Bars"],
+ min = 1, max = 40, step = 1
+ },
+ sort = {
+ order = 9,
+ type = "select",
+ name = L["Sort Method"],
+ values = {
+ ["TIME_REMAINING"] = L["Time Remaining"],
+ ["TIME_REMAINING_REVERSE"] = L["Time Remaining Reverse"],
+ ["TIME_DURATION"] = L["Duration"],
+ ["TIME_DURATION_REVERSE"] = L["Duration Reverse"],
+ ["NAME"] = L["NAME"],
+ ["NONE"] = L["NONE"]
+ }
+ },
+ friendlyAuraType = {
+ order = 16,
+ type = "select",
+ name = L["Friendly Aura Type"],
+ desc = L["Set the type of auras to show when a unit is friendly."],
+ values = {
+ ["HARMFUL"] = L["Debuffs"],
+ ["HELPFUL"] = L["Buffs"]
+ }
+ },
+ enemyAuraType = {
+ order = 17,
+ type = "select",
+ name = L["Enemy Aura Type"],
+ desc = L["Set the type of auras to show when a unit is a foe."],
+ values = {
+ ["HARMFUL"] = L["Debuffs"],
+ ["HELPFUL"] = L["Buffs"]
+ }
+ },
+ uniformThreshold = {
+ order = 18,
+ type = "range",
+ name = L["Uniform Threshold"],
+ desc = L["Seconds remaining on the aura duration before the bar starts moving. Set to 0 to disable."],
+ min = 0, max = 3600, step = 1
+ },
+ yOffset = {
+ order = 19,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -1000, max = 1000, step = 1,
+ },
+ spacing = {
+ order = 20,
+ type = "range",
+ name = L["Spacing"],
+ min = 0, softMax = 20, step = 1,
+ },
+ filters = {
+ order = 500,
+ type = "group",
+ name = L["FILTERS"],
+ guiInline = true,
+ args = {}
+ }
+ }
+ }
+
+ if groupName == "target" then
+ config.args.attachTo.values.PLAYER_AURABARS = L["Player Frame Aura Bars"]
+ end
+
+ config.args.filters.args.minDuration = {
+ order = 16,
+ type = "range",
+ name = L["Minimum Duration"],
+ desc = L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."],
+ min = 0, max = 10800, step = 1,
+ }
+ config.args.filters.args.maxDuration = {
+ order = 17,
+ type = "range",
+ name = L["Maximum Duration"],
+ desc = L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."],
+ min = 0, max = 10800, step = 1,
+ }
+ config.args.filters.args.jumpToFilter = {
+ order = 18,
+ type = "execute",
+ name = L["Filters Page"],
+ desc = L["Shortcut to 'Filters' section of the config."],
+ func = function() ACD:SelectGroup("ElvUI", "filters") end
+ }
+ config.args.filters.args.specialPriority = {
+ order = 19,
+ type = "select",
+ sortByValue = true,
+ name = L["Add Special Filter"],
+ desc = L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."],
+ values = function()
+ local filters = {}
+ local list = E.global.unitframe.specialFilters
+ if not list then return end
+ for filter in pairs(list) do
+ filters[filter] = L[filter]
+ end
+ return filters
+ end,
+ set = function(info, value)
+ filterPriority("aurabar", groupName, value)
+ updateFunc(UF, groupName)
+ end
+ }
+ config.args.filters.args.priority = {
+ order = 20,
+ type = "select",
+ name = L["Add Regular Filter"],
+ desc = L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."],
+ values = function()
+ local filters = {}
+ local list = E.global.unitframe.aurafilters
+ if not list then return end
+ for filter in pairs(list) do
+ filters[filter] = filter
+ end
+ return filters
+ end,
+ set = function(info, value)
+ filterPriority("aurabar", groupName, value)
+ updateFunc(UF, groupName)
+ end
+ }
+ config.args.filters.args.resetPriority = {
+ order = 21,
+ type = "execute",
+ name = L["Reset Priority"],
+ desc = L["Reset filter priority to the default state."],
+ func = function()
+ E.db.unitframe.units[groupName].aurabar.priority = P.unitframe.units[groupName].aurabar.priority
+ updateFunc(UF, groupName)
+ end
+ }
+ config.args.filters.args.filterPriority = {
+ order = 22,
+ type = "multiselect",
+ dragdrop = true,
+ name = L["Filter Priority"],
+ dragOnLeave = E.noop, --keep this here
+ dragOnEnter = function(info)
+ carryFilterTo = info.obj.value
+ end,
+ dragOnMouseDown = function(info)
+ carryFilterFrom, carryFilterTo = info.obj.value, nil
+ end,
+ dragOnMouseUp = function(info)
+ filterPriority("aurabar", groupName, carryFilterTo, nil, carryFilterFrom) --add it in the new spot
+ carryFilterFrom, carryFilterTo = nil, nil
+ end,
+ dragOnClick = function(info)
+ filterPriority("aurabar", groupName, carryFilterFrom, true)
+ end,
+ stateSwitchGetText = function(_, TEXT)
+ local friend, enemy = strmatch(TEXT, "^Friendly:([^,]*)"), strmatch(TEXT, "^Enemy:([^,]*)")
+ local text = friend or enemy or TEXT
+ local SF, localized = E.global.unitframe.specialFilters[text], L[text]
+ local blockText = SF and localized and text:match("^block") and localized:gsub("^%[.-]%s?", "")
+ local filterText = (blockText and format("|cFF999999%s|r %s", L["BLOCK"], blockText)) or localized or text
+ return (friend and format("|cFF33FF33%s|r %s", L["FRIEND"], filterText)) or (enemy and format("|cFFFF3333%s|r %s", L["ENEMY"], filterText)) or filterText
+ end,
+ stateSwitchOnClick = function(info)
+ filterPriority("aurabar", groupName, carryFilterFrom, nil, nil, true)
+ end,
+ values = function()
+ local str = E.db.unitframe.units[groupName].aurabar.priority
+ if str == "" then return nil end
+ return {strsplit(",",str)}
+ end,
+ get = function(info, value)
+ local str = E.db.unitframe.units[groupName].aurabar.priority
+ if str == "" then return nil end
+ local tbl = {strsplit(",",str)}
+ return tbl[value]
+ end,
+ set = function(info)
+ E.db.unitframe.units[groupName].aurabar[info[#info]] = nil -- this was being set when drag and drop was first added, setting it to nil to clear tester profiles of this variable
+ updateFunc(UF, groupName)
+ end
+ }
+ config.args.filters.args.spacer1 = {
+ order = 23,
+ type = "description",
+ name = L["Use drag and drop to rearrange filter priority or right click to remove a filter."].."\n"..L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."],
+ }
+
+ return config
+end
+
+local function GetOptionsTable_Auras(auraType, updateFunc, groupName, numUnits)
+ local config = {
+ order = auraType == "buffs" and 500 or 600,
+ type = "group",
+ name = auraType == "buffs" and L["Buffs"] or L["Debuffs"],
+ get = function(info) return E.db.unitframe.units[groupName][auraType][info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName][auraType][info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = auraType == "buffs" and L["Buffs"] or L["Debuffs"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ perrow = {
+ order = 3,
+ type = "range",
+ name = L["Per Row"],
+ min = 1, max = 20, step = 1,
+ },
+ numrows = {
+ order = 4,
+ type = "range",
+ name = L["Num Rows"],
+ min = 1, max = 10, step = 1
+ },
+ sizeOverride = {
+ order = 5,
+ type = "range",
+ name = L["Size Override"],
+ desc = L["If not set to 0 then override the size of the aura icon to this."],
+ min = 0, max = 60, step = 1
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ anchorPoint = {
+ order = 8,
+ type = "select",
+ name = L["Anchor Point"],
+ desc = L["What point to anchor to the frame you set to attach to."],
+ values = positionValues
+ },
+ clickThrough = {
+ order = 9,
+ type = "toggle",
+ name = L["Click Through"],
+ desc = L["Ignore mouse events."]
+ },
+ sortMethod = {
+ order = 10,
+ type = "select",
+ name = L["Sort By"],
+ desc = L["Method to sort by."],
+ values = {
+ ["TIME_REMAINING"] = L["Time Remaining"],
+ ["DURATION"] = L["Duration"],
+ ["NAME"] = L["NAME"],
+ ["INDEX"] = L["Index"],
+ ["PLAYER"] = L["PLAYER"]
+ }
+ },
+ sortDirection = {
+ order = 11,
+ type = "select",
+ name = L["Sort Direction"],
+ desc = L["Ascending or Descending order."],
+ values = {
+ ["ASCENDING"] = L["Ascending"],
+ ["DESCENDING"] = L["Descending"]
+ }
+ },
+ stacks = {
+ order = 12,
+ type = "group",
+ name = L["Stack Counter"],
+ guiInline = true,
+ get = function(info, value) return E.db.unitframe.units[groupName][auraType][info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName][auraType][info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ countFont = {
+ order = 1,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = _G.AceGUIWidgetLSMlists.font
+ },
+ countFontSize = {
+ order = 2,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 4, max = 20, step = 1, -- max 20 cause otherwise it looks weird
+ },
+ countFontOutline = {
+ order = 3,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ }
+ }
+ },
+ duration = {
+ order = 13,
+ type = "group",
+ name = L["Duration"],
+ guiInline = true,
+ get = function(info) return E.db.unitframe.units[groupName][auraType][info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName][auraType][info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ cooldownShortcut = {
+ order = 1,
+ type = "execute",
+ name = L["Cooldowns"],
+ func = function() ACD:SelectGroup("ElvUI", "cooldown", "unitframe") end,
+ },
+ durationPosition = {
+ order = 2,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOP"] = "TOP",
+ ["LEFT"] = "LEFT",
+ ["BOTTOM"] = "BOTTOM",
+ ["CENTER"] = "CENTER",
+ ["TOPLEFT"] = "TOPLEFT",
+ ["BOTTOMLEFT"] = "BOTTOMLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT"
+ }
+ }
+ }
+ },
+ filters = {
+ order = 100,
+ type = "group",
+ name = L["FILTERS"],
+ guiInline = true,
+ args = {}
+ }
+ }
+ }
+
+ if auraType == "buffs" then
+ config.args.attachTo = {
+ order = 7,
+ type = "select",
+ name = L["Attach To"],
+ desc = L["What to attach the buff anchor frame to."],
+ values = {
+ ["FRAME"] = L["Frame"],
+ ["DEBUFFS"] = L["Debuffs"],
+ ["HEALTH"] = L["HEALTH"],
+ ["POWER"] = L["Power"]
+ },
+ disabled = function()
+ local smartAuraPosition = E.db.unitframe.units[groupName].smartAuraPosition
+ return (smartAuraPosition and (smartAuraPosition == "BUFFS_ON_DEBUFFS" or smartAuraPosition == "FLUID_BUFFS_ON_DEBUFFS"))
+ end
+ }
+ else
+ config.args.attachTo = {
+ order = 7,
+ type = "select",
+ name = L["Attach To"],
+ desc = L["What to attach the debuff anchor frame to."],
+ values = {
+ ["FRAME"] = L["Frame"],
+ ["BUFFS"] = L["Buffs"],
+ ["HEALTH"] = L["HEALTH"],
+ ["POWER"] = L["Power"]
+ },
+ disabled = function()
+ local smartAuraPosition = E.db.unitframe.units[groupName].smartAuraPosition
+ return (smartAuraPosition and (smartAuraPosition == "DEBUFFS_ON_BUFFS" or smartAuraPosition == "FLUID_DEBUFFS_ON_BUFFS"))
+ end
+ }
+ end
+
+ config.args.filters.args.minDuration = {
+ order = 16,
+ type = "range",
+ name = L["Minimum Duration"],
+ desc = L["Don't display auras that are shorter than this duration (in seconds). Set to zero to disable."],
+ min = 0, max = 10800, step = 1
+ }
+ config.args.filters.args.maxDuration = {
+ order = 17,
+ type = "range",
+ name = L["Maximum Duration"],
+ desc = L["Don't display auras that are longer than this duration (in seconds). Set to zero to disable."],
+ min = 0, max = 10800, step = 1
+ }
+ config.args.filters.args.jumpToFilter = {
+ order = 18,
+ type = "execute",
+ name = L["Filters Page"],
+ desc = L["Shortcut to 'Filters' section of the config."],
+ func = function() ACD:SelectGroup("ElvUI", "filters") end
+ }
+ config.args.filters.args.specialPriority = {
+ order = 19,
+ type = "select",
+ sortByValue = true,
+ name = L["Add Special Filter"],
+ desc = L["These filters don't use a list of spells like the regular filters. Instead they use the WoW API and some code logic to determine if an aura should be allowed or blocked."],
+ values = function()
+ local filters = {}
+ local list = E.global.unitframe.specialFilters
+ if not list then return end
+ for filter in pairs(list) do
+ filters[filter] = L[filter]
+ end
+ return filters
+ end,
+ set = function(info, value)
+ filterPriority(auraType, groupName, value)
+ updateFunc(UF, groupName, numUnits)
+ end
+ }
+ config.args.filters.args.priority = {
+ order = 20,
+ type = "select",
+ name = L["Add Regular Filter"],
+ desc = L["These filters use a list of spells to determine if an aura should be allowed or blocked. The content of these filters can be modified in the 'Filters' section of the config."],
+ values = function()
+ local filters = {}
+ local list = E.global.unitframe.aurafilters
+ if not list then return end
+ for filter in pairs(list) do
+ filters[filter] = filter
+ end
+ return filters
+ end,
+ set = function(info, value)
+ filterPriority(auraType, groupName, value)
+ updateFunc(UF, groupName, numUnits)
+ end
+ }
+ config.args.filters.args.resetPriority = {
+ order = 21,
+ type = "execute",
+ name = L["Reset Priority"],
+ desc = L["Reset filter priority to the default state."],
+ func = function()
+ E.db.unitframe.units[groupName][auraType].priority = P.unitframe.units[groupName][auraType].priority
+ updateFunc(UF, groupName, numUnits)
+ end
+ }
+ config.args.filters.args.filterPriority = {
+ order = 22,
+ type = "multiselect",
+ dragdrop = true,
+ name = L["Filter Priority"],
+ dragOnLeave = E.noop, --keep this here
+ dragOnEnter = function(info)
+ carryFilterTo = info.obj.value
+ end,
+ dragOnMouseDown = function(info)
+ carryFilterFrom, carryFilterTo = info.obj.value, nil
+ end,
+ dragOnMouseUp = function(info)
+ filterPriority(auraType, groupName, carryFilterTo, nil, carryFilterFrom) --add it in the new spot
+ carryFilterFrom, carryFilterTo = nil, nil
+ end,
+ dragOnClick = function(info)
+ filterPriority(auraType, groupName, carryFilterFrom, true)
+ end,
+ stateSwitchGetText = function(_, TEXT)
+ local friend, enemy = strmatch(TEXT, "^Friendly:([^,]*)"), strmatch(TEXT, "^Enemy:([^,]*)")
+ local text = friend or enemy or TEXT
+ local SF, localized = E.global.unitframe.specialFilters[text], L[text]
+ local blockText = SF and localized and text:match("^block") and localized:gsub("^%[.-]%s?", "")
+ local filterText = (blockText and format("|cFF999999%s|r %s", L["BLOCK"], blockText)) or localized or text
+ return (friend and format("|cFF33FF33%s|r %s", L["FRIEND"], filterText)) or (enemy and format("|cFFFF3333%s|r %s", L["ENEMY"], filterText)) or filterText
+ end,
+ stateSwitchOnClick = function(info)
+ filterPriority(auraType, groupName, carryFilterFrom, nil, nil, true)
+ end,
+ values = function()
+ local str = E.db.unitframe.units[groupName][auraType].priority
+ if str == "" then return nil end
+ return {strsplit(",",str)}
+ end,
+ get = function(info, value)
+ local str = E.db.unitframe.units[groupName][auraType].priority
+ if str == "" then return nil end
+ local tbl = {strsplit(",",str)}
+ return tbl[value]
+ end,
+ set = function(info)
+ E.db.unitframe.units[groupName][auraType][info[#info]] = nil -- this was being set when drag and drop was first added, setting it to nil to clear tester profiles of this variable
+ updateFunc(UF, groupName, numUnits)
+ end
+ }
+ config.args.filters.args.spacer1 = {
+ order = 23,
+ type = "description",
+ name = L["Use drag and drop to rearrange filter priority or right click to remove a filter."].."\n"..L["Use Shift+LeftClick to toggle between friendly or enemy or normal state. Normal state will allow the filter to be checked on all units. Friendly state is for friendly units only and enemy state is for enemy units."],
+ }
+
+ return config
+end
+
+local function GetOptionsTable_InformationPanel(updateFunc, groupName, numUnits)
+ local config = {
+ order = 4000,
+ type = "group",
+ name = L["Information Panel"],
+ get = function(info) return E.db.unitframe.units[groupName].infoPanel[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].infoPanel[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Information Panel"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ transparent = {
+ order = 3,
+ type = "toggle",
+ name = L["Transparent"]
+ },
+ height = {
+ order = 4,
+ type = "range",
+ name = L["Height"],
+ min = 4, max = 30, step = 1
+ }
+ }
+ }
+
+ return config
+end
+
+local function GetOptionsTable_Health(isGroupFrame, updateFunc, groupName, numUnits)
+ local config = {
+ order = 100,
+ type = "group",
+ name = L["HEALTH"],
+ get = function(info) return E.db.unitframe.units[groupName].health[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].health[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["HEALTH"]
+ },
+ position = {
+ order = 2,
+ type = "select",
+ name = L["Text Position"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 3,
+ type = "range",
+ name = L["Text xOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 4,
+ type = "range",
+ name = L["Text yOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ attachTextTo = {
+ order = 5,
+ type = "select",
+ name = L["Attach Text To"],
+ values = attachToValues
+ },
+ colorOverride = {
+ order = 6,
+ type = "select",
+ name = L["Class Color Override"],
+ desc = L["Override the default class color setting."],
+ values = colorOverrideValues,
+ get = function(info) return E.db.unitframe.units[groupName][info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName][info[#info]] = value; updateFunc(UF, groupName, numUnits) end,
+ },
+ configureButton = {
+ order = 7,
+ type = "execute",
+ name = L["Coloring"],
+ desc = L["This opens the UnitFrames Color settings. These settings affect all unitframes."],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "generalOptionsGroup", "allColorsGroup", "healthGroup") end
+ },
+ text_format = {
+ order = 10,
+ type = "input",
+ name = L["Text Format"],
+ desc = L["TEXT_FORMAT_DESC"],
+ width = "full"
+ }
+ }
+ }
+
+ if isGroupFrame then
+ config.args.frequentUpdates = {
+ order = 8,
+ type = "toggle",
+ name = L["Frequent Updates"],
+ desc = L["Rapidly update the health, uses more memory and cpu. Only recommended for healing."]
+ }
+
+ config.args.orientation = {
+ order = 9,
+ type = "select",
+ name = L["Statusbar Fill Orientation"],
+ desc = L["Direction the health bar moves when gaining/losing health."],
+ values = {
+ ["HORIZONTAL"] = L["Horizontal"],
+ ["VERTICAL"] = L["Vertical"]
+ }
+ }
+ end
+
+ return config
+end
+
+local function GetOptionsTable_Power(hasDetatchOption, updateFunc, groupName, numUnits, hasStrataLevel)
+ local config = {
+ order = 200,
+ type = "group",
+ name = L["Power"],
+ get = function(info) return E.db.unitframe.units[groupName].power[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].power[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Power"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ width = {
+ order = 3,
+ type = "select",
+ name = L["Style"],
+ values = {
+ ["fill"] = L["Filled"],
+ ["spaced"] = L["Spaced"],
+ ["inset"] = L["Inset"]
+ },
+ set = function(info, value)
+ E.db.unitframe.units[groupName].power[info[#info]] = value
+
+ local frameName = E:StringTitle(groupName)
+ frameName = "ElvUF_"..frameName
+ frameName = frameName:gsub("t(arget)", "T%1")
+
+ if numUnits then
+ for i = 1, numUnits do
+ if _G[frameName..i] then
+ local min, max = _G[frameName..i].Power:GetMinMaxValues()
+ _G[frameName..i].Power:SetMinMaxValues(min, max + 500)
+ _G[frameName..i].Power:SetValue(1)
+ _G[frameName..i].Power:SetValue(0)
+ end
+ end
+ else
+ if _G[frameName] and _G[frameName].Power then
+ local min, max = _G[frameName].Power:GetMinMaxValues()
+ _G[frameName].Power:SetMinMaxValues(min, max + 500)
+ _G[frameName].Power:SetValue(1)
+ _G[frameName].Power:SetValue(0)
+ else
+ for i = 1, _G[frameName]:GetNumChildren() do
+ local child = select(i, _G[frameName]:GetChildren())
+ if child and child.Power then
+ local min, max = child.Power:GetMinMaxValues()
+ child.Power:SetMinMaxValues(min, max + 500)
+ child.Power:SetValue(1)
+ child.Power:SetValue(0)
+ end
+ end
+ end
+ end
+
+ updateFunc(UF, groupName, numUnits)
+ end
+ },
+ height = {
+ order = 4,
+ type = "range",
+ name = L["Height"],
+ min = ((E.db.unitframe.thinBorders or E.PixelMode) and 3 or 7), max = 50, step = 1
+ },
+ offset = {
+ order = 5,
+ type = "range",
+ name = L["Offset"],
+ desc = L["Offset of the powerbar to the healthbar, set to 0 to disable."],
+ min = 0, max = 20, step = 1
+ },
+ configureButton = {
+ order = 6,
+ type = "execute",
+ name = L["Coloring"],
+ desc = L["This opens the UnitFrames Color settings. These settings affect all unitframes."],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "general", "allColorsGroup", "powerGroup") end,
+ },
+ position = {
+ order = 7,
+ type = "select",
+ name = L["Text Position"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 8,
+ type = "range",
+ name = L["Text xOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 9,
+ type = "range",
+ name = L["Text yOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ attachTextTo = {
+ order = 10,
+ type = "select",
+ name = L["Attach Text To"],
+ values = attachToValues
+ },
+ text_format = {
+ order = 100,
+ type = "input",
+ name = L["Text Format"],
+ width = "full",
+ desc = L["TEXT_FORMAT_DESC"]
+ }
+ }
+ }
+
+ if hasDetatchOption then
+ config.args.detachFromFrame = {
+ order = 11,
+ type = "toggle",
+ name = L["Detach From Frame"]
+ }
+ config.args.detachedWidth = {
+ order = 12,
+ type = "range",
+ name = L["Detached Width"],
+ disabled = function() return not E.db.unitframe.units[groupName].power.detachFromFrame end,
+ min = 15, max = 1000, step = 1
+ }
+ config.args.parent = {
+ order = 13,
+ type = "select",
+ name = L["Parent"],
+ desc = L["Choose UIPARENT to prevent it from hiding with the unitframe."],
+ disabled = function() return not E.db.unitframe.units[groupName].power.detachFromFrame end,
+ values = {
+ ["FRAME"] = "FRAME",
+ ["UIPARENT"] = "UIPARENT"
+ }
+ }
+ end
+
+ if hasStrataLevel then
+ config.args.strataAndLevel = {
+ order = 101,
+ type = "group",
+ name = L["Strata and Level"],
+ get = function(info) return E.db.unitframe.units[groupName].power.strataAndLevel[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].power.strataAndLevel[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ guiInline = true,
+ args = {
+ useCustomStrata = {
+ order = 1,
+ type = "toggle",
+ name = L["Use Custom Strata"]
+ },
+ frameStrata = {
+ order = 2,
+ type = "select",
+ name = L["Frame Strata"],
+ values = {
+ ["BACKGROUND"] = "BACKGROUND",
+ ["LOW"] = "LOW",
+ ["MEDIUM"] = "MEDIUM",
+ ["HIGH"] = "HIGH",
+ ["DIALOG"] = "DIALOG",
+ ["TOOLTIP"] = "TOOLTIP"
+ }
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ useCustomLevel = {
+ order = 4,
+ type = "toggle",
+ name = L["Use Custom Level"]
+ },
+ frameLevel = {
+ order = 5,
+ type = "range",
+ name = L["Frame Level"],
+ min = 2, max = 128, step = 1
+ }
+ }
+ }
+ end
+
+ return config
+end
+
+local function GetOptionsTable_Energy(hasDetatchOption, updateFunc, groupName, numUnits, hasStrataLevel)
+ local config = {
+ order = 250,
+ type = "group",
+ name = L["Energy"],
+ get = function(info)
+ return E.db.unitframe.units[groupName].energy[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.unitframe.units[groupName].energy[info[#info]] = value
+ updateFunc(UF, groupName, numUnits)
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Energy"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ width = {
+ order = 3,
+ type = "select",
+ name = L["Style"],
+ values = {
+ ["fill"] = L["Filled"],
+ ["spaced"] = L["Spaced"],
+ ["inset"] = L["Inset"]
+ },
+ set = function(info, value)
+ E.db.unitframe.units[groupName].energy[info[#info]] = value
+
+ local frameName = E:StringTitle(groupName)
+ frameName = "ElvUF_"..frameName
+ frameName = frameName:gsub("t(arget)", "T%1")
+
+ if numUnits then
+ for i = 1, numUnits do
+ if _G[frameName..i] then
+ local min, max = _G[frameName..i].Power:GetMinMaxValues()
+ _G[frameName..i].Power:SetMinMaxValues(min, max + 500)
+ _G[frameName..i].Power:SetValue(1)
+ _G[frameName..i].Power:SetValue(0)
+ end
+ end
+ else
+ if _G[frameName] and _G[frameName].Power then
+ local min, max = _G[frameName].Power:GetMinMaxValues()
+ _G[frameName].Power:SetMinMaxValues(min, max + 500)
+ _G[frameName].Power:SetValue(1)
+ _G[frameName].Power:SetValue(0)
+ else
+ for i = 1, _G[frameName]:GetNumChildren() do
+ local child = select(i, _G[frameName]:GetChildren())
+ if child and child.Power then
+ local min, max = child.Power:GetMinMaxValues()
+ child.Power:SetMinMaxValues(min, max + 500)
+ child.Power:SetValue(1)
+ child.Power:SetValue(0)
+ end
+ end
+ end
+ end
+
+ updateFunc(UF, groupName, numUnits)
+ end
+ },
+ height = {
+ order = 4,
+ type = "range",
+ name = L["Height"],
+ min = ((E.db.unitframe.thinBorders or E.PixelMode) and 3 or 7), max = 50, step = 1
+ },
+ offset = {
+ order = 5,
+ type = "range",
+ name = L["Offset"],
+ desc = L["Offset of the powerbar to the healthbar, set to 0 to disable."],
+ min = 0, max = 20, step = 1
+ },
+ configureButton = {
+ order = 6,
+ type = "execute",
+ name = L["Coloring"],
+ desc = L["This opens the UnitFrames Color settings. These settings affect all unitframes."],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "general", "allColorsGroup", "powerGroup") end
+ },
+ position = {
+ order = 7,
+ type = "select",
+ name = L["Text Position"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 8,
+ type = "range",
+ name = L["Text xOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 9,
+ type = "range",
+ name = L["Text yOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ attachTextTo = {
+ order = 10,
+ type = "select",
+ name = L["Attach Text To"],
+ values = {
+ ["Health"] = HEALTH,
+ ["Power"] = L["Power"],
+ ["Energy"] = L["Energy"],
+ ["InfoPanel"] = L["Information Panel"],
+ ["Frame"] = L["Frame"]
+ }
+ },
+ text_format = {
+ order = 100,
+ type = "input",
+ name = L["Text Format"],
+ desc = L["TEXT_FORMAT_DESC"],
+ width = "full"
+ }
+ }
+ }
+
+ if hasDetatchOption then
+ config.args.detachFromFrame = {
+ type = "toggle",
+ order = 11,
+ name = L["Detach From Frame"]
+ }
+ config.args.detachedWidth = {
+ type = "range",
+ order = 12,
+ name = L["Detached Width"],
+ disabled = function() return not E.db.unitframe.units[groupName].power.detachFromFrame end,
+ min = 15, max = 1000, step = 1
+ }
+ config.args.parent = {
+ type = "select",
+ order = 11,
+ name = L["Parent"],
+ desc = L["Choose UIPARENT to prevent it from hiding with the unitframe."],
+ disabled = function() return not E.db.unitframe.units[groupName].power.detachFromFrame end,
+ values = {
+ ["FRAME"] = "FRAME",
+ ["UIPARENT"] = "UIPARENT"
+ }
+ }
+ end
+
+ if hasStrataLevel then
+ config.args.strataAndLevel = {
+ order = 101,
+ type = "group",
+ name = L["Strata and Level"],
+ get = function(info) return E.db.unitframe.units[groupName]["power"]["strataAndLevel"][ info[#info] ] end,
+ set = function(info, value) E.db.unitframe.units[groupName]["power"]["strataAndLevel"][ info[#info] ] = value updateFunc(UF, groupName, numUnits) end,
+ guiInline = true,
+ args = {
+ useCustomStrata = {
+ order = 1,
+ type = "toggle",
+ name = L["Use Custom Strata"]
+ },
+ frameStrata = {
+ order = 2,
+ type = "select",
+ name = L["Frame Strata"],
+ values = {
+ ["BACKGROUND"] = "BACKGROUND",
+ ["LOW"] = "LOW",
+ ["MEDIUM"] = "MEDIUM",
+ ["HIGH"] = "HIGH",
+ ["DIALOG"] = "DIALOG",
+ ["TOOLTIP"] = "TOOLTIP"
+ }
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ useCustomLevel = {
+ order = 4,
+ type = "toggle",
+ name = L["Use Custom Level"]
+ },
+ frameLevel = {
+ order = 5,
+ type = "range",
+ name = L["Frame Level"],
+ min = 2, max = 128, step = 1
+ }
+ }
+ }
+ end
+
+ return config
+end
+
+local function GetOptionsTable_Rage(hasDetatchOption, updateFunc, groupName, numUnits, hasStrataLevel)
+ local config = {
+ order = 250,
+ type = "group",
+ name = L["Rage"],
+ get = function(info)
+ return E.db.unitframe.units[groupName].rage[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.unitframe.units[groupName].rage[info[#info]] = value
+ updateFunc(UF, groupName, numUnits)
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Rage"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ width = {
+ order = 3,
+ type = "select",
+ name = L["Style"],
+ values = {
+ ["fill"] = L["Filled"],
+ ["spaced"] = L["Spaced"],
+ ["inset"] = L["Inset"]
+ },
+ set = function(info, value)
+ E.db.unitframe.units[groupName].rage[info[#info]] = value
+
+ local frameName = E:StringTitle(groupName)
+ frameName = "ElvUF_"..frameName
+ frameName = frameName:gsub("t(arget)", "T%1")
+
+ if numUnits then
+ for i = 1, numUnits do
+ if _G[frameName..i] then
+ local min, max = _G[frameName..i].Power:GetMinMaxValues()
+ _G[frameName..i].Power:SetMinMaxValues(min, max + 500)
+ _G[frameName..i].Power:SetValue(1)
+ _G[frameName..i].Power:SetValue(0)
+ end
+ end
+ else
+ if _G[frameName] and _G[frameName].Power then
+ local min, max = _G[frameName].Power:GetMinMaxValues()
+ _G[frameName].Power:SetMinMaxValues(min, max + 500)
+ _G[frameName].Power:SetValue(1)
+ _G[frameName].Power:SetValue(0)
+ else
+ for i = 1, _G[frameName]:GetNumChildren() do
+ local child = select(i, _G[frameName]:GetChildren())
+ if child and child.Power then
+ local min, max = child.Power:GetMinMaxValues()
+ child.Power:SetMinMaxValues(min, max + 500)
+ child.Power:SetValue(1)
+ child.Power:SetValue(0)
+ end
+ end
+ end
+ end
+
+ updateFunc(UF, groupName, numUnits)
+ end
+ },
+ height = {
+ order = 4,
+ type = "range",
+ name = L["Height"],
+ min = ((E.db.unitframe.thinBorders or E.PixelMode) and 3 or 7), max = 50, step = 1
+ },
+ offset = {
+ order = 5,
+ type = "range",
+ name = L["Offset"],
+ desc = L["Offset of the powerbar to the healthbar, set to 0 to disable."],
+ min = 0, max = 20, step = 1
+ },
+ configureButton = {
+ order = 6,
+ type = "execute",
+ name = L["Coloring"],
+ desc = L["This opens the UnitFrames Color settings. These settings affect all unitframes."],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "general", "allColorsGroup", "powerGroup") end
+ },
+ position = {
+ order = 7,
+ type = "select",
+ name = L["Text Position"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 8,
+ type = "range",
+ name = L["Text xOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 9,
+ type = "range",
+ name = L["Text yOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ attachTextTo = {
+ order = 10,
+ type = "select",
+ name = L["Attach Text To"],
+ values = {
+ ["Health"] = HEALTH,
+ ["Power"] = L["Power"],
+ ["Rage"] = L["Rage"],
+ ["InfoPanel"] = L["Information Panel"],
+ ["Frame"] = L["Frame"]
+ }
+ },
+ text_format = {
+ order = 100,
+ type = "input",
+ name = L["Text Format"],
+ desc = L["TEXT_FORMAT_DESC"],
+ width = "full"
+ }
+ }
+ }
+
+ if hasDetatchOption then
+ config.args.detachFromFrame = {
+ type = "toggle",
+ order = 11,
+ name = L["Detach From Frame"]
+ }
+ config.args.detachedWidth = {
+ type = "range",
+ order = 12,
+ name = L["Detached Width"],
+ disabled = function() return not E.db.unitframe.units[groupName].power.detachFromFrame end,
+ min = 15, max = 1000, step = 1
+ }
+ config.args.parent = {
+ type = "select",
+ order = 11,
+ name = L["Parent"],
+ desc = L["Choose UIPARENT to prevent it from hiding with the unitframe."],
+ disabled = function() return not E.db.unitframe.units[groupName].power.detachFromFrame end,
+ values = {
+ ["FRAME"] = "FRAME",
+ ["UIPARENT"] = "UIPARENT"
+ }
+ }
+ end
+
+ if hasStrataLevel then
+ config.args.strataAndLevel = {
+ order = 101,
+ type = "group",
+ name = L["Strata and Level"],
+ get = function(info) return E.db.unitframe.units[groupName]["power"]["strataAndLevel"][ info[#info] ] end,
+ set = function(info, value) E.db.unitframe.units[groupName]["power"]["strataAndLevel"][ info[#info] ] = value updateFunc(UF, groupName, numUnits) end,
+ guiInline = true,
+ args = {
+ useCustomStrata = {
+ order = 1,
+ type = "toggle",
+ name = L["Use Custom Strata"]
+ },
+ frameStrata = {
+ order = 2,
+ type = "select",
+ name = L["Frame Strata"],
+ values = {
+ ["BACKGROUND"] = "BACKGROUND",
+ ["LOW"] = "LOW",
+ ["MEDIUM"] = "MEDIUM",
+ ["HIGH"] = "HIGH",
+ ["DIALOG"] = "DIALOG",
+ ["TOOLTIP"] = "TOOLTIP"
+ }
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ useCustomLevel = {
+ order = 4,
+ type = "toggle",
+ name = L["Use Custom Level"]
+ },
+ frameLevel = {
+ order = 5,
+ type = "range",
+ name = L["Frame Level"],
+ min = 2, max = 128, step = 1
+ }
+ }
+ }
+ end
+
+ return config
+end
+
+local function GetOptionsTable_Name(updateFunc, groupName, numUnits)
+ local config = {
+ order = 300,
+ type = "group",
+ name = L["NAME"],
+ get = function(info) return E.db.unitframe.units[groupName].name[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].name[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["NAME"]
+ },
+ position = {
+ order = 2,
+ type = "select",
+ name = L["Text Position"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 3,
+ type = "range",
+ name = L["Text xOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 4,
+ type = "range",
+ name = L["Text yOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ attachTextTo = {
+ order = 5,
+ type = "select",
+ name = L["Attach Text To"],
+ values = attachToValues
+ },
+ text_format = {
+ order = 100,
+ type = "input",
+ name = L["Text Format"],
+ desc = L["TEXT_FORMAT_DESC"],
+ width = "full"
+ }
+ }
+ }
+
+ return config
+end
+
+local function GetOptionsTable_Portrait(updateFunc, groupName, numUnits)
+ local config = {
+ order = 400,
+ type = "group",
+ name = L["Portrait"],
+ get = function(info) return E.db.unitframe.units[groupName].portrait[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].portrait[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Portrait"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ desc = L["If you have a lot of 3D Portraits active then it will likely have a big impact on your FPS. Disable some portraits if you experience FPS issues."],
+ confirmText = L["If you have a lot of 3D Portraits active then it will likely have a big impact on your FPS. Disable some portraits if you experience FPS issues."],
+ confirm = true
+ },
+ overlay = {
+ order = 3,
+ type = "toggle",
+ name = L["Overlay"],
+ desc = L["The Portrait will overlay the Healthbar. This will be automatically happen if the Frame Orientation is set to Middle."],
+ disabled = function() return not E.db.unitframe.units[groupName].portrait.enable end
+ },
+ fullOverlay = {
+ order = 4,
+ type = "toggle",
+ name = L["Full Overlay"],
+ desc = L["This option allows the overlay to span the whole health, including the background."],
+ disabled = function() return not E.db.unitframe.units[groupName].portrait.enable or not E.db.unitframe.units[groupName].portrait.overlay end,
+ },
+ style = {
+ order = 5,
+ type = "select",
+ name = L["Style"],
+ desc = L["Select the display method of the portrait."],
+ values = {
+ ["2D"] = L["2D"],
+ ["3D"] = L["3D"]
+ },
+ disabled = function() return not E.db.unitframe.units[groupName].portrait.enable end
+ },
+ width = {
+ order = 6,
+ type = "range",
+ name = L["Width"],
+ min = 15, max = 150, step = 1,
+ disabled = function() return not E.db.unitframe.units[groupName].portrait.enable or E.db.unitframe.units[groupName].portrait.overlay end
+ },
+ overlayAlpha = {
+ order = 7,
+ type = "range",
+ name = L["Overlay Alpha"],
+ desc = L["Set the alpha level of portrait when frame is overlayed."],
+ min = 0.01, max = 1, step = 0.01,
+ disabled = function() return not E.db.unitframe.units[groupName].portrait.overlay end,
+ }
+ }
+ }
+
+ return config
+end
+
+local function GetOptionsTable_Fader(updateFunc, groupName, numUnits)
+ local config = {
+ order = 550,
+ type = "group",
+ name = L["Fader"],
+ get = function(info) return E.db.unitframe.units[groupName].fader[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].fader[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Fader"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ range = {
+ order = 3,
+ type = "toggle",
+ name = L["Range"],
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable end,
+ hidden = function() return groupName == "player" end
+ },
+ hover = {
+ order = 4,
+ type = "toggle",
+ name = L["Hover"],
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable or E.db.unitframe.units[groupName].fader.range end
+ },
+ combat = {
+ order = 5,
+ type = "toggle",
+ name = L["COMBAT"],
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable or E.db.unitframe.units[groupName].fader.range end
+ },
+ unittarget = {
+ order = 6,
+ type = "toggle",
+ name = L["Unit Target"],
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable or E.db.unitframe.units[groupName].fader.range end,
+ hidden = function() return groupName == "player" end
+ },
+ playertarget = {
+ order = 7,
+ type = "toggle",
+ name = (groupName == "player" and L["TARGET"]) or L["Player Target"],
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable or E.db.unitframe.units[groupName].fader.range end
+ },
+ focus = {
+ order = 8,
+ type = "toggle",
+ name = L["Focus"],
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable or E.db.unitframe.units[groupName].fader.range end
+ },
+ health = {
+ order = 9,
+ type = "toggle",
+ name = L["HEALTH"],
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable or E.db.unitframe.units[groupName].fader.range end
+ },
+ power = {
+ order = 10,
+ type = "toggle",
+ name = L["Power"],
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable or E.db.unitframe.units[groupName].fader.range end
+ },
+ vehicle = {
+ order = 11,
+ type = "toggle",
+ name = L["Vehicle"],
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable or E.db.unitframe.units[groupName].fader.range end
+ },
+ casting = {
+ order = 12,
+ type = "toggle",
+ name = L["Casting"],
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable or E.db.unitframe.units[groupName].fader.range end
+ },
+ spacer = {
+ order = 13,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ delay = {
+ order = 14,
+ type = "range",
+ name = L["Fade Out Delay"],
+ min = 0, max = 3, step = 0.01,
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable or E.db.unitframe.units[groupName].fader.range end
+ },
+ smooth = {
+ order = 15,
+ type = "range",
+ name = L["Smooth"],
+ min = 0, max = 1, step = 0.01,
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable end
+ },
+ minAlpha = {
+ order = 16,
+ type = "range",
+ name = L["Min Alpha"],
+ min = 0, max = 1, step = 0.01,
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable end
+ },
+ maxAlpha = {
+ order = 17,
+ type = "range",
+ name = L["Max Alpha"],
+ min = 0, max = 1, step = 0.01,
+ disabled = function() return not E.db.unitframe.units[groupName].fader.enable end
+ }
+ }
+ }
+
+ return config
+end
+
+local function GetOptionsTable_Castbar(hasTicks, updateFunc, groupName, numUnits)
+ local config = {
+ order = 700,
+ type = "group",
+ name = L["Castbar"],
+ get = function(info) return E.db.unitframe.units[groupName].castbar[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].castbar[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Castbar"]
+ },
+ matchsize = {
+ order = 2,
+ type = "execute",
+ name = L["Match Frame Width"],
+ func = function() E.db.unitframe.units[groupName].castbar.width = E.db.unitframe.units[groupName].width updateFunc(UF, groupName, numUnits) end
+ },
+ forceshow = {
+ order = 3,
+ type = "execute",
+ name = L["SHOW"].." / "..L["HIDE"],
+ func = function()
+ local frameName = E:StringTitle(groupName)
+ frameName = "ElvUF_"..frameName
+ frameName = frameName:gsub("t(arget)", "T%1")
+
+ if groupName == "party" then
+ local header = UF.headers[groupName]
+ for i = 1, header:GetNumChildren() do
+ local group = select(i, header:GetChildren())
+ for j = 1, group:GetNumChildren() do
+ --Party unitbutton
+ local unitbutton = select(j, group:GetChildren())
+ local castbar = unitbutton.Castbar
+ if not castbar.oldHide then
+ castbar.oldHide = castbar.Hide
+ castbar.Hide = castbar.Show
+ castbar:Show()
+ else
+ castbar.Hide = castbar.oldHide
+ castbar.oldHide = nil
+ castbar:Hide()
+ end
+ end
+ end
+ elseif numUnits then
+ for i = 1, numUnits do
+ local castbar = _G[frameName..i].Castbar
+ if not castbar.oldHide then
+ castbar.oldHide = castbar.Hide
+ castbar.Hide = castbar.Show
+ castbar:Show()
+ else
+ castbar.Hide = castbar.oldHide
+ castbar.oldHide = nil
+ castbar:Hide()
+ end
+ end
+ else
+ local castbar = _G[frameName].Castbar
+ if not castbar.oldHide then
+ castbar.oldHide = castbar.Hide
+ castbar.Hide = castbar.Show
+ castbar:Show()
+ else
+ castbar.Hide = castbar.oldHide
+ castbar.oldHide = nil
+ castbar:Hide()
+ end
+ end
+ end
+ },
+ configureButton = {
+ order = 4,
+ type = "execute",
+ name = L["Coloring"],
+ desc = L["This opens the UnitFrames Color settings. These settings affect all unitframes."],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "generalOptionsGroup", "allColorsGroup", "castBars") end
+ },
+ enable = {
+ order = 5,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ width = {
+ order = 6,
+ type = "range",
+ name = L["Width"],
+ softMax = 600,
+ min = 50, max = GetScreenWidth(), step = 1
+ },
+ height = {
+ order = 7,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 85, step = 1
+ },
+ timeToHold = {
+ order = 8,
+ type = "range",
+ name = L["Time To Hold"],
+ desc = L["How many seconds the castbar should stay visible after the cast failed or was interrupted."],
+ min = 0, max = 10, step = .1
+ },
+ latency = {
+ order = 9,
+ type = "toggle",
+ name = L["Latency"]
+ },
+ format = {
+ order = 10,
+ type = "select",
+ name = L["Format"],
+ values = {
+ ["CURRENTMAX"] = L["Current / Max"],
+ ["CURRENT"] = L["Current"],
+ ["REMAINING"] = L["Remaining"],
+ ["REMAININGMAX"] = L["Remaining / Max"]
+ }
+ },
+ spark = {
+ order = 11,
+ type = "toggle",
+ name = L["Spark"],
+ desc = L["Display a spark texture at the end of the castbar statusbar to help show the differance between castbar and backdrop."]
+ },
+ insideInfoPanel = {
+ order = 12,
+ type = "toggle",
+ name = L["Inside Information Panel"],
+ desc = L["Display the castbar inside the information panel, the icon will be displayed outside the main unitframe."],
+ disabled = function() return not E.db.unitframe.units[groupName].infoPanel or not E.db.unitframe.units[groupName].infoPanel.enable end
+ },
+ iconSettings = {
+ order = 13,
+ type = "group",
+ name = L["Icon"],
+ guiInline = true,
+ get = function(info) return E.db.unitframe.units[groupName].castbar[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].castbar[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ icon = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ iconAttached = {
+ order = 2,
+ type = "toggle",
+ name = L["Icon Inside Castbar"],
+ desc = L["Display the castbar icon inside the castbar."]
+ },
+ iconSize = {
+ order = 3,
+ type = "range",
+ name = L["Icon Size"],
+ desc = L["This dictates the size of the icon when it is not attached to the castbar."],
+ min = 8, max = 150, step = 1,
+ disabled = function() return E.db.unitframe.units[groupName].castbar.iconAttached end
+ },
+ iconAttachedTo = {
+ order = 4,
+ type = "select",
+ name = L["Attach To"],
+ disabled = function() return E.db.unitframe.units[groupName].castbar.iconAttached end,
+ values = {
+ ["Frame"] = L["Frame"],
+ ["Castbar"] = L["Castbar"]
+ }
+ },
+ iconPosition = {
+ order = 5,
+ type = "select",
+ name = L["Position"],
+ values = positionValues,
+ disabled = function() return E.db.unitframe.units[groupName].castbar.iconAttached end
+ },
+ iconXOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -300, max = 300, step = 1,
+ disabled = function() return E.db.unitframe.units[groupName].castbar.iconAttached end
+ },
+ iconYOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -300, max = 300, step = 1,
+ disabled = function() return E.db.unitframe.units[groupName].castbar.iconAttached end
+ }
+ }
+ },
+ strataAndLevel = {
+ order = 14,
+ type = "group",
+ name = L["Strata and Level"],
+ get = function(info) return E.db.unitframe.units[groupName].castbar.strataAndLevel[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].castbar.strataAndLevel[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ guiInline = true,
+ args = {
+ useCustomStrata = {
+ order = 1,
+ type = "toggle",
+ name = L["Use Custom Strata"]
+ },
+ frameStrata = {
+ order = 2,
+ type = "select",
+ name = L["Frame Strata"],
+ values = {
+ ["BACKGROUND"] = "BACKGROUND",
+ ["LOW"] = "LOW",
+ ["MEDIUM"] = "MEDIUM",
+ ["HIGH"] = "HIGH",
+ ["DIALOG"] = "DIALOG",
+ ["TOOLTIP"] = "TOOLTIP"
+ }
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ useCustomLevel = {
+ order = 4,
+ type = "toggle",
+ name = L["Use Custom Level"]
+ },
+ frameLevel = {
+ order = 5,
+ type = "range",
+ name = L["Frame Level"],
+ min = 2, max = 128, step = 1
+ }
+ }
+ }
+ }
+ }
+
+ if hasTicks then
+ config.args.displayTarget = {
+ order = 11,
+ type = "toggle",
+ name = L["Display Target"],
+ desc = L["Display the target of your current cast. Useful for mouseover casts."]
+ }
+ config.args.ticks = {
+ order = 12,
+ type = "group",
+ name = L["Ticks"],
+ guiInline = true,
+ args = {
+ ticks = {
+ order = 1,
+ type = "toggle",
+ name = L["Ticks"],
+ desc = L["Display tick marks on the castbar for channelled spells. This will adjust automatically for spells like Drain Soul and add additional ticks based on haste."]
+ },
+ tickColor = {
+ order = 2,
+ type = "color",
+ name = L["COLOR"],
+ hasAlpha = true,
+ get = function(info)
+ local c = E.db.unitframe.units[groupName].castbar.tickColor
+ local d = P.unitframe.units[groupName].castbar.tickColor
+ return c.r, c.g, c.b, c.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local c = E.db.unitframe.units[groupName].castbar.tickColor
+ c.r, c.g, c.b, c.a = r, g, b, a
+ updateFunc(UF, groupName, numUnits)
+ end
+ },
+ tickWidth = {
+ order = 3,
+ type = "range",
+ name = L["Width"],
+ min = 1, max = 20, step = 1
+ }
+ }
+ }
+ end
+
+ return config
+end
+
+local function GetOptionsTable_RaidIcon(updateFunc, groupName, numUnits)
+ local config = {
+ order = 1000,
+ type = "group",
+ name = L["Raid Icon"],
+ get = function(info) return E.db.unitframe.units[groupName].raidicon[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].raidicon[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Raid Icon"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"],
+ },
+ attachTo = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ values = positionValues,
+ disabled = function() return not E.db.unitframe.units[groupName].raidicon.enable end
+ },
+ attachToObject = {
+ order = 4,
+ type = "select",
+ name = L["Attach To"],
+ values = attachToValues
+ },
+ size = {
+ order = 5,
+ type = "range",
+ name = L["Size"],
+ min = 8, max = 60, step = 1,
+ disabled = function() return not E.db.unitframe.units[groupName].raidicon.enable end
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -300, max = 300, step = 1,
+ disabled = function() return not E.db.unitframe.units[groupName].raidicon.enable end
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -300, max = 300, step = 1,
+ disabled = function() return not E.db.unitframe.units[groupName].raidicon.enable end
+ }
+ }
+ }
+
+ return config
+end
+
+local function GetOptionsTable_ResurrectIcon(updateFunc, groupName, numUnits)
+ local config = {
+ order = 5001,
+ type = "group",
+ name = L["Resurrect Icon"],
+ get = function(info) return E.db.unitframe.units[groupName].resurrectIcon[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].resurrectIcon[info[#info]] = value updateFunc(UF, groupName, numUnits) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Resurrect Icon"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ attachTo = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ values = positionValues
+ },
+ attachToObject = {
+ order = 4,
+ type = "select",
+ name = L["Attach To"],
+ values = attachToValues
+ },
+ size = {
+ order = 5,
+ type = "range",
+ name = L["Size"],
+ min = 8, max = 60, step = 1
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -300, max = 300, step = 1
+ }
+ }
+ }
+
+ return config
+end
+
+local function GetOptionsTable_RaidDebuff(updateFunc, groupName)
+ local config = {
+ order = 800,
+ type = "group",
+ name = L["RaidDebuff Indicator"],
+ get = function(info) return E.db.unitframe.units[groupName].rdebuffs[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].rdebuffs[info[#info]] = value updateFunc(UF, groupName) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["RaidDebuff Indicator"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ showDispellableDebuff = {
+ order = 3,
+ type = "toggle",
+ name = L["Show Dispellable Debuffs"]
+ },
+ onlyMatchSpellID = {
+ order = 4,
+ type = "toggle",
+ name = L["Only Match SpellID"],
+ desc = L["When enabled it will only show spells that were added to the filter using a spell ID and not a name."],
+ },
+ size = {
+ order = 5,
+ type = "range",
+ name = L["Size"],
+ min = 8, max = 100, step = 1
+ },
+ font = {
+ order = 6,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ fontSize = {
+ order = 7,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 7, max = 22, step = 1
+ },
+ fontOutline = {
+ order = 8,
+ type = "select",
+ name = L["Font Outline"],
+ values = C.Values.FontFlags
+ },
+ xOffset = {
+ order = 9,
+ type = "range",
+ name = L["X-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 10,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ configureButton = {
+ order = 11,
+ type = "execute",
+ name = L["Configure Auras"],
+ func = function() E:SetToFilterConfig("RaidDebuffs") end
+ },
+ duration = {
+ order = 12,
+ type = "group",
+ guiInline = true,
+ name = L["Duration Text"],
+ get = function(info) return E.db.unitframe.units[groupName].rdebuffs.duration[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].rdebuffs.duration[info[#info]] = value updateFunc(UF, groupName) end,
+ args = {
+ position = {
+ order = 1,
+ type = "select",
+ name = L["Position"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 2,
+ type = "range",
+ name = L["X-Offset"],
+ min = -10, max = 10, step = 1
+ },
+ yOffset = {
+ order = 3,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -10, max = 10, step = 1
+ },
+ color = {
+ order = 4,
+ type = "color",
+ name = L["COLOR"],
+ hasAlpha = true,
+ get = function(info)
+ local c = E.db.unitframe.units.raid.rdebuffs.duration.color
+ local d = P.unitframe.units.raid.rdebuffs.duration.color
+ return c.r, c.g, c.b, c.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local c = E.db.unitframe.units.raid.rdebuffs.duration.color
+ c.r, c.g, c.b, c.a = r, g, b, a
+ UF:CreateAndUpdateHeaderGroup("raid")
+ end
+ }
+ }
+ },
+ stack = {
+ order = 13,
+ type = "group",
+ guiInline = true,
+ name = L["Stack Counter"],
+ get = function(info) return E.db.unitframe.units[groupName].rdebuffs.stack[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].rdebuffs.stack[info[#info]] = value updateFunc(UF, groupName) end,
+ args = {
+ position = {
+ order = 1,
+ type = "select",
+ name = L["Position"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 2,
+ type = "range",
+ name = L["X-Offset"],
+ min = -10, max = 10, step = 1
+ },
+ yOffset = {
+ order = 3,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -10, max = 10, step = 1
+ },
+ color = {
+ order = 4,
+ type = "color",
+ name = L["COLOR"],
+ hasAlpha = true,
+ get = function(info)
+ local c = E.db.unitframe.units[groupName].rdebuffs.stack.color
+ local d = P.unitframe.units[groupName].rdebuffs.stack.color
+ return c.r, c.g, c.b, c.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local c = E.db.unitframe.units[groupName].rdebuffs.stack.color
+ c.r, c.g, c.b, c.a = r, g, b, a
+ updateFunc(UF, groupName)
+ end
+ }
+ }
+ }
+ }
+ }
+
+ return config
+end
+
+local function GetOptionsTable_ReadyCheckIcon(updateFunc, groupName)
+ local config = {
+ order = 700,
+ type = "group",
+ name = L["Ready Check Icon"],
+ get = function(info) return E.db.unitframe.units[groupName].readycheckIcon[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].readycheckIcon[info[#info]] = value updateFunc(UF, groupName) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Ready Check Icon"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ size = {
+ order = 3,
+ type = "range",
+ name = L["Size"],
+ min = 8, max = 60, step = 1
+ },
+ attachTo = {
+ order = 4,
+ type = "select",
+ name = L["Attach To"],
+ values = attachToValues
+ },
+ position = {
+ order = 5,
+ type = "select",
+ name = L["Position"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -300, max = 300, step = 1
+ }
+ }
+ }
+
+ return config
+end
+
+local function GetOptionsTable_HealPrediction(updateFunc, groupName, numGroup)
+ local config = {
+ order = 101,
+ type = "group",
+ name = L["Heal Prediction"],
+ desc = L["Show an incoming heal prediction bar on the unitframe. Also display a slightly different colored bar for incoming overheals."],
+ get = function(info) return E.db.unitframe.units[groupName].healPrediction[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].healPrediction[info[#info]] = value updateFunc(UF, groupName, numGroup) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Heal Prediction"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ colors = {
+ order = 3,
+ type = "execute",
+ name = L["COLORS"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "generalOptionsGroup", "allColorsGroup", "healPrediction") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ }
+ }
+ }
+
+ return config
+end
+
+local function CreateCustomTextGroup(unit, objectName)
+ if not E.Options.args.unitframe.args[unit] then
+ return
+ elseif E.Options.args.unitframe.args[unit].args.customText.args[objectName] then
+ E.Options.args.unitframe.args[unit].args.customText.args[objectName].hidden = false -- Re-show existing custom texts which belong to current profile and were previously hidden
+ tinsert(CUSTOMTEXT_CONFIGS, E.Options.args.unitframe.args[unit].args.customText.args[objectName]) --Register this custom text config to be hidden again on profile change
+ return
+ end
+
+ E.Options.args.unitframe.args[unit].args.customText.args[objectName] = {
+ order = -1,
+ type = "group",
+ name = objectName,
+ get = function(info) return E.db.unitframe.units[unit].customTexts[objectName][info[#info]] end,
+ set = function(info, value)
+ E.db.unitframe.units[unit].customTexts[objectName][info[#info]] = value
+
+ if unit == "party" or unit:find("raid") then
+ UF:CreateAndUpdateHeaderGroup(unit)
+ elseif unit == "boss" then
+ UF:CreateAndUpdateUFGroup("boss", MAX_BOSS_FRAMES)
+ elseif unit == "arena" then
+ UF:CreateAndUpdateUFGroup("arena", 5)
+ else
+ UF:CreateAndUpdateUF(unit)
+ end
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = objectName,
+ },
+ delete = {
+ order = 2,
+ type = "execute",
+ name = L["DELETE"],
+ func = function()
+ E.Options.args.unitframe.args[unit].args.customText.args[objectName] = nil
+ E.db.unitframe.units[unit].customTexts[objectName] = nil
+
+ if unit == "boss" or unit == "arena" then
+ for i = 1, 5 do
+ if UF[unit..i] then
+ UF[unit..i]:Untag(UF[unit..i].customTexts[objectName])
+ UF[unit..i].customTexts[objectName]:Hide()
+ UF[unit..i].customTexts[objectName] = nil
+ end
+ end
+ elseif unit == "party" or unit:find("raid") then
+ for i = 1, UF[unit]:GetNumChildren() do
+ local child = select(i, UF[unit]:GetChildren())
+ if child.Untag then
+ child:Untag(child.customTexts[objectName])
+ child.customTexts[objectName]:Hide()
+ child.customTexts[objectName] = nil
+ else
+ for x = 1, child:GetNumChildren() do
+ local c2 = select(x, child:GetChildren())
+ if c2.Untag then
+ c2:Untag(c2.customTexts[objectName])
+ c2.customTexts[objectName]:Hide()
+ c2.customTexts[objectName] = nil
+ end
+ end
+ end
+ end
+ elseif UF[unit] then
+ UF[unit]:Untag(UF[unit].customTexts[objectName])
+ UF[unit].customTexts[objectName]:Hide()
+ UF[unit].customTexts[objectName] = nil
+ end
+ end
+ },
+ enable = {
+ order = 3,
+ type = "toggle",
+ name = L["Enable"],
+ },
+ font = {
+ order = 4,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Font"],
+ values = AceGUIWidgetLSMlists.font
+ },
+ size = {
+ order = 5,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 6, max = 32, step = 1
+ },
+ fontOutline = {
+ order = 6,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags
+ },
+ justifyH = {
+ order = 7,
+ type = "select",
+ name = L["JustifyH"],
+ desc = L["Sets the font instance's horizontal text alignment style."],
+ values = {
+ ["CENTER"] = L["Center"],
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"]
+ }
+ },
+ xOffset = {
+ order = 8,
+ type = "range",
+ name = L["X-Offset"],
+ min = -400, max = 400, step = 1
+ },
+ yOffset = {
+ order = 9,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -400, max = 400, step = 1
+ },
+ attachTextTo = {
+ order = 10,
+ type = "select",
+ name = L["Attach Text To"],
+ values = attachToValues
+ },
+ text_format = {
+ order = 100,
+ type = "input",
+ name = L["Text Format"],
+ desc = L["TEXT_FORMAT_DESC"],
+ width = "full"
+ }
+ }
+ }
+
+ tinsert(CUSTOMTEXT_CONFIGS, E.Options.args.unitframe.args[unit].args.customText.args[objectName]) --Register this custom text config to be hidden on profile change
+end
+
+local function GetOptionsTable_CustomText(updateFunc, groupName, numUnits)
+ local config = {
+ order = 5100,
+ type = "group",
+ name = L["Custom Texts"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Custom Texts"],
+ },
+ createCustomText = {
+ order = 2,
+ type = "input",
+ name = L["Create Custom Text"],
+ width = "full",
+ get = function() return "" end,
+ set = function(info, textName)
+ for object in pairs(E.db.unitframe.units[groupName]) do
+ if object:lower() == textName:lower() then
+ E:Print(L["The name you have selected is already in use by another element."])
+ return
+ end
+ end
+
+ if not E.db.unitframe.units[groupName].customTexts then
+ E.db.unitframe.units[groupName].customTexts = {}
+ end
+
+ local frameName = "ElvUF_"..E:StringTitle(groupName)
+ if E.db.unitframe.units[groupName].customTexts[textName] or (_G[frameName] and _G[frameName].customTexts and _G[frameName].customTexts[textName] or _G[frameName.."Group1UnitButton1"] and _G[frameName.."Group1UnitButton1"].customTexts and _G[frameName.."Group1UnitButton1"][textName]) then
+ E:Print(L["The name you have selected is already in use by another element."])
+ return
+ end
+
+ E.db.unitframe.units[groupName].customTexts[textName] = {
+ ["text_format"] = "",
+ ["size"] = E.db.unitframe.fontSize,
+ ["font"] = E.db.unitframe.font,
+ ["xOffset"] = 0,
+ ["yOffset"] = 0,
+ ["justifyH"] = "CENTER",
+ ["fontOutline"] = E.db.unitframe.fontOutline,
+ ["attachTextTo"] = "Health"
+ }
+
+ CreateCustomTextGroup(groupName, textName)
+ updateFunc(UF, groupName, numUnits)
+ end
+ }
+ }
+ }
+
+ return config
+end
+
+local function GetOptionsTable_GPS(groupName)
+ local config = {
+ order = 3000,
+ type = "group",
+ name = L["GPS Arrow"],
+ get = function(info) return E.db.unitframe.units[groupName].GPSArrow[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].GPSArrow[info[#info]] = value UF:CreateAndUpdateHeaderGroup(groupName) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["GPS Arrow"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ onMouseOver = {
+ order = 3,
+ type = "toggle",
+ name = L["Mouseover"],
+ desc = L["Only show when you are mousing over a frame."]
+ },
+ outOfRange = {
+ order = 4,
+ type = "toggle",
+ name = L["Out of Range"],
+ desc = L["Only show when the unit is not in range."]
+ },
+ size = {
+ order = 5,
+ type = "range",
+ name = L["Size"],
+ min = 8, max = 60, step = 1
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -300, max = 300, step = 1
+ }
+ }
+ }
+
+ return config
+end
+
+local function GetOptionsTableForNonGroup_GPS(unit)
+ local config = {
+ order = 3000,
+ type = "group",
+ name = L["GPS Arrow"],
+ get = function(info) return E.db.unitframe.units[unit].GPSArrow[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[unit].GPSArrow[info[#info]] = value UF:CreateAndUpdateUF(unit) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["GPS Arrow"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ onMouseOver = {
+ order = 3,
+ type = "toggle",
+ name = L["Mouseover"],
+ desc = L["Only show when you are mousing over a frame."]
+ },
+ outOfRange = {
+ order = 4,
+ type = "toggle",
+ name = L["Out of Range"],
+ desc = L["Only show when the unit is not in range."]
+ },
+ size = {
+ order = 5,
+ type = "range",
+ name = L["Size"],
+ min = 8, max = 60, step = 1
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -300, max = 300, step = 1
+ }
+ }
+ }
+
+ return config
+end
+
+local function GetOptionsTable_Cutaway(updateFunc, groupName, numGroup)
+ local config = {
+ order = 1021,
+ type = "group",
+ childGroups = "tabs",
+ name = L["Cutaway Bars"],
+ args = {
+ health = {
+ order = 1,
+ type = "group",
+ guiInline = true,
+ name = L["HEALTH"],
+ get = function(info) return E.db.unitframe.units[groupName].cutaway.health[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].cutaway.health[info[#info]] = value; updateFunc(UF, groupName, numGroup) end,
+ args = {
+ enabled = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ lengthBeforeFade = {
+ order = 2,
+ type = "range",
+ name = L["Fade Out Delay"],
+ desc = L["How much time before the cutaway health starts to fade."],
+ min = 0.1, max = 1, step = 0.1,
+ disabled = function() return not E.db.unitframe.units[groupName].cutaway.health.enabled end
+ },
+ fadeOutTime = {
+ order = 3,
+ type = "range",
+ name = L["Fade Out"],
+ desc = L["How long the cutaway health will take to fade out."],
+ min = 0.1, max = 1, step = 0.1,
+ disabled = function() return not E.db.unitframe.units[groupName].cutaway.health.enabled end
+ }
+ }
+ }
+ }
+ }
+ if E.db.unitframe.units[groupName].cutaway.power then
+ config.args.power = {
+ order = 2,
+ type = "group",
+ name = L["Power"],
+ guiInline = true,
+ get = function(info) return E.db.unitframe.units[groupName].cutaway.power[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units[groupName].cutaway.power[info[#info]] = value updateFunc(UF, groupName, numGroup) end,
+ args = {
+ enabled = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ lengthBeforeFade = {
+ order = 2,
+ type = "range",
+ name = L["Fade Out Delay"],
+ desc = L["How much time before the cutaway power starts to fade."],
+ min = 0.1, max = 1, step = 0.1,
+ disabled = function() return not E.db.unitframe.units[groupName].cutaway.power.enabled end
+ },
+ fadeOutTime = {
+ type = "range",
+ order = 3,
+ name = L["Fade Out"],
+ desc = L["How long the cutaway power will take to fade out."],
+ min = 0.1, max = 1, step = 0.1,
+ disabled = function() return not E.db.unitframe.units[groupName].cutaway.power.enabled end
+ }
+ }
+ }
+ end
+
+ return config
+end
+
+E.Options.args.unitframe = {
+ type = "group",
+ name = L["UnitFrames"],
+ childGroups = "tree",
+ get = function(info) return E.db.unitframe[info[#info]] end,
+ set = function(info, value) E.db.unitframe[info[#info]] = value end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ get = function(info) return E.private.unitframe.enable end,
+ set = function(info, value) E.private.unitframe.enable = value E:StaticPopup_Show("PRIVATE_RL") end
+ },
+ intro = {
+ order = 2,
+ type = "description",
+ name = L["UNITFRAME_DESC"]
+ },
+ header = {
+ order = 3,
+ type = "header",
+ name = L["Shortcuts"]
+ },
+ spacer1 = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ generalShortcut = {
+ order = 5,
+ type = "execute",
+ name = L["General"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "generalOptionsGroup", "generalGroup") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ frameGlowShortcut = {
+ order = 6,
+ type = "execute",
+ name = L["Frame Glow"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "generalOptionsGroup", "frameGlowGroup") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ cooldownShortcut = {
+ order = 7,
+ type = "execute",
+ name = L["Cooldowns"],
+ func = function() ACD:SelectGroup("ElvUI", "cooldown", "unitframe") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ colorsShortcut = {
+ order = 8,
+ type = "execute",
+ name = L["COLORS"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "generalOptionsGroup", "allColorsGroup") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ },
+ spacer2 = {
+ order = 9,
+ type = "description",
+ name = " "
+ },
+ blizzardShortcut = {
+ order = 10,
+ type = "execute",
+ name = L["Disabled Blizzard Frames"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "generalOptionsGroup", "disabledBlizzardFrames") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ playerShortcut = {
+ order = 11,
+ type = "execute",
+ name = L["Player"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "player") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ targetShortcut = {
+ order = 12,
+ type = "execute",
+ name = L["TARGET"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "target") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ targettargetShortcut = {
+ order = 13,
+ type = "execute",
+ name = L["TargetTarget"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "targettarget") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ spacer3 = {
+ order = 14,
+ type = "description",
+ name = " "
+ },
+ targettargettargetShortcut = {
+ order = 15,
+ type = "execute",
+ name = L["TargetTargetTarget"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "targettargettarget") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ focusShortcut = {
+ order = 16,
+ type = "execute",
+ name = L["Focus"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "focus") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ focustargetShortcut = {
+ order = 17,
+ type = "execute",
+ name = L["FocusTarget"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "focustarget") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ petShortcut = {
+ order = 18,
+ type = "execute",
+ name = L["PET"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "pet") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ spacer4 = {
+ order = 19,
+ type = "description",
+ name = " "
+ },
+ pettargetShortcut = {
+ order = 20,
+ type = "execute",
+ name = L["PetTarget"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "pettarget") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ arenaShortcut = {
+ order = 21,
+ type = "execute",
+ name = L["ARENA"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "arena") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ bossShortcut = {
+ order = 22,
+ type = "execute",
+ name = L["BOSS"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "boss") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ partyShortcut = {
+ order = 23,
+ type = "execute",
+ name = L["PARTY"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "party") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ spacer6 = {
+ order = 24,
+ type = "description",
+ name = " "
+ },
+ raidShortcut = {
+ order = 25,
+ type = "execute",
+ name = L["RAID"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "raid") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ raid40Shortcut = {
+ order = 26,
+ type = "execute",
+ name = L["Raid-40"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "raid40") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ raidpetShortcut = {
+ order = 29,
+ type = "execute",
+ name = L["Raid Pet"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "raidpet") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ assistShortcut = {
+ order = 30,
+ type = "execute",
+ name = L["Assist"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "assist") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ spacer7 = {
+ order = 31,
+ type = "description",
+ name = " "
+ },
+ tankShortcut = {
+ order = 32,
+ type = "execute",
+ name = L["TANK"],
+ func = function() ACD:SelectGroup("ElvUI", "unitframe", "tank") end,
+ disabled = function() return not E.UnitFrames.Initialized end
+ },
+ generalOptionsGroup = {
+ order = 33,
+ type = "group",
+ name = L["General Options"],
+ childGroups = "tab",
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ generalGroup = {
+ order = 1,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ thinBorders = {
+ order = 2,
+ type = "toggle",
+ name = L["Thin Borders"],
+ desc = L["Use thin borders on certain unitframe elements."],
+ disabled = function() return E.private.general.pixelPerfect end,
+ set = function(info, value) E.db.unitframe[info[#info]] = value E:StaticPopup_Show("CONFIG_RL") end
+ },
+ smartRaidFilter = {
+ order = 3,
+ type = "toggle",
+ name = L["Smart Raid Filter"],
+ desc = L["Override any custom visibility setting in certain situations, EX: Only show groups 1 and 2 inside a 10 man instance."],
+ set = function(info, value) E.db.unitframe[info[#info]] = value UF:UpdateAllHeaders() end
+ },
+ targetOnMouseDown = {
+ order = 4,
+ type = "toggle",
+ name = L["Target On Mouse-Down"],
+ desc = L["Target units on mouse down rather than mouse up. \n\n|cffFF0000Warning: If you are using the addon 'Clique' you may have to adjust your clique settings when changing this."],
+ set = function(info, value) E.db.unitframe[info[#info]] = value E:StaticPopup_Show("CONFIG_RL") end
+ },
+ auraBlacklistModifier = {
+ order = 5,
+ type = "select",
+ name = L["Blacklist Modifier"],
+ desc = L["You need to hold this modifier down in order to blacklist an aura by right-clicking the icon. Set to None to disable the blacklist functionality."],
+ values = {
+ ["NONE"] = L["NONE"],
+ ["SHIFT"] = L["SHIFT_KEY"],
+ ["ALT"] = L["ALT_KEY_TEXT"],
+ ["CTRL"] = L["CTRL_KEY"]
+ }
+ },
+ resetFilters = {
+ order = 6,
+ type = "execute",
+ name = L["Reset Aura Filters"],
+ func = function(info)
+ E:StaticPopup_Show("RESET_UF_AF") --reset unitframe aurafilters
+ end
+ },
+ barGroup = {
+ order = 7,
+ type = "group",
+ guiInline = true,
+ name = L["Bars"],
+ args = {
+ smoothbars = {
+ order = 1,
+ type = "toggle",
+ name = L["Smooth Bars"],
+ desc = L["Bars will transition smoothly."],
+ set = function(info, value) E.db.unitframe[info[#info]] = value UF:Update_AllFrames() end
+ },
+ statusbar = {
+ order = 3,
+ type = "select", dialogControl = "LSM30_Statusbar",
+ name = L["StatusBar Texture"],
+ desc = L["Main statusbar texture."],
+ values = AceGUIWidgetLSMlists.statusbar,
+ set = function(info, value) E.db.unitframe[info[#info]] = value UF:Update_StatusBars() end
+ }
+ }
+ },
+ fontGroup = {
+ order = 8,
+ type = "group",
+ guiInline = true,
+ name = L["Fonts"],
+ args = {
+ font = {
+ order = 4,
+ type = "select", dialogControl = "LSM30_Font",
+ name = L["Default Font"],
+ desc = L["The font that the unitframes will use."],
+ values = AceGUIWidgetLSMlists.font,
+ set = function(info, value) E.db.unitframe[info[#info]] = value UF:Update_FontStrings() end
+ },
+ fontSize = {
+ order = 5,
+ type = "range",
+ name = L["FONT_SIZE"],
+ desc = L["Set the font size for unitframes."],
+ min = 4, max = 32, step = 1,
+ set = function(info, value) E.db.unitframe[info[#info]] = value UF:Update_FontStrings() end
+ },
+ fontOutline = {
+ order = 6,
+ type = "select",
+ name = L["Font Outline"],
+ desc = L["Set the font outline."],
+ values = C.Values.FontFlags,
+ set = function(info, value) E.db.unitframe[info[#info]] = value UF:Update_FontStrings() end
+ }
+ }
+ }
+ }
+ },
+ frameGlowGroup = {
+ order = 2,
+ type = "group",
+ childGroups = "tree",
+ name = L["Frame Glow"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Frame Glow"]
+ },
+ mainGlow = {
+ order = 2,
+ type = "group",
+ guiInline = true,
+ name = L["Mouseover Glow"],
+ get = function(info)
+ local t = E.db.unitframe.colors.frameGlow.mainGlow[info[#info]]
+ if type(t) == "boolean" then return t end
+ local d = P.unitframe.colors.frameGlow.mainGlow[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.db.unitframe.colors.frameGlow.mainGlow[info[#info]]
+ if type(t) == "boolean" then
+ E.db.unitframe.colors.frameGlow.mainGlow[info[#info]] = r
+ else
+ t.r, t.g, t.b, t.a = r, g, b, a
+ end
+ UF:FrameGlow_UpdateFrames()
+ end,
+ disabled = function() return not E.db.unitframe.colors.frameGlow.mainGlow.enable end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ disabled = false
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = ""
+ },
+ class = {
+ order = 3,
+ type = "toggle",
+ name = L["Use Class Color"],
+ desc = L["Alpha channel is taken from the color option."]
+ },
+ color = {
+ order = 4,
+ type = "color",
+ name = L["COLOR"],
+ hasAlpha = true,
+ disabled = function() return not E.db.unitframe.colors.frameGlow.mainGlow.enable or E.db.unitframe.colors.frameGlow.mainGlow.class end
+ }
+ }
+ },
+ targetGlow = {
+ order = 3,
+ type = "group",
+ guiInline = true,
+ name = L["Targeted Glow"],
+ get = function(info)
+ local t = E.db.unitframe.colors.frameGlow.targetGlow[info[#info]]
+ if type(t) == "boolean" then return t end
+ local d = P.unitframe.colors.frameGlow.targetGlow[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.db.unitframe.colors.frameGlow.targetGlow[info[#info]]
+ if type(t) == "boolean" then
+ E.db.unitframe.colors.frameGlow.targetGlow[info[#info]] = r
+ else
+ t.r, t.g, t.b, t.a = r, g, b, a
+ end
+ UF:FrameGlow_UpdateFrames()
+ end,
+ disabled = function() return not E.db.unitframe.colors.frameGlow.targetGlow.enable end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ disabled = false
+ },
+ spacer = {
+ order = 2,
+ type = "description",
+ name = ""
+ },
+ class = {
+ order = 3,
+ type = "toggle",
+ name = L["Use Class Color"],
+ desc = L["Alpha channel is taken from the color option."]
+ },
+ color = {
+ order = 4,
+ type = "color",
+ name = L["COLOR"],
+ hasAlpha = true,
+ disabled = function() return not E.db.unitframe.colors.frameGlow.targetGlow.enable or E.db.unitframe.colors.frameGlow.targetGlow.class end
+ }
+ }
+ },
+ mouseoverGlow = {
+ order = 4,
+ type = "group",
+ guiInline = true,
+ name = L["Mouseover Highlight"],
+ get = function(info)
+ local t = E.db.unitframe.colors.frameGlow.mouseoverGlow[info[#info]]
+ if type(t) == "boolean" then return t end
+ local d = P.unitframe.colors.frameGlow.mouseoverGlow[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.db.unitframe.colors.frameGlow.mouseoverGlow[info[#info]]
+ if type(t) == "boolean" then
+ E.db.unitframe.colors.frameGlow.mouseoverGlow[info[#info]] = r
+ else
+ t.r, t.g, t.b, t.a = r, g, b, a
+ end
+ UF:FrameGlow_UpdateFrames()
+ end,
+ disabled = function() return not E.db.unitframe.colors.frameGlow.mouseoverGlow.enable end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ disabled = false
+ },
+ texture = {
+ order = 2,
+ type = "select",
+ dialogControl = "LSM30_Statusbar",
+ name = L["Texture"],
+ values = AceGUIWidgetLSMlists.statusbar,
+ get = function(info)
+ return E.db.unitframe.colors.frameGlow.mouseoverGlow[info[#info]]
+ end,
+ set = function(info, value)
+ E.db.unitframe.colors.frameGlow.mouseoverGlow[info[#info]] = value
+ UF:FrameGlow_UpdateFrames()
+ end
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ class = {
+ order = 4,
+ type = "toggle",
+ name = L["Use Class Color"],
+ desc = L["Alpha channel is taken from the color option."]
+ },
+ color = {
+ order = 5,
+ type = "color",
+ name = L["COLOR"],
+ hasAlpha = true,
+ disabled = function() return not E.db.unitframe.colors.frameGlow.mouseoverGlow.enable or E.db.unitframe.colors.frameGlow.mouseoverGlow.class end
+ }
+ }
+ }
+ }
+ },
+ allColorsGroup = {
+ order = 3,
+ type = "group",
+ childGroups = "tree",
+ name = L["COLORS"],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["COLORS"]
+ },
+ borderColor = {
+ order = 2,
+ type = "color",
+ name = L["Border Color"],
+ get = function(info)
+ local t = E.db.unitframe.colors.borderColor
+ local d = P.unitframe.colors.borderColor
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors.borderColor
+ t.r, t.g, t.b = r, g, b
+ E:UpdateMedia()
+ E:UpdateBorderColors()
+ end
+ },
+ healthGroup = {
+ order = 3,
+ type = "group",
+ name = L["HEALTH"],
+ get = function(info)
+ local t = E.db.unitframe.colors[info[#info]]
+ local d = P.unitframe.colors[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["HEALTH"]
+ },
+ colorhealthbyvalue = {
+ order = 2,
+ type = "toggle",
+ name = L["Health By Value"],
+ desc = L["Color health by amount remaining."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end,
+ disabled = function() return E.db.unitframe.colors.colorhealthbyvalue_threshold end
+ },
+ healthclass = {
+ order = 3,
+ type = "toggle",
+ name = L["Class Health"],
+ desc = L["Color health by classcolor or reaction."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ forcehealthreaction = {
+ order = 4,
+ type = "toggle",
+ name = L["Force Reaction Color"],
+ desc = L["Forces reaction color instead of class color on units controlled by players."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end,
+ disabled = function() return not E.db.unitframe.colors.healthclass end
+ },
+ --[=[healththreat = {
+ order = 5,
+ type = "toggle",
+ name = L["Threat Health"],
+ desc = L["Color health by threat status."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },]=]
+ transparentHealth = {
+ order = 6,
+ type = "toggle",
+ name = L["Transparent"],
+ desc = L["Make textures transparent."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ spacer1 = {
+ order = 7,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ customhealthbackdrop = {
+ order = 8,
+ type = "toggle",
+ name = L["Custom Backdrop"],
+ desc = L["Use the custom backdrop color instead of a multiple of the main color."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ health_backdrop = {
+ order = 9,
+ type = "color",
+ name = L["Health Backdrop"],
+ disabled = function() return not E.db.unitframe.colors.customhealthbackdrop end
+ },
+ spacer2 = {
+ order = 10,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ useDeadBackdrop = {
+ order = 11,
+ type = "toggle",
+ name = L["Use Dead Backdrop"],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ health_backdrop_dead = {
+ order = 12,
+ type = "color",
+ name = L["Custom Dead Backdrop"],
+ desc = L["Use this backdrop color for units that are dead or ghosts."],
+ customWidth = 250,
+ disabled = function() return not E.db.unitframe.colors.useDeadBackdrop end
+ },
+ spacer3 = {
+ order = 13,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ classbackdrop = {
+ order = 14,
+ type = "toggle",
+ name = L["Class Backdrop"],
+ desc = L["Color the health backdrop by class or reaction."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end,
+ disabled = function() return E.db.unitframe.colors.customhealthbackdrop end
+ },
+ healthMultiplier = {
+ order = 15,
+ type = "range",
+ name = L["Health Backdrop Multiplier"],
+ min = 0, softMax = 0.75, max = 1, step = .01,
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end,
+ disabled = function() return E.db.unitframe.colors.customhealthbackdrop end
+ },
+ spacer4 = {
+ order = 16,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ tapped = {
+ order = 17,
+ type = "color",
+ name = L["Tapped"]
+ },
+ health = {
+ order = 18,
+ type = "color",
+ name = L["HEALTH"]
+ },
+ disconnected = {
+ order = 19,
+ type = "color",
+ name = L["Disconnected"]
+ },
+ spacer5 = {
+ order = 20,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ colorhealthbyvalue_threshold = {
+ order = 21,
+ type = "toggle",
+ name = L["Health By Threshold"],
+ desc = L["Color health by specific thresholds."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end,
+ disabled = function() return E.db.unitframe.colors.colorhealthbyvalue end
+ },
+ colorhealthbyvalue_thresholdgradient = {
+ order = 22,
+ type = "toggle",
+ name = L["Slight Gradient"],
+ desc = L["Allow a small gradient between each threshold"],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end,
+ disabled = function() return not E.db.unitframe.colors.colorhealthbyvalue_threshold end
+ },
+ spacer6 = {
+ order = 23,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ threshold_20 = {
+ order = 24,
+ type = "color",
+ name = L["Threshold 20"]
+ },
+ threshold_35 = {
+ order = 25,
+ type = "color",
+ name = L["Threshold 35"]
+ },
+ threshold_50 = {
+ order = 26,
+ type = "color",
+ name = L["Threshold 50"]
+ },
+ threshold_75 = {
+ order = 27,
+ type = "color",
+ name = L["Threshold 75"]
+ }
+ }
+ },
+ powerGroup = {
+ order = 4,
+ type = "group",
+ name = L["Powers"],
+ get = function(info)
+ local t = E.db.unitframe.colors.power[info[#info]]
+ local d = P.unitframe.colors.power[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors.power[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Powers"]
+ },
+ transparentPower = {
+ order = 2,
+ type = "toggle",
+ name = L["Transparent"],
+ desc = L["Make textures transparent."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ invertPower = {
+ order = 3,
+ type = "toggle",
+ name = L["Invert Colors"],
+ desc = L["Invert foreground and background colors."],
+ disabled = function() return not E.db.unitframe.colors.transparentPower end,
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end,
+ },
+ powerclass = {
+ order = 4,
+ type = "toggle",
+ name = L["Class Power"],
+ desc = L["Color power by classcolor or reaction."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ --[=[powerthreat = {
+ order = 5,
+ type = "toggle",
+ name = L["Threat Power"],
+ desc = L["Color power by threat status."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },]=]
+ spacer2 = {
+ order = 6,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ custompowerbackdrop = {
+ order = 7,
+ type = "toggle",
+ name = L["Custom Backdrop"],
+ desc = L["Use the custom backdrop color instead of a multiple of the main color."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end,
+ },
+ power_backdrop = {
+ order = 8,
+ type = "color",
+ name = L["Custom Backdrop"],
+ desc = L["Use the custom backdrop color instead of a multiple of the main color."],
+ disabled = function() return not E.db.unitframe.colors.custompowerbackdrop end,
+ get = function(info)
+ local t = E.db.unitframe.colors[info[#info]]
+ local d = P.unitframe.colors[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end,
+ },
+ spacer3 = {
+ order = 9,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ MANA = {
+ order = 10,
+ type = "color",
+ name = L["MANA"]
+ },
+ RAGE = {
+ order = 11,
+ type = "color",
+ name = L["RAGE"]
+ },
+ FOCUS = {
+ order = 12,
+ type = "color",
+ name = L["FOCUS"]
+ },
+ ENERGY = {
+ order = 13,
+ type = "color",
+ name = L["ENERGY"]
+ },
+ RUNIC_POWER = {
+ order = 14,
+ type = "color",
+ name = L["RUNIC_POWER"]
+ }
+ }
+ },
+ castBars = {
+ order = 5,
+ type = "group",
+ name = L["Castbar"],
+ get = function(info)
+ local t = E.db.unitframe.colors[info[#info]]
+ local d = P.unitframe.colors[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Castbar"]
+ },
+ transparentCastbar = {
+ order = 2,
+ type = "toggle",
+ name = L["Transparent"],
+ desc = L["Make textures transparent."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ invertCastbar = {
+ order = 3,
+ type = "toggle",
+ name = L["Invert Colors"],
+ desc = L["Invert foreground and background colors."],
+ disabled = function() return not E.db.unitframe.colors.transparentCastbar end,
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ castClassColor = {
+ order = 4,
+ type = "toggle",
+ name = L["Class Castbars"],
+ desc = L["Color castbars by the class of player units."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ castReactionColor = {
+ order = 5,
+ type = "toggle",
+ name = L["Reaction Castbars"],
+ desc = L["Color castbars by the reaction type of non-player units."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ spacer1 = {
+ order = 6,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ customcastbarbackdrop = {
+ order = 7,
+ type = "toggle",
+ name = L["Custom Backdrop"],
+ desc = L["Use the custom backdrop color instead of a multiple of the main color."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ castbar_backdrop = {
+ order = 8,
+ type = "color",
+ name = L["Custom Backdrop"],
+ desc = L["Use the custom backdrop color instead of a multiple of the main color."],
+ disabled = function() return not E.db.unitframe.colors.customcastbarbackdrop end
+ },
+ spacer2 = {
+ order = 9,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ castColor = {
+ order = 10,
+ type = "color",
+ name = L["Interruptable"]
+ },
+ castNoInterrupt = {
+ order = 11,
+ type = "color",
+ name = L["Non-Interruptable"]
+ }
+ }
+ },
+ auraBars = {
+ order = 6,
+ type = "group",
+ name = L["Aura Bars"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Aura Bars"]
+ },
+ transparentAurabars = {
+ order = 2,
+ type = "toggle",
+ name = L["Transparent"],
+ desc = L["Make textures transparent."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ invertAurabars = {
+ order = 3,
+ type = "toggle",
+ name = L["Invert Colors"],
+ desc = L["Invert foreground and background colors."],
+ disabled = function() return not E.db.unitframe.colors.transparentAurabars end,
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end
+ },
+ auraBarByType = {
+ order = 4,
+ type = "toggle",
+ name = L["By Type"],
+ desc = L["Color aurabar debuffs by type."]
+ },
+ auraBarTurtle = {
+ order = 5,
+ type = "toggle",
+ name = L["Color Turtle Buffs"],
+ desc = L["Color all buffs that reduce the unit's incoming damage."]
+ },
+ spacer1 = {
+ order = 6,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ customaurabarbackdrop = {
+ order = 7,
+ type = "toggle",
+ name = L["Custom Backdrop"],
+ desc = L["Use the custom backdrop color instead of a multiple of the main color."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end,
+ },
+ aurabar_backdrop = {
+ order = 8,
+ type = "color",
+ name = L["Custom Backdrop"],
+ desc = L["Use the custom backdrop color instead of a multiple of the main color."],
+ disabled = function() return not E.db.unitframe.colors.customaurabarbackdrop end,
+ get = function(info)
+ local t = E.db.unitframe.colors[info[#info]]
+ local d = P.unitframe.colors[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end,
+ },
+ spacer2 = {
+ order = 9,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ BUFFS = {
+ order = 10,
+ type = "color",
+ name = L["Buffs"],
+ get = function(info)
+ local t = E.db.unitframe.colors.auraBarBuff
+ local d = P.unitframe.colors.auraBarBuff
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors.auraBarBuff
+ t.r, t.g, t.b = r, g, b
+
+ UF:Update_AllFrames()
+ end
+ },
+ DEBUFFS = {
+ order = 11,
+ type = "color",
+ name = L["Debuffs"],
+ get = function(info)
+ local t = E.db.unitframe.colors.auraBarDebuff
+ local d = P.unitframe.colors.auraBarDebuff
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors.auraBarDebuff
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end
+ },
+ auraBarTurtleColor = {
+ order = 12,
+ type = "color",
+ name = L["Turtle Color"],
+ get = function(info)
+ local t = E.db.unitframe.colors.auraBarTurtleColor
+ local d = P.unitframe.colors.auraBarTurtleColor
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors.auraBarTurtleColor
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end
+ }
+ }
+ },
+ reactionGroup = {
+ order = 7,
+ type = "group",
+ name = L["Reactions"],
+ get = function(info)
+ local t = E.db.unitframe.colors.reaction[info[#info]]
+ local d = P.unitframe.colors.reaction[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors.reaction[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Reactions"]
+ },
+ BAD = {
+ order = 2,
+ type = "color",
+ name = L["Bad"]
+ },
+ NEUTRAL = {
+ order = 3,
+ type = "color",
+ name = L["Neutral"]
+ },
+ GOOD = {
+ order = 4,
+ type = "color",
+ name = L["Good"]
+ }
+ }
+ },
+ --[[threatGroup = {
+ order = 8,
+ type = "group",
+ name = L["Threat"],
+ get = function(info)
+ local n = tonumber(info[#info])
+ local t = E.db.unitframe.colors.threat[n]
+ local d = P.unitframe.colors.threat[n]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local n = tonumber(info[#info])
+ local t = E.db.unitframe.colors.threat[n]
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end,
+ args = {
+ ["0"] = {
+ order = 1,
+ type = "color",
+ name = L["Low Threat"]
+ },
+ ["1"] = {
+ order = 2,
+ type = "color",
+ name = L["Overnuking"]
+ },
+ ["2"] = {
+ order = 3,
+ type = "color",
+ name = L["Losing Threat"]
+ },
+ ["3"] = {
+ order = 4,
+ type = "color",
+ name = L["Securely Tanking"]
+ }
+ }
+ },]]
+ healPrediction = {
+ order = 8,
+ type = "group",
+ name = L["Heal Prediction"],
+ get = function(info)
+ local t = E.db.unitframe.colors.healPrediction[info[#info]]
+ local d = P.unitframe.colors.healPrediction[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.db.unitframe.colors.healPrediction[info[#info]]
+ t.r, t.g, t.b, t.a = r, g, b, a
+ UF:Update_AllFrames()
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Heal Prediction"]
+ },
+ personal = {
+ order = 2,
+ type = "color",
+ name = L["Personal"],
+ hasAlpha = true
+ },
+ others = {
+ order = 3,
+ type = "color",
+ name = L["Others"],
+ hasAlpha = true
+ },
+ maxOverflow = {
+ order = 4,
+ type = "range",
+ name = L["Max Overflow"],
+ desc = L["Max amount of overflow allowed to extend past the end of the health bar."],
+ isPercent = true,
+ min = 0, max = 1, step = 0.01,
+ get = function(info) return E.db.unitframe.colors.healPrediction.maxOverflow end,
+ set = function(info, value) E.db.unitframe.colors.healPrediction.maxOverflow = value UF:Update_AllFrames() end
+ }
+ }
+ },
+ debuffHighlight = {
+ order = 9,
+ type = "group",
+ name = L["Debuff Highlighting"],
+ get = function(info)
+ local t = E.db.unitframe.colors.debuffHighlight[info[#info]]
+ local d = P.unitframe.colors.debuffHighlight[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(info, r, g, b, a)
+ local t = E.db.unitframe.colors.debuffHighlight[info[#info]]
+ t.r, t.g, t.b, t.a = r, g, b, a
+ UF:Update_AllFrames()
+ end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Debuff Highlighting"]
+ },
+ debuffHighlighting = {
+ order = 2,
+ type = "select",
+ name = L["Debuff Highlighting"],
+ desc = L["Color the unit healthbar if there is a debuff that can be dispelled by you."],
+ get = function(info) return E.db.unitframe[info[#info]] end,
+ set = function(info, value) E.db.unitframe[info[#info]] = value end,
+ values = {
+ ["NONE"] = L["NONE"],
+ ["GLOW"] = L["Glow"],
+ ["FILL"] = L["Fill"]
+ }
+ },
+ blendMode = {
+ order = 3,
+ type = "select",
+ name = L["Blend Mode"],
+ values = blendModeValues,
+ get = function(info) return E.db.unitframe.colors.debuffHighlight[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors.debuffHighlight[info[#info]] = value UF:Update_AllFrames() end
+ },
+ spacer1 = {
+ order = 4,
+ type = "description",
+ name = " ",
+ width = "full"
+ },
+ Magic = {
+ order = 5,
+ type = "color",
+ name = L["Magic Effect"],
+ hasAlpha = true
+ },
+ Curse = {
+ order = 6,
+ type = "color",
+ name = L["Curse Effect"],
+ hasAlpha = true
+ },
+ Disease = {
+ order = 7,
+ type = "color",
+ name = L["Disease Effect"],
+ hasAlpha = true
+ },
+ Poison = {
+ order = 8,
+ type = "color",
+ name = L["Poison Effect"],
+ hasAlpha = true
+ }
+ }
+ }
+ }
+ },
+ disabledBlizzardFrames = {
+ order = 4,
+ type = "group",
+ name = L["Disabled Blizzard Frames"],
+ get = function(info) return E.private.unitframe.disabledBlizzardFrames[info[#info]] end,
+ set = function(info, value) E.private.unitframe.disabledBlizzardFrames[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Disabled Blizzard Frames"]
+ },
+ player = {
+ order = 2,
+ type = "toggle",
+ name = L["Player"],
+ desc = L["Disables the player and pet unitframes."]
+ },
+ target = {
+ order = 3,
+ type = "toggle",
+ name = L["TARGET"],
+ desc = L["Disables the target and target of target unitframes."]
+ },
+ focus = {
+ order = 4,
+ type = "toggle",
+ name = L["Focus"],
+ desc = L["Disables the focus and target of focus unitframes."]
+ },
+ boss = {
+ order = 5,
+ type = "toggle",
+ name = L["BOSS"]
+ },
+ arena = {
+ order = 6,
+ type = "toggle",
+ name = L["Arena"]
+ },
+ party = {
+ order = 7,
+ type = "toggle",
+ name = L["PARTY"]
+ }
+ }
+ },
+ raidDebuffIndicator = {
+ order = 5,
+ type = "group",
+ name = L["RaidDebuff Indicator"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["RaidDebuff Indicator"],
+ },
+ instanceFilter = {
+ order = 2,
+ type = "select",
+ name = L["Dungeon & Raid Filter"],
+ values = function()
+ local filters = {}
+ local list = E.global.unitframe.aurafilters
+ if not list then return end
+ for filter in pairs(list) do
+ filters[filter] = filter
+ end
+
+ return filters
+ end,
+ get = function(info) return E.global.unitframe.raidDebuffIndicator.instanceFilter end,
+ set = function(info, value) E.global.unitframe.raidDebuffIndicator.instanceFilter = value UF:UpdateAllHeaders() end
+ },
+ otherFilter = {
+ order = 3,
+ type = "select",
+ name = L["Other Filter"],
+ values = function()
+ local filters = {}
+ local list = E.global.unitframe.aurafilters
+ if not list then return end
+ for filter in pairs(list) do
+ filters[filter] = filter
+ end
+
+ return filters
+ end,
+ get = function(info) return E.global.unitframe.raidDebuffIndicator.otherFilter end,
+ set = function(info, value) E.global.unitframe.raidDebuffIndicator.otherFilter = value UF:UpdateAllHeaders() end
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+--Player
+E.Options.args.unitframe.args.player = {
+ order = 300,
+ type = "group",
+ name = L["Player"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.player[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.player[info[#info]] = value UF:CreateAndUpdateUF("player") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ set = function(info, value)
+ E.db.unitframe.units.player[info[#info]] = value
+ UF:CreateAndUpdateUF("player")
+ end
+ },
+ showAuras = {
+ order = 2,
+ type = "execute",
+ name = L["Show Auras"],
+ func = function()
+ local frame = ElvUF_Player
+ if frame.forceShowAuras then
+ frame.forceShowAuras = nil
+ else
+ frame.forceShowAuras = true
+ end
+
+ UF:CreateAndUpdateUF("player")
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["Player"], nil, {unit="player", mover="Player Frame"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = UF.units,
+ set = function(info, value) UF:MergeUnitSettings(value, "player") end
+ },
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 2,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1,
+ set = function(info, value)
+ if E.db.unitframe.units.player.castbar.width == E.db.unitframe.units.player[info[#info]] then
+ E.db.unitframe.units.player.castbar.width = value
+ end
+
+ E.db.unitframe.units.player[info[#info]] = value
+ UF:CreateAndUpdateUF("player")
+ end
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ hideonnpc = {
+ order = 4,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.player.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.player.power.hideonnpc = value UF:CreateAndUpdateUF("player") end
+ },
+ threatStyle = {
+ order = 5,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ smartAuraPosition = {
+ order = 6,
+ type = "select",
+ name = L["Smart Aura Position"],
+ desc = L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."],
+ values = smartAuraPositionValues
+ },
+ orientation = {
+ order = 7,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 10,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 11,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ healPredction = GetOptionsTable_HealPrediction(UF.CreateAndUpdateUF, "player"),
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateUF, "player"),
+ health = GetOptionsTable_Health(false, UF.CreateAndUpdateUF, "player"),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateUF, "player"),
+ power = GetOptionsTable_Power(true, UF.CreateAndUpdateUF, "player", nil, true),
+ energy = GetOptionsTable_Energy(true, UF.CreateAndUpdateUF, "player", nil, true),
+ rage = GetOptionsTable_Rage(true, UF.CreateAndUpdateUF, "player", nil, true),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateUF, "player"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateUF, "player"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateUF, "player"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateUF, "player"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateUF, "player"),
+ castbar = GetOptionsTable_Castbar(true, UF.CreateAndUpdateUF, "player"),
+ aurabar = GetOptionsTable_AuraBars(UF.CreateAndUpdateUF, "player"),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateUF, "player"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateUF, "player"),
+ classbar = {
+ order = 750,
+ type = "group",
+ name = L["Classbar"],
+ get = function(info) return E.db.unitframe.units.player.classbar[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.player.classbar[info[#info]] = value UF:CreateAndUpdateUF("player") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Classbar"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = ((E.db.unitframe.thinBorders or E.PixelMode) and 3 or 7),
+ max = (E.db.unitframe.units.player.classbar.detachFromFrame and 300 or 30),
+ step = 1,
+ disabled = function() return not E.db.unitframe.units.player.classbar.enable end
+ },
+ fill = {
+ order = 4,
+ type = "select",
+ name = L["Fill"],
+ values = {
+ ["fill"] = L["Filled"],
+ ["spaced"] = L["Spaced"]
+ },
+ disabled = function() return not E.db.unitframe.units.player.classbar.enable end
+ },
+ autoHide = {
+ order = 5,
+ type = "toggle",
+ name = L["Auto-Hide"],
+ disabled = function() return not E.db.unitframe.units.player.classbar.enable end
+ },
+ additionalPowerText = {
+ order = 6,
+ type = "toggle",
+ name = L["Additional Power Text"],
+ hidden = function() return false end,
+ disabled = function() return not E.db.unitframe.units.player.classbar.enable end
+ },
+ spacer = {
+ order = 7,
+ type = "description",
+ name = ""
+ },
+ detachGroup = {
+ order = 8,
+ type = "group",
+ name = L["Detach From Frame"],
+ get = function(info) return E.db.unitframe.units.player.classbar[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.player.classbar[info[#info]] = value UF:CreateAndUpdateUF("player") end,
+ guiInline = true,
+ args = {
+ detachFromFrame = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ width = "full",
+ set = function(info, value)
+ if value == true then
+ E.Options.args.unitframe.args.player.args.classbar.args.height.max = 300
+ else
+ E.Options.args.unitframe.args.player.args.classbar.args.height.max = 30
+ end
+ E.db.unitframe.units.player.classbar[info[#info]] = value
+ UF:CreateAndUpdateUF("player")
+ end,
+ disabled = function() return not E.db.unitframe.units.player.classbar.enable end
+ },
+ detachedWidth = {
+ order = 2,
+ type = "range",
+ name = L["Detached Width"],
+ disabled = function() return not E.db.unitframe.units.player.classbar.detachFromFrame or not E.db.unitframe.units.player.classbar.enable end,
+ min = ((E.db.unitframe.thinBorders or E.PixelMode) and 3 or 7), max = 800, step = 1
+ },
+ orientation = {
+ order = 3,
+ type = "select",
+ name = L["Frame Orientation"],
+ disabled = function()
+ return (E.db.unitframe.units.player.classbar.fill and (E.db.unitframe.units.player.classbar.fill == "fill"))
+ or not E.db.unitframe.units.player.classbar.detachFromFrame
+ or not E.db.unitframe.units.player.classbar.enable
+ end,
+ values = {
+ ["HORIZONTAL"] = L["Horizontal"],
+ ["VERTICAL"] = L["Vertical"]
+ }
+ },
+ verticalOrientation = {
+ order = 4,
+ type = "toggle",
+ name = L["Vertical Fill Direction"],
+ disabled = function() return not E.db.unitframe.units.player.classbar.detachFromFrame or not E.db.unitframe.units.player.classbar.enable end
+ },
+ spacing = {
+ order = 5,
+ type = "range",
+ name = L["Spacing"],
+ min = ((E.db.unitframe.thinBorders or E.PixelMode) and -1 or -4), max = 20, step = 1,
+ disabled = function()
+ return E.db.unitframe.units.player.classbar.fill and (E.db.unitframe.units.player.classbar.fill == "fill")
+ or not E.db.unitframe.units.player.classbar.detachFromFrame
+ or not E.db.unitframe.units.player.classbar.enable
+ end
+ },
+ parent = {
+ order = 6,
+ type = "select",
+ name = L["Parent"],
+ desc = L["Choose UIPARENT to prevent it from hiding with the unitframe."],
+ disabled = function() return not E.db.unitframe.units.player.classbar.detachFromFrame or not E.db.unitframe.units.player.classbar.enable end,
+ values = {
+ ["FRAME"] = "FRAME",
+ ["UIPARENT"] = "UIPARENT"
+ }
+ },
+ strataAndLevel = {
+ order = 7,
+ type = "group",
+ name = L["Strata and Level"],
+ get = function(info) return E.db.unitframe.units.player.classbar.strataAndLevel[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.player.classbar.strataAndLevel[info[#info]] = value UF:CreateAndUpdateUF("player") end,
+ guiInline = true,
+ disabled = function() return not E.db.unitframe.units.player.classbar.detachFromFrame end,
+ hidden = function() return not E.db.unitframe.units.player.classbar.detachFromFrame end,
+ args = {
+ useCustomStrata = {
+ order = 1,
+ type = "toggle",
+ name = L["Use Custom Strata"],
+ disabled = function() return not E.db.unitframe.units.player.classbar.enable end
+ },
+ frameStrata = {
+ order = 2,
+ type = "select",
+ name = L["Frame Strata"],
+ values = {
+ ["BACKGROUND"] = "BACKGROUND",
+ ["LOW"] = "LOW",
+ ["MEDIUM"] = "MEDIUM",
+ ["HIGH"] = "HIGH",
+ ["DIALOG"] = "DIALOG",
+ ["TOOLTIP"] = "TOOLTIP"
+ },
+ disabled = function() return not E.db.unitframe.units.player.classbar.enable end
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ useCustomLevel = {
+ order = 4,
+ type = "toggle",
+ name = L["Use Custom Level"],
+ disabled = function() return not E.db.unitframe.units.player.classbar.enable end
+ },
+ frameLevel = {
+ order = 5,
+ type = "range",
+ name = L["Frame Level"],
+ min = 2, max = 128, step = 1,
+ disabled = function() return not E.db.unitframe.units.player.classbar.enable end
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ RestIcon = {
+ order = 430,
+ type = "group",
+ name = L["Rest Icon"],
+ get = function(info) return E.db.unitframe.units.player.RestIcon[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.player.RestIcon[info[#info]] = value UF:CreateAndUpdateUF("player") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Rest Icon"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ defaultColor = {
+ order = 3,
+ type = "toggle",
+ name = L["Default Color"]
+ },
+ color = {
+ order = 4,
+ type = "color",
+ name = L["COLOR"],
+ hasAlpha = true,
+ disabled = function()
+ return E.db.unitframe.units.player.RestIcon.defaultColor
+ end,
+ get = function()
+ local c = E.db.unitframe.units.player.RestIcon.color
+ local d = P.unitframe.units.player.RestIcon.color
+ return c.r, c.g, c.b, c.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(_, r, g, b, a)
+ local c = E.db.unitframe.units.player.RestIcon.color
+ c.r, c.g, c.b, c.a = r, g, b, a
+ UF:CreateAndUpdateUF("player")
+ end
+ },
+ size = {
+ order = 5,
+ type = "range",
+ name = L["Size"],
+ min = 10, max = 60, step = 1
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ spacer2 = {
+ order = 8,
+ type = "description",
+ name = " "
+ },
+ anchorPoint = {
+ order = 9,
+ type = "select",
+ name = L["Anchor Point"],
+ values = positionValues
+ },
+ texture = {
+ order = 10,
+ type = "select",
+ sortByValue = true,
+ name = L["Texture"],
+ values = {
+ ["CUSTOM"] = L["CUSTOM"],
+ ["DEFAULT"] = L["DEFAULT"],
+ ["RESTING"] = E:TextureString(E.Media.Textures.Resting, ":14"),
+ ["RESTING1"] = E:TextureString(E.Media.Textures.Resting1, ":14")
+ }
+ },
+ customTexture = {
+ order = 11,
+ type = "input",
+ customWidth = 250,
+ name = L["Custom Texture"],
+ disabled = function()
+ return E.db.unitframe.units.player.RestIcon.texture ~= "CUSTOM"
+ end,
+ set = function(_, value)
+ E.db.unitframe.units.player.RestIcon.customTexture = (value and (not value:match("^%s-$")) and value) or nil
+ UF:CreateAndUpdateUF("player")
+ end
+ }
+ }
+ },
+ CombatIcon = {
+ order = 440,
+ type = "group",
+ name = L["Combat Icon"],
+ get = function(info) return E.db.unitframe.units.player.CombatIcon[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.player.CombatIcon[info[#info]] = value UF:CreateAndUpdateUF("player") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Combat Icon"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ defaultColor = {
+ order = 3,
+ type = "toggle",
+ name = L["Default Color"]
+ },
+ color = {
+ order = 4,
+ type = "color",
+ name = L["COLOR"],
+ hasAlpha = true,
+ disabled = function()
+ return E.db.unitframe.units.player.CombatIcon.defaultColor
+ end,
+ get = function()
+ local c = E.db.unitframe.units.player.CombatIcon.color
+ local d = P.unitframe.units.player.CombatIcon.color
+ return c.r, c.g, c.b, c.a, d.r, d.g, d.b, d.a
+ end,
+ set = function(_, r, g, b, a)
+ local c = E.db.unitframe.units.player.CombatIcon.color
+ c.r, c.g, c.b, c.a = r, g, b, a
+ UF:CreateAndUpdateUF("player")
+ end
+ },
+ size = {
+ order = 5,
+ type = "range",
+ name = L["Size"],
+ min = 10, max = 60, step = 1
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ spacer2 = {
+ order = 8,
+ type = "description",
+ name = " "
+ },
+ anchorPoint = {
+ order = 9,
+ type = "select",
+ name = L["Anchor Point"],
+ values = positionValues
+ },
+ texture = {
+ order = 10,
+ type = "select",
+ sortByValue = true,
+ name = L["Texture"],
+ values = {
+ ["CUSTOM"] = L["CUSTOM"],
+ ["DEFAULT"] = L["DEFAULT"],
+ ["COMBAT"] = E:TextureString(E.Media.Textures.Combat, ":14"),
+ --["PLATINUM"] = [[|TInterface\Challenges\ChallengeMode_Medal_Platinum:14|t]],
+ ["ATTACK"] = [[|TInterface\CURSOR\Attack:14|t]],
+ ["ALERT"] = [[|TInterface\DialogFrame\UI-Dialog-Icon-AlertNew:14|t]],
+ ["ALERT2"] = [[|TInterface\OptionsFrame\UI-OptionsFrame-NewFeatureIcon:14|t]],
+ ["ARTHAS"] =[[|TInterface\LFGFRAME\UI-LFR-PORTRAIT:14|t]],
+ ["SKULL"] = [[|TInterface\LootFrame\LootPanel-Icon:14|t]]
+ }
+ },
+ customTexture = {
+ order = 11,
+ type = "input",
+ customWidth = 250,
+ name = L["Custom Texture"],
+ disabled = function()
+ return E.db.unitframe.units.player.CombatIcon.texture ~= "CUSTOM"
+ end,
+ set = function(_, value)
+ E.db.unitframe.units.player.CombatIcon.customTexture = (value and (not value:match("^%s-$")) and value) or nil
+ UF:CreateAndUpdateUF("player")
+ end
+ }
+ }
+ },
+ pvpIcon = {
+ order = 449,
+ type = "group",
+ name = L["PvP Icon"],
+ get = function(info) return E.db.unitframe.units.player.pvpIcon[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.player.pvpIcon[info[#info]] = value UF:CreateAndUpdateUF("player") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["PvP Icon"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ scale = {
+ order = 3,
+ type = "range",
+ name = L["Scale"],
+ isPercent = true,
+ min = 0.1, max = 2, step = 0.01
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ anchorPoint = {
+ order = 5,
+ type = "select",
+ name = L["Anchor Point"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -100, max = 100, step = 1
+ }
+ }
+ },
+ pvpText = {
+ order = 850,
+ type = "group",
+ name = L["PvP Text"],
+ get = function(info) return E.db.unitframe.units.player.pvp[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.player.pvp[info[#info]] = value UF:CreateAndUpdateUF("player") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["PvP Text"]
+ },
+ position = {
+ order = 2,
+ type = "select",
+ name = L["Position"],
+ values = positionValues
+ },
+ text_format = {
+ order = 100,
+ type = "input",
+ name = L["Text Format"],
+ desc = L["TEXT_FORMAT_DESC"],
+ width = "full"
+ }
+ }
+ },
+ raidRoleIcons = {
+ order = 703,
+ type = "group",
+ name = L["RL / ML Icons"],
+ get = function(info) return E.db.unitframe.units.player.raidRoleIcons[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.player.raidRoleIcons[info[#info]] = value UF:CreateAndUpdateUF("player") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["RL / ML Icons"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ position = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOPLEFT"] = "TOPLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT"
+ }
+ }
+ }
+ }
+ }
+}
+
+--Target Frame
+E.Options.args.unitframe.args.target = {
+ order = 400,
+ type = "group",
+ name = L["TARGET"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.target[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.target[info[#info]] = value UF:CreateAndUpdateUF("target") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ showAuras = {
+ order = 2,
+ type = "execute",
+ name = L["Show Auras"],
+ func = function()
+ local frame = ElvUF_Target
+ if frame.forceShowAuras then
+ frame.forceShowAuras = nil
+ else
+ frame.forceShowAuras = true
+ end
+
+ UF:CreateAndUpdateUF("target")
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["TARGET"], nil, {unit="target", mover="Target Frame"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = UF.units,
+ set = function(info, value) UF:MergeUnitSettings(value, "target") end
+ },
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 6,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1,
+ set = function(info, value)
+ if E.db.unitframe.units.target.castbar.width == E.db.unitframe.units.target[info[#info]] then
+ E.db.unitframe.units.target.castbar.width = value
+ end
+
+ E.db.unitframe.units.target[info[#info]] = value
+ UF:CreateAndUpdateUF("target")
+ end
+ },
+ height = {
+ order = 7,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ hideonnpc = {
+ order = 8,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.target.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.target.power.hideonnpc = value UF:CreateAndUpdateUF("target") end
+ },
+ middleClickFocus = {
+ order = 9,
+ type = "toggle",
+ name = L["Middle Click - Set Focus"],
+ desc = L["Middle clicking the unit frame will cause your focus to match the unit."],
+ disabled = function() return IsAddOnLoaded("Clique") end
+ },
+ threatStyle = {
+ order = 10,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ smartAuraPosition = {
+ order = 11,
+ type = "select",
+ name = L["Smart Aura Position"],
+ desc = L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."],
+ values = smartAuraPositionValues
+ },
+ orientation = {
+ order = 12,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 15,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 16,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ healPredction = GetOptionsTable_HealPrediction(UF.CreateAndUpdateUF, "target"),
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateUF, "target"),
+ health = GetOptionsTable_Health(false, UF.CreateAndUpdateUF, "target"),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateUF, "target"),
+ power = GetOptionsTable_Power(true, UF.CreateAndUpdateUF, "target", nil, true),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateUF, "target"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateUF, "target"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateUF, "target"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateUF, "target"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateUF, "target"),
+ castbar = GetOptionsTable_Castbar(false, UF.CreateAndUpdateUF, "target"),
+ aurabar = GetOptionsTable_AuraBars(UF.CreateAndUpdateUF, "target"),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateUF, "target"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateUF, "target"),
+ GPSArrow = GetOptionsTableForNonGroup_GPS("target"),
+ combobar = {
+ order = 850,
+ type = "group",
+ name = L["COMBO_POINTS"],
+ get = function(info) return E.db.unitframe.units.target.combobar[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.target.combobar[info[#info]] = value UF:CreateAndUpdateUF("target") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["COMBO_POINTS"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = ((E.db.unitframe.thinBorders or E.PixelMode) and 3 or 7),
+ max = (E.db.unitframe.units.target.combobar.detachFromFrame and 300 or 30),
+ step = 1,
+ disabled = function() return not E.db.unitframe.units.target.combobar.enable end
+ },
+ fill = {
+ order = 4,
+ type = "select",
+ name = L["Fill"],
+ values = {
+ ["fill"] = L["Filled"],
+ ["spaced"] = L["Spaced"]
+ },
+ disabled = function() return not E.db.unitframe.units.target.combobar.enable end
+ },
+ autoHide = {
+ order = 5,
+ type = "toggle",
+ name = L["Auto-Hide"],
+ disabled = function() return not E.db.unitframe.units.target.combobar.enable end
+ },
+ spacer = {
+ order = 6,
+ type = "description",
+ name = ""
+ },
+ detachGroup = {
+ order = 8,
+ type = "group",
+ name = L["Detach From Frame"],
+ get = function(info) return E.db.unitframe.units.target.combobar[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.target.combobar[info[#info]] = value UF:CreateAndUpdateUF("target") end,
+ guiInline = true,
+ args = {
+ detachFromFrame = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"],
+ width = "full",
+ set = function(info, value)
+ if value == true then
+ E.Options.args.unitframe.args.target.args.combobar.args.height.max = 300
+ else
+ E.Options.args.unitframe.args.target.args.combobar.args.height.max = 30
+ end
+ E.db.unitframe.units.target.combobar[info[#info]] = value
+ UF:CreateAndUpdateUF("target")
+ end,
+ disabled = function() return not E.db.unitframe.units.target.combobar.enable end
+ },
+ detachedWidth = {
+ order = 2,
+ type = "range",
+ name = L["Detached Width"],
+ disabled = function() return not E.db.unitframe.units.target.combobar.detachFromFrame or not E.db.unitframe.units.target.combobar.enable end,
+ min = ((E.db.unitframe.thinBorders or E.PixelMode) and 3 or 7), max = 800, step = 1
+ },
+ orientation = {
+ order = 3,
+ type = "select",
+ name = L["Frame Orientation"],
+ disabled = function()
+ return (E.db.unitframe.units.target.combobar.fill and (E.db.unitframe.units.target.combobar.fill == "fill"))
+ or not E.db.unitframe.units.target.combobar.detachFromFrame
+ or not E.db.unitframe.units.target.combobar.enable
+ end,
+ values = {
+ ["HORIZONTAL"] = L["Horizontal"],
+ ["VERTICAL"] = L["Vertical"]
+ }
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = ""
+ },
+ spacing = {
+ order = 5,
+ type = "range",
+ name = L["Spacing"],
+ min = ((E.db.unitframe.thinBorders or E.PixelMode) and -1 or -4), max = 20, step = 1,
+ disabled = function()
+ return (E.db.unitframe.units.target.combobar.fill and (E.db.unitframe.units.target.combobar.fill == "fill"))
+ or not E.db.unitframe.units.target.combobar.detachFromFrame
+ or not E.db.unitframe.units.target.combobar.enable
+ end
+ },
+ parent = {
+ order = 6,
+ type = "select",
+ name = L["Parent"],
+ desc = L["Choose UIPARENT to prevent it from hiding with the unitframe."],
+ disabled = function() return not E.db.unitframe.units.target.combobar.detachFromFrame or not E.db.unitframe.units.target.combobar.enable end,
+ values = {
+ ["FRAME"] = "FRAME",
+ ["UIPARENT"] = "UIPARENT"
+ }
+ },
+ strataAndLevel = {
+ order = 7,
+ type = "group",
+ name = L["Strata and Level"],
+ get = function(info) return E.db.unitframe.units.target.combobar.strataAndLevel[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.target.combobar.strataAndLevel[info[#info]] = value UF:CreateAndUpdateUF("target") end,
+ guiInline = true,
+ disabled = function() return not E.db.unitframe.units.target.combobar.detachFromFrame end,
+ hidden = function() return not E.db.unitframe.units.target.combobar.detachFromFrame end,
+ args = {
+ useCustomStrata = {
+ order = 1,
+ type = "toggle",
+ name = L["Use Custom Strata"],
+ disabled = function() return not E.db.unitframe.units.target.combobar.enable end
+ },
+ frameStrata = {
+ order = 2,
+ type = "select",
+ name = L["Frame Strata"],
+ values = {
+ ["BACKGROUND"] = "BACKGROUND",
+ ["LOW"] = "LOW",
+ ["MEDIUM"] = "MEDIUM",
+ ["HIGH"] = "HIGH",
+ ["DIALOG"] = "DIALOG",
+ ["TOOLTIP"] = "TOOLTIP"
+ },
+ disabled = function() return not E.db.unitframe.units.target.combobar.enable end
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = ""
+ },
+ useCustomLevel = {
+ order = 4,
+ type = "toggle",
+ name = L["Use Custom Level"],
+ disabled = function() return not E.db.unitframe.units.target.combobar.enable end
+ },
+ frameLevel = {
+ order = 5,
+ type = "range",
+ name = L["Frame Level"],
+ min = 2, max = 128, step = 1,
+ disabled = function() return not E.db.unitframe.units.target.combobar.enable end
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ pvpIcon = {
+ order = 449,
+ type = "group",
+ name = L["PvP Icon"],
+ get = function(info) return E.db.unitframe.units.target.pvpIcon[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.target.pvpIcon[info[#info]] = value UF:CreateAndUpdateUF("target") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["PvP Icon"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ scale = {
+ order = 3,
+ type = "range",
+ name = L["Scale"],
+ isPercent = true,
+ min = 0.1, max = 2, step = 0.01
+ },
+ spacer = {
+ order = 4,
+ type = "description",
+ name = " "
+ },
+ anchorPoint = {
+ order = 5,
+ type = "select",
+ name = L["Anchor Point"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ min = -100, max = 100, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -100, max = 100, step = 1
+ }
+ }
+ }
+ }
+}
+
+--TargetTarget
+E.Options.args.unitframe.args.targettarget = {
+ order = 500,
+ type = "group",
+ name = L["TargetTarget"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.targettarget[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.targettarget[info[#info]] = value UF:CreateAndUpdateUF("targettarget") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ showAuras = {
+ order = 2,
+ type = "execute",
+ name = L["Show Auras"],
+ func = function()
+ local frame = ElvUF_TargetTarget
+ if frame.forceShowAuras then
+ frame.forceShowAuras = nil
+ else
+ frame.forceShowAuras = true
+ end
+
+ UF:CreateAndUpdateUF("targettarget")
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["TargetTarget"], nil, {unit="targettarget", mover="TargetTarget Frame"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = UF.units,
+ set = function(info, value) UF:MergeUnitSettings(value, "targettarget") end
+ },
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 2,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ hideonnpc = {
+ order = 4,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.targettarget.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.targettarget.power.hideonnpc = value UF:CreateAndUpdateUF("targettarget") end
+ },
+ threatStyle = {
+ order = 5,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ smartAuraPosition = {
+ order = 6,
+ type = "select",
+ name = L["Smart Aura Position"],
+ desc = L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."],
+ values = smartAuraPositionValues
+ },
+ orientation = {
+ order = 7,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 10,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 11,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateUF, "targettarget"),
+ health = GetOptionsTable_Health(false, UF.CreateAndUpdateUF, "targettarget"),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateUF, "targettarget"),
+ power = GetOptionsTable_Power(nil, UF.CreateAndUpdateUF, "targettarget"),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateUF, "targettarget"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateUF, "targettarget"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateUF, "targettarget"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateUF, "targettarget"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateUF, "targettarget"),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateUF, "targettarget"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateUF, "targettarget")
+ }
+}
+
+--TargetTargetTarget
+E.Options.args.unitframe.args.targettargettarget = {
+ order = 550,
+ type = "group",
+ name = L["TargetTargetTarget"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.targettargettarget[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.targettargettarget[info[#info]] = value UF:CreateAndUpdateUF("targettargettarget") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ showAuras = {
+ order = 2,
+ type = "execute",
+ name = L["Show Auras"],
+ func = function()
+ local frame = ElvUF_TargetTargetTarget
+ if frame.forceShowAuras then
+ frame.forceShowAuras = nil
+ else
+ frame.forceShowAuras = true
+ end
+
+ UF:CreateAndUpdateUF("targettargettarget")
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["TargetTargetTarget"], nil, {unit="targettargettarget", mover="TargetTargetTarget Frame"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = UF.units,
+ set = function(info, value) UF:MergeUnitSettings(value, "targettargettarget") end
+ },
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 2,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ hideonnpc = {
+ order = 4,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.targettargettarget.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.targettargettarget.power.hideonnpc = value UF:CreateAndUpdateUF("targettargettarget") end
+ },
+ threatStyle = {
+ order = 5,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ smartAuraPosition = {
+ order = 6,
+ type = "select",
+ name = L["Smart Aura Position"],
+ desc = L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."],
+ values = smartAuraPositionValues
+ },
+ orientation = {
+ order = 7,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 10,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 11,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateUF, "targettargettarget"),
+ health = GetOptionsTable_Health(false, UF.CreateAndUpdateUF, "targettargettarget"),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateUF, "targettargettarget"),
+ power = GetOptionsTable_Power(nil, UF.CreateAndUpdateUF, "targettargettarget"),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateUF, "targettargettarget"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateUF, "targettargettarget"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateUF, "targettargettarget"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateUF, "targettargettarget"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateUF, "targettargettarget"),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateUF, "targettargettarget"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateUF, "targettargettarget")
+ }
+}
+
+--Focus
+E.Options.args.unitframe.args.focus = {
+ order = 600,
+ type = "group",
+ name = L["Focus"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.focus[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.focus[info[#info]] = value UF:CreateAndUpdateUF("focus") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ showAuras = {
+ order = 2,
+ type = "execute",
+ name = L["Show Auras"],
+ func = function()
+ local frame = ElvUF_Focus
+ if frame.forceShowAuras then
+ frame.forceShowAuras = nil
+ else
+ frame.forceShowAuras = true
+ end
+
+ UF:CreateAndUpdateUF("focus")
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["Focus"], nil, {unit="focus", mover="Focus Frame"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = UF.units,
+ set = function(info, value) UF:MergeUnitSettings(value, "focus") end
+ },
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 2,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ hideonnpc = {
+ order = 4,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.focus.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.focus.power.hideonnpc = value UF:CreateAndUpdateUF("focus") end
+ },
+ threatStyle = {
+ order = 5,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ smartAuraPosition = {
+ order = 6,
+ type = "select",
+ name = L["Smart Aura Position"],
+ desc = L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."],
+ values = smartAuraPositionValues
+ },
+ orientation = {
+ order = 7,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 10,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 11,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ healPredction = GetOptionsTable_HealPrediction(UF.CreateAndUpdateUF, "focus"),
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateUF, "focus"),
+ health = GetOptionsTable_Health(false, UF.CreateAndUpdateUF, "focus"),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateUF, "focus"),
+ power = GetOptionsTable_Power(nil, UF.CreateAndUpdateUF, "focus"),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateUF, "focus"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateUF, "focus"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateUF, "focus"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateUF, "focus"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateUF, "focus"),
+ castbar = GetOptionsTable_Castbar(false, UF.CreateAndUpdateUF, "focus"),
+ aurabar = GetOptionsTable_AuraBars(UF.CreateAndUpdateUF, "focus"),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateUF, "focus"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateUF, "focus"),
+ GPSArrow = GetOptionsTableForNonGroup_GPS("focus")
+ }
+}
+
+--Focus Target
+E.Options.args.unitframe.args.focustarget = {
+ order = 700,
+ type = "group",
+ name = L["FocusTarget"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.focustarget[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.focustarget[info[#info]] = value UF:CreateAndUpdateUF("focustarget") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ showAuras = {
+ order = 2,
+ type = "execute",
+ name = L["Show Auras"],
+ func = function()
+ local frame = ElvUF_FocusTarget
+ if frame.forceShowAuras then
+ frame.forceShowAuras = nil
+ else
+ frame.forceShowAuras = true
+ end
+
+ UF:CreateAndUpdateUF("focustarget")
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["FocusTarget"], nil, {unit="focustarget", mover="FocusTarget Frame"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = UF.units,
+ set = function(info, value) UF:MergeUnitSettings(value, "focustarget") end
+ },
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 6,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1
+ },
+ height = {
+ order = 7,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ hideonnpc = {
+ order = 9,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.focustarget.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.focustarget.power.hideonnpc = value UF:CreateAndUpdateUF("focustarget") end
+ },
+ threatStyle = {
+ order = 10,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ smartAuraPosition = {
+ order = 11,
+ type = "select",
+ name = L["Smart Aura Position"],
+ desc = L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."],
+ values = smartAuraPositionValues
+ },
+ orientation = {
+ order = 12,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 15,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 16,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateUF, "focustarget"),
+ health = GetOptionsTable_Health(false, UF.CreateAndUpdateUF, "focustarget"),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateUF, "focustarget"),
+ power = GetOptionsTable_Power(false, UF.CreateAndUpdateUF, "focustarget"),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateUF, "focustarget"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateUF, "focustarget"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateUF, "focustarget"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateUF, "focustarget"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateUF, "focustarget"),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateUF, "focustarget"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateUF, "focustarget")
+ }
+}
+
+--Pet
+E.Options.args.unitframe.args.pet = {
+ order = 800,
+ type = "group",
+ name = L["PET"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.pet[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.pet[info[#info]] = value UF:CreateAndUpdateUF("pet") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ showAuras = {
+ order = 2,
+ type = "execute",
+ name = L["Show Auras"],
+ func = function()
+ local frame = ElvUF_Pet
+ if frame.forceShowAuras then
+ frame.forceShowAuras = nil
+ else
+ frame.forceShowAuras = true
+ end
+
+ UF:CreateAndUpdateUF("pet")
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["PET"], nil, {unit="pet", mover="Pet Frame"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = UF.units,
+ set = function(info, value) UF:MergeUnitSettings(value, "pet") end
+ },
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 2,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ hideonnpc = {
+ order = 4,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.pet.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.pet.power.hideonnpc = value UF:CreateAndUpdateUF("pet") end
+ },
+ threatStyle = {
+ order = 5,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ smartAuraPosition = {
+ order = 6,
+ type = "select",
+ name = L["Smart Aura Position"],
+ desc = L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."],
+ values = smartAuraPositionValues
+ },
+ orientation = {
+ order = 7,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 10,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 11,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ buffIndicator = {
+ order = 600,
+ type = "group",
+ name = L["Buff Indicator"],
+ get = function(info) return E.db.unitframe.units.pet.buffIndicator[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.pet.buffIndicator[info[#info]] = value UF:CreateAndUpdateUF("pet") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Buff Indicator"],
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ size = {
+ order = 3,
+ type = "range",
+ name = L["Size"],
+ desc = L["Size of the indicator icon."],
+ min = 4, max = 50, step = 1
+ },
+ fontSize = {
+ order = 4,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 7, max = 22, step = 1
+ }
+ }
+ },
+ healPredction = GetOptionsTable_HealPrediction(UF.CreateAndUpdateUF, "pet"),
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateUF, "pet"),
+ health = GetOptionsTable_Health(false, UF.CreateAndUpdateUF, "pet"),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateUF, "pet"),
+ power = GetOptionsTable_Power(false, UF.CreateAndUpdateUF, "pet"),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateUF, "pet"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateUF, "pet"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateUF, "pet"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateUF, "pet"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateUF, "pet"),
+ castbar = GetOptionsTable_Castbar(false, UF.CreateAndUpdateUF, "pet"),
+ aurabar = GetOptionsTable_AuraBars(UF.CreateAndUpdateUF, "pet"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateUF, "pet"),
+ happiness = {
+ order = 700,
+ type = "group",
+ name = HAPPINESS,
+ get = function(info) return E.db.unitframe.units.pet.happiness[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.pet.happiness[info[#info]] = value; UF:CreateAndUpdateUF("pet") end,
+ disabled = false,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["HAPPINESS"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ autoHide = {
+ order = 3,
+ type = "toggle",
+ name = L["Auto-Hide"]
+ },
+ width = {
+ order = 4,
+ type = "range",
+ name = L["Size"],
+ min = 5, max = 40, step = 1
+ }
+ }
+ }
+ }
+}
+
+--Pet Target
+E.Options.args.unitframe.args.pettarget = {
+ order = 900,
+ type = "group",
+ name = L["PetTarget"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.pettarget[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.pettarget[info[#info]] = value UF:CreateAndUpdateUF("pettarget") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ showAuras = {
+ order = 2,
+ type = "execute",
+ name = L["Show Auras"],
+ func = function()
+ local frame = ElvUF_PetTarget
+ if frame.forceShowAuras then
+ frame.forceShowAuras = nil
+ else
+ frame.forceShowAuras = true
+ end
+
+ UF:CreateAndUpdateUF("pettarget")
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["PetTarget"], nil, {unit="pettarget", mover="PetTarget Frame"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = UF.units,
+ set = function(info, value) UF:MergeUnitSettings(value, "pettarget") end
+ },
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 2,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ hideonnpc = {
+ order = 4,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.pettarget.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.pettarget.power.hideonnpc = value UF:CreateAndUpdateUF("pettarget") end
+ },
+ threatStyle = {
+ order = 5,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ smartAuraPosition = {
+ order = 6,
+ type = "select",
+ name = L["Smart Aura Position"],
+ desc = L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."],
+ values = smartAuraPositionValues
+ },
+ orientation = {
+ order = 7,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 10,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 11,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateUF, "pettarget"),
+ health = GetOptionsTable_Health(false, UF.CreateAndUpdateUF, "pettarget"),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateUF, "pettarget"),
+ power = GetOptionsTable_Power(false, UF.CreateAndUpdateUF, "pettarget"),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateUF, "pettarget"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateUF, "pettarget"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateUF, "pettarget"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateUF, "pettarget"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateUF, "pettarget"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateUF, "pettarget")
+ }
+}
+
+--Boss Frames
+E.Options.args.unitframe.args.boss = {
+ order = 1000,
+ type = "group",
+ name = L["BOSS"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.boss[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.boss[info[#info]] = value UF:CreateAndUpdateUFGroup("boss", MAX_BOSS_FRAMES) end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ displayFrames = {
+ order = 2,
+ type = "execute",
+ name = L["Display Frames"],
+ desc = L["Force the frames to show, they will act as if they are the player frame."],
+ func = function() UF:ToggleForceShowGroupFrames("boss", _G.MAX_BOSS_FRAMES) end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["BOSS"], nil, {unit="boss", mover="Boss Frames"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = {
+ ["boss"] = "boss",
+ ["arena"] = "arena"
+ },
+ set = function(info, value) UF:MergeUnitSettings(value, "boss") end
+ },
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 2,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1,
+ set = function(info, value)
+ if E.db.unitframe.units.boss.castbar.width == E.db.unitframe.units.boss[info[#info]] then
+ E.db.unitframe.units.boss.castbar.width = value
+ end
+
+ E.db.unitframe.units.boss[info[#info]] = value
+ UF:CreateAndUpdateUFGroup("boss", MAX_BOSS_FRAMES)
+ end
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ hideonnpc = {
+ order = 4,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.boss.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.boss.power.hideonnpc = value UF:CreateAndUpdateUFGroup("boss", MAX_BOSS_FRAMES) end
+ },
+ growthDirection = {
+ order = 5,
+ type = "select",
+ name = L["Growth Direction"],
+ values = {
+ ["UP"] = L["Bottom to Top"],
+ ["DOWN"] = L["Top to Bottom"],
+ ["LEFT"] = L["Right to Left"],
+ ["RIGHT"] = L["Left to Right"]
+ }
+ },
+ spacing = {
+ order = 6,
+ type = "range",
+ name = L["Spacing"],
+ min = 0, max = 400, step = 1
+ },
+ threatStyle = {
+ order = 7,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ smartAuraPosition = {
+ order = 8,
+ type = "select",
+ name = L["Smart Aura Position"],
+ desc = L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."],
+ values = smartAuraPositionValues
+ },
+ orientation = {
+ order = 9,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 11,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 12,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES),
+ health = GetOptionsTable_Health(false, UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES),
+ power = GetOptionsTable_Power(false, UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES),
+ castbar = GetOptionsTable_Castbar(false, UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateUFGroup, "boss", MAX_BOSS_FRAMES)
+ }
+}
+
+--Arena Frames
+E.Options.args.unitframe.args.arena = {
+ order = 1100,
+ type = "group",
+ name = L["ARENA"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.arena[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.arena[info[#info]] = value UF:CreateAndUpdateUFGroup("arena", 5) end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ displayFrames = {
+ order = 2,
+ type = "execute",
+ name = L["Display Frames"],
+ desc = L["Force the frames to show, they will act as if they are the player frame."],
+ func = function() UF:ToggleForceShowGroupFrames("arena", 5) end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["ARENA"], nil, {unit="arena", mover="Arena Frames"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = {
+ ["boss"] = "boss",
+ ["arena"] = "arena"
+ },
+ set = function(info, value) UF:MergeUnitSettings(value, "arena") end
+ },
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 2,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1,
+ set = function(info, value)
+ if E.db.unitframe.units.arena.castbar.width == E.db.unitframe.units.arena[info[#info]] then
+ E.db.unitframe.units.arena.castbar.width = value
+ end
+
+ E.db.unitframe.units.arena[info[#info]] = value
+ UF:CreateAndUpdateUFGroup("arena", 5)
+ end
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ hideonnpc = {
+ order = 4,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.arena.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.arena.power.hideonnpc = value UF:CreateAndUpdateUFGroup("arena", 5) end
+ },
+ growthDirection = {
+ order = 5,
+ type = "select",
+ name = L["Growth Direction"],
+ values = {
+ ["UP"] = L["Bottom to Top"],
+ ["DOWN"] = L["Top to Bottom"],
+ ["LEFT"] = L["Right to Left"],
+ ["RIGHT"] = L["Left to Right"]
+ }
+ },
+ spacing = {
+ order = 6,
+ type = "range",
+ name = L["Spacing"],
+ min = 0, max = 400, step = 1
+ },
+ smartAuraPosition = {
+ order = 8,
+ type = "select",
+ name = L["Smart Aura Position"],
+ desc = L["Will show Buffs in the Debuff position when there are no Debuffs active, or vice versa."],
+ values = smartAuraPositionValues
+ },
+ orientation = {
+ order = 9,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = {
+ --["AUTOMATIC"] = L["Automatic"], not sure if i will use this yet
+ ["LEFT"] = L["Left"],
+ --["MIDDLE"] = L["Middle"], --no way to handle this with trinket
+ ["RIGHT"] = L["Right"]
+ }
+ },
+ spacer = {
+ order = 10,
+ type = "description",
+ name = " "
+ },
+ disableMouseoverGlow = {
+ order = 11,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 12,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ pvpTrinket = {
+ order = 750,
+ type = "group",
+ name = L["PVP Trinket"],
+ get = function(info) return E.db.unitframe.units.arena.pvpTrinket[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.arena.pvpTrinket[info[#info]] = value UF:CreateAndUpdateUFGroup("arena", 5) end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["PVP Trinket"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ position = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["LEFT"] = L["Left"],
+ ["RIGHT"] = L["Right"]
+ }
+ },
+ size = {
+ order = 4,
+ type = "range",
+ name = L["Size"],
+ min = 10, max = 60, step = 1
+ },
+ xOffset = {
+ order = 5,
+ type = "range",
+ name = L["X-Offset"],
+ min = -60, max = 60, step = 1
+ },
+ yOffset = {
+ order = 6,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -60, max = 60, step = 1
+ }
+ }
+ },
+ healPredction = GetOptionsTable_HealPrediction(UF.CreateAndUpdateUFGroup, "arena", 5),
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateUFGroup, "arena", 5),
+ health = GetOptionsTable_Health(false, UF.CreateAndUpdateUFGroup, "arena", 5),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateUFGroup, "arena", 5),
+ power = GetOptionsTable_Power(false, UF.CreateAndUpdateUFGroup, "arena", 5),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateUFGroup, "arena", 5),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateUFGroup, "arena", 5),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateUFGroup, "arena", 5),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateUFGroup, "arena", 5),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateUFGroup, "arena", 5),
+ castbar = GetOptionsTable_Castbar(false, UF.CreateAndUpdateUFGroup, "arena", 5),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateUFGroup, "arena", 5)
+ }
+}
+
+--Party Frames
+E.Options.args.unitframe.args.party = {
+ order = 1200,
+ type = "group",
+ name = L["PARTY"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.party[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.party[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ configureToggle = {
+ order = 2,
+ type = "execute",
+ name = L["Display Frames"],
+ func = function()
+ UF:HeaderConfig(ElvUF_Party, ElvUF_Party.forceShow ~= true or nil)
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["PARTY"], nil, {unit="party", mover="Party Frames"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = {
+ ["raid"] = L["RAID"],
+ ["raid40"] = L["Raid-40"]
+ },
+ set = function(info, value) UF:MergeUnitSettings(value, "party", true) end
+ },
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateHeaderGroup, "party"),
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ hideonnpc = {
+ order = 3,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.party.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.party.power.hideonnpc = value UF:CreateAndUpdateHeaderGroup("party") end
+ },
+ threatStyle = {
+ order = 5,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ orientation = {
+ order = 7,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 8,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 9,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ },
+ positionsGroup = {
+ order = 100,
+ name = L["Size and Positions"],
+ type = "group",
+ guiInline = true,
+ set = function(info, value) E.db.unitframe.units.party[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party", nil, nil, true) end,
+ args = {
+ width = {
+ order = 1,
+ type = "range",
+ name = L["Width"],
+ min = 10, max = 500, step = 1,
+ set = function(info, value) E.db.unitframe.units.party[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party") end
+ },
+ height = {
+ order = 2,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1,
+ set = function(info, value) E.db.unitframe.units.party[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party") end
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = "",
+ width = "full"
+ },
+ growthDirection = {
+ order = 4,
+ type = "select",
+ name = L["Growth Direction"],
+ desc = L["Growth direction from the first unitframe."],
+ values = growthDirectionValues
+ },
+ numGroups = {
+ order = 5,
+ type = "range",
+ name = L["Number of Groups"],
+ min = 1, max = 8, step = 1,
+ set = function(info, value)
+ E.db.unitframe.units.party[info[#info]] = value
+ UF:CreateAndUpdateHeaderGroup("party")
+ if ElvUF_Party.isForced then
+ UF:HeaderConfig(ElvUF_Party)
+ UF:HeaderConfig(ElvUF_Party, true)
+ end
+ end
+ },
+ groupsPerRowCol = {
+ order = 6,
+ type = "range",
+ name = L["Groups Per Row/Column"],
+ min = 1, max = 8, step = 1,
+ set = function(info, value)
+ E.db.unitframe.units.party[info[#info]] = value
+ UF:CreateAndUpdateHeaderGroup("party")
+ if ElvUF_Party.isForced then
+ UF:HeaderConfig(ElvUF_Party)
+ UF:HeaderConfig(ElvUF_Party, true)
+ end
+ end
+ },
+ horizontalSpacing = {
+ order = 7,
+ type = "range",
+ name = L["Horizontal Spacing"],
+ min = -1, max = 50, step = 1
+ },
+ verticalSpacing = {
+ order = 8,
+ type = "range",
+ name = L["Vertical Spacing"],
+ min = -1, max = 50, step = 1
+ },
+ groupSpacing = {
+ order = 9,
+ type = "range",
+ name = L["Group Spacing"],
+ desc = L["Additional spacing between each individual group."],
+ min = 0, softMax = 50, step = 1
+ }
+ }
+ },
+ visibilityGroup = {
+ order = 200,
+ type = "group",
+ name = L["Visibility"],
+ guiInline = true,
+ set = function(info, value) E.db.unitframe.units.party[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party", nil, nil, true) end,
+ args = {
+ showPlayer = {
+ order = 1,
+ type = "toggle",
+ name = L["Display Player"],
+ desc = L["When true, the header includes the player when not in a raid."],
+ },
+ visibility = {
+ order = 2,
+ type = "input",
+ name = L["Visibility"],
+ desc = L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."],
+ width = "full"
+ }
+ }
+ },
+ sortingGroup = {
+ order = 300,
+ type = "group",
+ guiInline = true,
+ name = L["Grouping & Sorting"],
+ set = function(info, value) E.db.unitframe.units.party[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party", nil, nil, true) end,
+ args = {
+ groupBy = {
+ order = 1,
+ type = "select",
+ name = L["Group By"],
+ desc = L["Set the order that the group will sort."],
+ values = {
+ ["CLASS"] = L["CLASS"],
+ ["NAME"] = L["NAME"],
+ ["MTMA"] = L["Main Tanks / Main Assist"],
+ ["GROUP"] = L["GROUP"]
+ }
+ },
+ sortDir = {
+ order = 2,
+ type = "select",
+ name = L["Sort Direction"],
+ desc = L["Defines the sort order of the selected sort method."],
+ values = {
+ ["ASC"] = L["Ascending"],
+ ["DESC"] = L["Descending"]
+ }
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ width = "full",
+ name = " "
+ },
+ raidWideSorting = {
+ order = 4,
+ type = "toggle",
+ name = L["Raid-Wide Sorting"],
+ desc = L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."]
+ },
+ invertGroupingOrder = {
+ order = 5,
+ type = "toggle",
+ name = L["Invert Grouping Order"],
+ desc = L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."],
+ disabled = function() return not E.db.unitframe.units.party.raidWideSorting end
+ },
+ startFromCenter = {
+ order = 6,
+ type = "toggle",
+ name = L["Start Near Center"],
+ desc = L["The initial group will start near the center and grow out."],
+ disabled = function() return not E.db.unitframe.units.party.raidWideSorting end
+ }
+ }
+ }
+ }
+ },
+ buffIndicator = {
+ order = 600,
+ type = "group",
+ name = L["Buff Indicator"],
+ get = function(info) return E.db.unitframe.units.party.buffIndicator[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.party.buffIndicator[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Buff Indicator"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ size = {
+ order = 3,
+ type = "range",
+ name = L["Size"],
+ desc = L["Size of the indicator icon."],
+ min = 4, max = 50, step = 1
+ },
+ fontSize = {
+ order = 4,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 7, max = 22, step = 1
+ },
+ profileSpecific = {
+ order = 5,
+ type = "toggle",
+ name = L["Profile Specific"],
+ desc = L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."]
+ },
+ configureButton = {
+ order = 6,
+ type = "execute",
+ name = L["Configure Auras"],
+ func = function()
+ if E.db.unitframe.units.party.buffIndicator.profileSpecific then
+ E:SetToFilterConfig("Buff Indicator (Profile)")
+ else
+ E:SetToFilterConfig("Buff Indicator")
+ end
+ end
+ }
+ }
+ },
+ roleIcon = {
+ order = 700,
+ type = "group",
+ name = L["Role Icon"],
+ get = function(info) return E.db.unitframe.units.party.roleIcon[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.party.roleIcon[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Role Icon"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ position = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ values = positionValues
+ },
+ attachTo = {
+ order = 4,
+ type = "select",
+ name = L["Attach To"],
+ values = attachToValues
+ },
+ xOffset = {
+ order = 5,
+ type = "range",
+ name = L["X-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 6,
+ type = "range",
+ name = L["Y-Offset"],
+ min = -300, max = 300, step = 1
+ },
+ size = {
+ order = 7,
+ type = "range",
+ name = L["Size"],
+ min = 4, max = 100, step = 1
+ },
+ tank = {
+ order = 8,
+ type = "toggle",
+ name = L["Show For Tanks"]
+ },
+ healer = {
+ order = 9,
+ type = "toggle",
+ name = L["Show For Healers"]
+ },
+ damager = {
+ order = 10,
+ type = "toggle",
+ name = L["Show For DPS"],
+ },
+ combatHide = {
+ order = 11,
+ type = "toggle",
+ name = L["Hide In Combat"]
+ }
+ }
+ },
+ raidRoleIcons = {
+ order = 750,
+ type = "group",
+ name = L["RL / ML Icons"],
+ get = function(info) return E.db.unitframe.units.party.raidRoleIcons[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.party.raidRoleIcons[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["RL / ML Icons"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ position = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOPLEFT"] = "TOPLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT"
+ }
+ }
+ }
+ },
+ health = GetOptionsTable_Health(true, UF.CreateAndUpdateHeaderGroup, "party"),
+ healPredction = GetOptionsTable_HealPrediction(UF.CreateAndUpdateHeaderGroup, "party"),
+ power = GetOptionsTable_Power(false, UF.CreateAndUpdateHeaderGroup, "party"),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateHeaderGroup, "party"),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateHeaderGroup, "party"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateHeaderGroup, "party"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateHeaderGroup, "party"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateHeaderGroup, "party"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateHeaderGroup, "party"),
+ rdebuffs = GetOptionsTable_RaidDebuff(UF.CreateAndUpdateHeaderGroup, "party"),
+ castbar = GetOptionsTable_Castbar(false, UF.CreateAndUpdateHeaderGroup, "party", 5),
+ petsGroup = {
+ order = 850,
+ type = "group",
+ name = L["Party Pets"],
+ get = function(info) return E.db.unitframe.units.party.petsGroup[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.party.petsGroup[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Party Pets"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ width = {
+ order = 3,
+ type = "range",
+ name = L["Width"],
+ min = 10, max = 500, step = 1
+ },
+ height = {
+ order = 4,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ anchorPoint = {
+ order = 5,
+ type = "select",
+ name = L["Anchor Point"],
+ desc = L["What point to anchor to the frame you set to attach to."],
+ values = petAnchors
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ desc = L["An X offset (in pixels) to be used when anchoring new frames."],
+ min = -500, max = 500, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ desc = L["An Y offset (in pixels) to be used when anchoring new frames."],
+ min = -500, max = 500, step = 1
+ },
+ name = {
+ order = 8,
+ type = "group",
+ name = L["NAME"],
+ guiInline = true,
+ get = function(info) return E.db.unitframe.units.party.petsGroup.name[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.party.petsGroup.name[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party") end,
+ args = {
+ position = {
+ order = 1,
+ type = "select",
+ name = L["Text Position"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 2,
+ type = "range",
+ name = L["Text xOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 3,
+ type = "range",
+ name = L["Text yOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ text_format = {
+ order = 100,
+ type = "input",
+ name = L["Text Format"],
+ desc = L["TEXT_FORMAT_DESC"],
+ width = "full"
+ }
+ }
+ }
+ }
+ },
+ targetsGroup = {
+ order = 900,
+ type = "group",
+ name = L["Party Targets"],
+ get = function(info) return E.db.unitframe.units.party.targetsGroup[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.party.targetsGroup[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Party Targets"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ width = {
+ order = 3,
+ type = "range",
+ name = L["Width"],
+ min = 10, max = 500, step = 1
+ },
+ height = {
+ order = 4,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ anchorPoint = {
+ order = 5,
+ type = "select",
+ name = L["Anchor Point"],
+ desc = L["What point to anchor to the frame you set to attach to."],
+ values = petAnchors
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ desc = L["An X offset (in pixels) to be used when anchoring new frames."],
+ min = -500, max = 500, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ desc = L["An Y offset (in pixels) to be used when anchoring new frames."],
+ min = -500, max = 500, step = 1
+ },
+ name = {
+ order = 8,
+ type = "group",
+ name = L["Name"],
+ guiInline = true,
+ get = function(info) return E.db.unitframe.units.party.targetsGroup.name[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.party.targetsGroup.name[info[#info]] = value UF:CreateAndUpdateHeaderGroup("party") end,
+ args = {
+ position = {
+ order = 1,
+ type = "select",
+ name = L["Text Position"],
+ values = positionValues
+ },
+ xOffset = {
+ order = 2,
+ type = "range",
+ name = L["Text xOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ yOffset = {
+ order = 3,
+ type = "range",
+ name = L["Text yOffset"],
+ desc = L["Offset position for text."],
+ min = -300, max = 300, step = 1
+ },
+ text_format = {
+ order = 100,
+ type = "input",
+ name = L["Text Format"],
+ desc = L["TEXT_FORMAT_DESC"],
+ width = "full"
+ }
+ }
+ }
+ }
+ },
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateHeaderGroup, "party"),
+ readycheckIcon = GetOptionsTable_ReadyCheckIcon(UF.CreateAndUpdateHeaderGroup, "party"),
+ resurrectIcon = GetOptionsTable_ResurrectIcon(UF.CreateAndUpdateHeaderGroup, "party"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateHeaderGroup, "party"),
+ GPSArrow = GetOptionsTable_GPS("party")
+ }
+}
+
+--Raid Frames
+E.Options.args.unitframe.args.raid = {
+ order = 1300,
+ type = "group",
+ name = L["RAID"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.raid[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.raid[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ configureToggle = {
+ order = 2,
+ type = "execute",
+ name = L["Display Frames"],
+ func = function()
+ UF:HeaderConfig(ElvUF_Raid, ElvUF_Raid.forceShow ~= true or nil)
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["RAID"], nil, {unit="raid", mover="Raid Frames"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = {
+ ["party"] = L["PARTY"],
+ ["raid40"] = L["Raid-40"]
+ },
+ set = function(info, value) UF:MergeUnitSettings(value, "raid", true) end
+ },
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateHeaderGroup, "raid"),
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ hideonnpc = {
+ order = 2,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.raid.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.raid.power.hideonnpc = value UF:CreateAndUpdateHeaderGroup("raid") end
+ },
+ threatStyle = {
+ order = 3,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ orientation = {
+ order = 5,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 6,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 7,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ },
+ positionsGroup = {
+ order = 100,
+ type = "group",
+ name = L["Size and Positions"],
+ guiInline = true,
+ set = function(info, value) E.db.unitframe.units.raid[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid", nil, nil, true) end,
+ args = {
+ width = {
+ order = 1,
+ type = "range",
+ name = L["Width"],
+ min = 10, max = 500, step = 1,
+ set = function(info, value) E.db.unitframe.units.raid[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid") end
+ },
+ height = {
+ order = 2,
+ name = L["Height"],
+ type = "range",
+ min = 10, max = 500, step = 1,
+ set = function(info, value) E.db.unitframe.units.raid[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid") end,
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = "",
+ width = "full"
+ },
+ growthDirection = {
+ order = 4,
+ type = "select",
+ name = L["Growth Direction"],
+ desc = L["Growth direction from the first unitframe."],
+ values = growthDirectionValues
+ },
+ numGroups = {
+ order = 7,
+ type = "range",
+ name = L["Number of Groups"],
+ min = 1, max = 8, step = 1,
+ set = function(info, value)
+ E.db.unitframe.units.raid[info[#info]] = value
+ UF:CreateAndUpdateHeaderGroup("raid")
+ if ElvUF_Raid.isForced then
+ UF:HeaderConfig(ElvUF_Raid)
+ UF:HeaderConfig(ElvUF_Raid, true)
+ end
+ end
+ },
+ groupsPerRowCol = {
+ order = 8,
+ type = "range",
+ name = L["Groups Per Row/Column"],
+ min = 1, max = 8, step = 1,
+ set = function(info, value)
+ E.db.unitframe.units.raid[info[#info]] = value
+ UF:CreateAndUpdateHeaderGroup("raid")
+ if ElvUF_Raid.isForced then
+ UF:HeaderConfig(ElvUF_Raid)
+ UF:HeaderConfig(ElvUF_Raid, true)
+ end
+ end
+ },
+ horizontalSpacing = {
+ order = 9,
+ type = "range",
+ name = L["Horizontal Spacing"],
+ min = -1, max = 50, step = 1
+ },
+ verticalSpacing = {
+ order = 10,
+ type = "range",
+ name = L["Vertical Spacing"],
+ min = -1, max = 50, step = 1
+ },
+ groupSpacing = {
+ order = 11,
+ type = "range",
+ name = L["Group Spacing"],
+ desc = L["Additional spacing between each individual group."],
+ min = 0, softMax = 50, step = 1
+ }
+ }
+ },
+ visibilityGroup = {
+ order = 200,
+ name = L["Visibility"],
+ type = "group",
+ guiInline = true,
+ set = function(info, value) E.db.unitframe.units.raid[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid", nil, nil, true) end,
+ args = {
+ showPlayer = {
+ order = 1,
+ type = "toggle",
+ name = L["Display Player"],
+ desc = L["When true, the header includes the player when not in a raid."]
+ },
+ visibility = {
+ order = 2,
+ type = "input",
+ name = L["Visibility"],
+ desc = L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."],
+ width = "full"
+ }
+ }
+ },
+ sortingGroup = {
+ order = 300,
+ type = "group",
+ guiInline = true,
+ name = L["Grouping & Sorting"],
+ set = function(info, value) E.db.unitframe.units.raid[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid", nil, nil, true) end,
+ args = {
+ groupBy = {
+ order = 1,
+ type = "select",
+ name = L["Group By"],
+ desc = L["Set the order that the group will sort."],
+ values = {
+ ["CLASS"] = L["CLASS"],
+ ["NAME"] = L["NAME"],
+ ["MTMA"] = L["Main Tanks / Main Assist"],
+ ["GROUP"] = L["GROUP"]
+ }
+ },
+ sortDir = {
+ order = 2,
+ type = "select",
+ name = L["Sort Direction"],
+ desc = L["Defines the sort order of the selected sort method."],
+ values = {
+ ["ASC"] = L["Ascending"],
+ ["DESC"] = L["Descending"]
+ }
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ width = "full",
+ name = " "
+ },
+ raidWideSorting = {
+ order = 4,
+ type = "toggle",
+ name = L["Raid-Wide Sorting"],
+ desc = L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."]
+ },
+ invertGroupingOrder = {
+ order = 5,
+ type = "toggle",
+ name = L["Invert Grouping Order"],
+ desc = L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."],
+ disabled = function() return not E.db.unitframe.units.raid.raidWideSorting end
+ },
+ startFromCenter = {
+ order = 6,
+ type = "toggle",
+ name = L["Start Near Center"],
+ desc = L["The initial group will start near the center and grow out."],
+ disabled = function() return not E.db.unitframe.units.raid.raidWideSorting end
+ }
+ }
+ }
+ }
+ },
+ health = GetOptionsTable_Health(true, UF.CreateAndUpdateHeaderGroup, "raid"),
+ healPredction = GetOptionsTable_HealPrediction(UF.CreateAndUpdateHeaderGroup, "raid"),
+ power = GetOptionsTable_Power(false, UF.CreateAndUpdateHeaderGroup, "raid"),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateHeaderGroup, "raid"),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateHeaderGroup, "raid"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateHeaderGroup, "raid"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateHeaderGroup, "raid"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateHeaderGroup, "raid"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateHeaderGroup, "raid"),
+ buffIndicator = {
+ order = 600,
+ type = "group",
+ name = L["Buff Indicator"],
+ get = function(info) return E.db.unitframe.units.raid.buffIndicator[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.raid.buffIndicator[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Buff Indicator"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ size = {
+ order = 3,
+ type = "range",
+ name = L["Size"],
+ desc = L["Size of the indicator icon."],
+ min = 4, max = 50, step = 1
+ },
+ fontSize = {
+ order = 4,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 7, max = 22, step = 1
+ },
+ profileSpecific = {
+ order = 5,
+ type = "toggle",
+ name = L["Profile Specific"],
+ desc = L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."]
+ },
+ configureButton = {
+ order = 6,
+ type = "execute",
+ name = L["Configure Auras"],
+ func = function()
+ if E.db.unitframe.units.raid.buffIndicator.profileSpecific then
+ E:SetToFilterConfig("Buff Indicator (Profile)")
+ else
+ E:SetToFilterConfig("Buff Indicator")
+ end
+ end
+ }
+ }
+ },
+ raidRoleIcons = {
+ order = 750,
+ type = "group",
+ name = L["RL / ML Icons"],
+ get = function(info) return E.db.unitframe.units.raid.raidRoleIcons[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.raid.raidRoleIcons[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["RL / ML Icons"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ position = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOPLEFT"] = "TOPLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT"
+ }
+ },
+ size = {
+ order = 4,
+ type = "range",
+ name = L["Size"],
+ min = 4, max = 100, step = 1
+ }
+ }
+ },
+ rdebuffs = GetOptionsTable_RaidDebuff(UF.CreateAndUpdateHeaderGroup, "raid"),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateHeaderGroup, "raid"),
+ readycheckIcon = GetOptionsTable_ReadyCheckIcon(UF.CreateAndUpdateHeaderGroup, "raid"),
+ resurrectIcon = GetOptionsTable_ResurrectIcon(UF.CreateAndUpdateHeaderGroup, "raid"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateHeaderGroup, "raid"),
+ GPSArrow = GetOptionsTable_GPS("raid")
+ }
+}
+
+--Raid-40 Frames
+E.Options.args.unitframe.args.raid40 = {
+ order = 1350,
+ type = "group",
+ name = L["Raid-40"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.raid40[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.raid40[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid40") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ configureToggle = {
+ order = 2,
+ type = "execute",
+ name = L["Display Frames"],
+ func = function()
+ UF:HeaderConfig(ElvUF_Raid40, ElvUF_Raid40.forceShow ~= true or nil)
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["Raid-40"], nil, {unit="raid40", mover="Raid Frames"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = {
+ ["party"] = L["PARTY"],
+ ["raid"] = L["RAID"]
+ },
+ set = function(info, value) UF:MergeUnitSettings(value, "raid40", true) end
+ },
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateHeaderGroup, "raid40"),
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ hideonnpc = {
+ order = 2,
+ type = "toggle",
+ name = L["Text Toggle On NPC"],
+ desc = L["Power text will be hidden on NPC targets, in addition the name text will be repositioned to the power texts anchor point."],
+ get = function(info) return E.db.unitframe.units.raid40.power.hideonnpc end,
+ set = function(info, value) E.db.unitframe.units.raid40.power.hideonnpc = value UF:CreateAndUpdateHeaderGroup("raid40") end
+ },
+ threatStyle = {
+ order = 3,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ orientation = {
+ order = 5,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 6,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 7,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ },
+ positionsGroup = {
+ order = 100,
+ type = "group",
+ name = L["Size and Positions"],
+ guiInline = true,
+ set = function(info, value) E.db.unitframe.units.raid40[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid40", nil, nil, true) end,
+ args = {
+ width = {
+ order = 1,
+ type = "range",
+ name = L["Width"],
+ min = 10, max = 500, step = 1,
+ set = function(info, value) E.db.unitframe.units.raid40[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid40") end
+ },
+ height = {
+ order = 2,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1,
+ set = function(info, value) E.db.unitframe.units.raid40[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid40") end
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = "",
+ width = "full"
+ },
+ growthDirection = {
+ order = 4,
+ type = "select",
+ name = L["Growth Direction"],
+ desc = L["Growth direction from the first unitframe."],
+ values = growthDirectionValues
+ },
+ numGroups = {
+ order = 7,
+ type = "range",
+ name = L["Number of Groups"],
+ min = 1, max = 8, step = 1,
+ set = function(info, value)
+ E.db.unitframe.units.raid40[info[#info]] = value
+ UF:CreateAndUpdateHeaderGroup("raid40")
+ if ElvUF_Raid40.isForced then
+ UF:HeaderConfig(ElvUF_Raid40)
+ UF:HeaderConfig(ElvUF_Raid40, true)
+ end
+ end
+ },
+ groupsPerRowCol = {
+ order = 8,
+ type = "range",
+ name = L["Groups Per Row/Column"],
+ min = 1, max = 8, step = 1,
+ set = function(info, value)
+ E.db.unitframe.units.raid40[info[#info]] = value
+ UF:CreateAndUpdateHeaderGroup("raid40")
+ if ElvUF_Raid40.isForced then
+ UF:HeaderConfig(ElvUF_Raid40)
+ UF:HeaderConfig(ElvUF_Raid40, true)
+ end
+ end
+ },
+ horizontalSpacing = {
+ order = 9,
+ type = "range",
+ name = L["Horizontal Spacing"],
+ min = -1, max = 50, step = 1
+ },
+ verticalSpacing = {
+ order = 10,
+ type = "range",
+ name = L["Vertical Spacing"],
+ min = -1, max = 50, step = 1
+ },
+ groupSpacing = {
+ order = 11,
+ type = "range",
+ name = L["Group Spacing"],
+ desc = L["Additional spacing between each individual group."],
+ min = 0, softMax = 50, step = 1
+ }
+ }
+ },
+ visibilityGroup = {
+ order = 200,
+ type = "group",
+ name = L["Visibility"],
+ guiInline = true,
+ set = function(info, value) E.db.unitframe.units.raid40[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid40", nil, nil, true) end,
+ args = {
+ showPlayer = {
+ order = 1,
+ type = "toggle",
+ name = L["Display Player"],
+ desc = L["When true, the header includes the player when not in a raid."]
+ },
+ visibility = {
+ order = 2,
+ type = "input",
+ name = L["Visibility"],
+ desc = L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."],
+ width = "full"
+ }
+ }
+ },
+ sortingGroup = {
+ order = 300,
+ type = "group",
+ guiInline = true,
+ name = L["Grouping & Sorting"],
+ set = function(info, value) E.db.unitframe.units.raid40[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid40", nil, nil, true) end,
+ args = {
+ groupBy = {
+ order = 1,
+ type = "select",
+ name = L["Group By"],
+ desc = L["Set the order that the group will sort."],
+ values = {
+ ["CLASS"] = L["CLASS"],
+ ["NAME"] = L["NAME"],
+ ["MTMA"] = L["Main Tanks / Main Assist"],
+ ["GROUP"] = L["GROUP"]
+ }
+ },
+ sortDir = {
+ order = 2,
+ type = "select",
+ name = L["Sort Direction"],
+ desc = L["Defines the sort order of the selected sort method."],
+ values = {
+ ["ASC"] = L["Ascending"],
+ ["DESC"] = L["Descending"]
+ }
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ width = "full",
+ name = " "
+ },
+ raidWideSorting = {
+ order = 4,
+ type = "toggle",
+ name = L["Raid-Wide Sorting"],
+ desc = L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."]
+ },
+ invertGroupingOrder = {
+ order = 5,
+ type = "toggle",
+ name = L["Invert Grouping Order"],
+ desc = L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."],
+ disabled = function() return not E.db.unitframe.units.raid40.raidWideSorting end
+ },
+ startFromCenter = {
+ order = 6,
+ type = "toggle",
+ name = L["Start Near Center"],
+ desc = L["The initial group will start near the center and grow out."],
+ disabled = function() return not E.db.unitframe.units.raid40.raidWideSorting end
+ }
+ }
+ }
+ }
+ },
+ health = GetOptionsTable_Health(true, UF.CreateAndUpdateHeaderGroup, "raid40"),
+ healPredction = GetOptionsTable_HealPrediction(UF.CreateAndUpdateHeaderGroup, "raid40"),
+ power = GetOptionsTable_Power(false, UF.CreateAndUpdateHeaderGroup, "raid40"),
+ infoPanel = GetOptionsTable_InformationPanel(UF.CreateAndUpdateHeaderGroup, "raid40"),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateHeaderGroup, "raid40"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateHeaderGroup, "raid40"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateHeaderGroup, "raid40"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateHeaderGroup, "raid40"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateHeaderGroup, "raid40"),
+ buffIndicator = {
+ order = 600,
+ type = "group",
+ name = L["Buff Indicator"],
+ get = function(info) return E.db.unitframe.units.raid40.buffIndicator[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.raid40.buffIndicator[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid40") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Buff Indicator"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ size = {
+ order = 3,
+ type = "range",
+ name = L["Size"],
+ desc = L["Size of the indicator icon."],
+ min = 4, max = 50, step = 1
+ },
+ fontSize = {
+ order = 4,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 7, max = 22, step = 1
+ },
+ profileSpecific = {
+ order = 5,
+ type = "toggle",
+ name = L["Profile Specific"],
+ desc = L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."]
+ },
+ configureButton = {
+ order = 6,
+ type = "execute",
+ name = L["Configure Auras"],
+ func = function()
+ if E.db.unitframe.units.raid40.buffIndicator.profileSpecific then
+ E:SetToFilterConfig("Buff Indicator (Profile)")
+ else
+ E:SetToFilterConfig("Buff Indicator")
+ end
+ end
+ }
+ }
+ },
+ raidRoleIcons = {
+ order = 750,
+ type = "group",
+ name = L["RL / ML Icons"],
+ get = function(info) return E.db.unitframe.units.raid40.raidRoleIcons[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.raid40.raidRoleIcons[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raid40") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["RL / ML Icons"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ position = {
+ order = 3,
+ type = "select",
+ name = L["Position"],
+ values = {
+ ["TOPLEFT"] = "TOPLEFT",
+ ["TOPRIGHT"] = "TOPRIGHT"
+ }
+ }
+ }
+ },
+ rdebuffs = GetOptionsTable_RaidDebuff(UF.CreateAndUpdateHeaderGroup, "raid40"),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateHeaderGroup, "raid40"),
+ readycheckIcon = GetOptionsTable_ReadyCheckIcon(UF.CreateAndUpdateHeaderGroup, "raid40"),
+ resurrectIcon = GetOptionsTable_ResurrectIcon(UF.CreateAndUpdateHeaderGroup, "raid40"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateHeaderGroup, "raid40"),
+ GPSArrow = GetOptionsTable_GPS("raid40")
+ }
+}
+
+--Raid Pet Frames
+E.Options.args.unitframe.args.raidpet = {
+ order = 1400,
+ type = "group",
+ name = L["Raid Pet"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.raidpet[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.raidpet[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raidpet") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ configureToggle = {
+ order = 2,
+ type = "execute",
+ name = L["Display Frames"],
+ func = function()
+ UF:HeaderConfig(ElvUF_Raidpet, ElvUF_Raidpet.forceShow ~= true or nil)
+ end
+ },
+ resetSettings = {
+ order = 3,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["Raid Pet"], nil, {unit="raidpet", mover="Raid Pet Frames"}) end
+ },
+ copyFrom = {
+ order = 4,
+ type = "select",
+ name = L["Copy From"],
+ desc = L["Select a unit to copy settings from."],
+ values = {
+ ["party"] = L["PARTY"],
+ ["raid"] = L["RAID"]
+ },
+ set = function(info, value) UF:MergeUnitSettings(value, "raidpet", true) end
+ },
+ customText = GetOptionsTable_CustomText(UF.CreateAndUpdateHeaderGroup, "raidpet"),
+ generalGroup = {
+ order = 5,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ threatStyle = {
+ order = 2,
+ type = "select",
+ name = L["Threat Display Mode"],
+ values = threatValues
+ },
+ orientation = {
+ order = 4,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 5,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 6,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ },
+ positionsGroup = {
+ order = 100,
+ type = "group",
+ name = L["Size and Positions"],
+ guiInline = true,
+ set = function(info, value) E.db.unitframe.units.raidpet[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raidpet", nil, nil, true) end,
+ args = {
+ width = {
+ order = 1,
+ type = "range",
+ name = L["Width"],
+ min = 10, max = 500, step = 1,
+ set = function(info, value) E.db.unitframe.units.raidpet[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raidpet") end,
+ },
+ height = {
+ order = 2,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1,
+ set = function(info, value) E.db.unitframe.units.raidpet[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raidpet") end,
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ name = "",
+ width = "full"
+ },
+ growthDirection = {
+ order = 4,
+ type = "select",
+ name = L["Growth Direction"],
+ desc = L["Growth direction from the first unitframe."],
+ values = growthDirectionValues
+ },
+ numGroups = {
+ order = 7,
+ type = "range",
+ name = L["Number of Groups"],
+ min = 1, max = 8, step = 1,
+ set = function(info, value)
+ E.db.unitframe.units.raidpet[info[#info]] = value
+ UF:CreateAndUpdateHeaderGroup("raidpet")
+ if ElvUF_Raidpet.isForced then
+ UF:HeaderConfig(ElvUF_Raidpet)
+ UF:HeaderConfig(ElvUF_Raidpet, true)
+ end
+ end
+ },
+ groupsPerRowCol = {
+ order = 8,
+ type = "range",
+ name = L["Groups Per Row/Column"],
+ min = 1, max = 8, step = 1,
+ set = function(info, value)
+ E.db.unitframe.units.raidpet[info[#info]] = value
+ UF:CreateAndUpdateHeaderGroup("raidpet")
+ if ElvUF_Raidpet.isForced then
+ UF:HeaderConfig(ElvUF_Raidpet)
+ UF:HeaderConfig(ElvUF_Raidpet, true)
+ end
+ end
+ },
+ horizontalSpacing = {
+ order = 9,
+ type = "range",
+ name = L["Horizontal Spacing"],
+ min = -1, max = 50, step = 1
+ },
+ verticalSpacing = {
+ order = 10,
+ type = "range",
+ name = L["Vertical Spacing"],
+ min = -1, max = 50, step = 1
+ },
+ groupSpacing = {
+ order = 11,
+ type = "range",
+ name = L["Group Spacing"],
+ desc = L["Additional spacing between each individual group."],
+ min = 0, softMax = 50, step = 1
+ }
+ }
+ },
+ visibilityGroup = {
+ order = 200,
+ type = "group",
+ name = L["Visibility"],
+ guiInline = true,
+ set = function(info, value) E.db.unitframe.units.raidpet[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raidpet", nil, nil, true) end,
+ args = {
+ visibility = {
+ order = 2,
+ type = "input",
+ name = L["Visibility"],
+ desc = L["The following macro must be true in order for the group to be shown, in addition to any filter that may already be set."],
+ width = "full"
+ }
+ }
+ },
+ sortingGroup = {
+ order = 300,
+ type = "group",
+ guiInline = true,
+ name = L["Grouping & Sorting"],
+ set = function(info, value) E.db.unitframe.units.raidpet[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raidpet", nil, nil, true) end,
+ args = {
+ groupBy = {
+ order = 1,
+ type = "select",
+ name = L["Group By"],
+ desc = L["Set the order that the group will sort."],
+ values = {
+ ["NAME"] = L["Owners Name"],
+ ["PETNAME"] = L["Pet Name"],
+ ["GROUP"] = L["GROUP"]
+ }
+ },
+ sortDir = {
+ order = 2,
+ type = "select",
+ name = L["Sort Direction"],
+ desc = L["Defines the sort order of the selected sort method."],
+ values = {
+ ["ASC"] = L["Ascending"],
+ ["DESC"] = L["Descending"]
+ }
+ },
+ spacer = {
+ order = 3,
+ type = "description",
+ width = "full",
+ name = " "
+ },
+ raidWideSorting = {
+ order = 4,
+ type = "toggle",
+ name = L["Raid-Wide Sorting"],
+ desc = L["Enabling this allows raid-wide sorting however you will not be able to distinguish between groups."]
+ },
+ invertGroupingOrder = {
+ order = 5,
+ type = "toggle",
+ name = L["Invert Grouping Order"],
+ desc = L["Enabling this inverts the grouping order when the raid is not full, this will reverse the direction it starts from."],
+ disabled = function() return not E.db.unitframe.units.raidpet.raidWideSorting end
+ },
+ startFromCenter = {
+ order = 6,
+ type = "toggle",
+ name = L["Start Near Center"],
+ desc = L["The initial group will start near the center and grow out."],
+ disabled = function() return not E.db.unitframe.units.raidpet.raidWideSorting end
+ }
+ }
+ }
+ }
+ },
+ health = GetOptionsTable_Health(true, UF.CreateAndUpdateHeaderGroup, "raidpet"),
+ healPredction = GetOptionsTable_HealPrediction(UF.CreateAndUpdateHeaderGroup, "raidpet"),
+ name = GetOptionsTable_Name(UF.CreateAndUpdateHeaderGroup, "raidpet"),
+ portrait = GetOptionsTable_Portrait(UF.CreateAndUpdateHeaderGroup, "raidpet"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateHeaderGroup, "raidpet"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateHeaderGroup, "raidpet"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateHeaderGroup, "raidpet"),
+ rdebuffs = GetOptionsTable_RaidDebuff(UF.CreateAndUpdateHeaderGroup, "raidpet"),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateHeaderGroup, "raidpet"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateHeaderGroup, "raidpet"),
+ buffIndicator = {
+ order = 600,
+ type = "group",
+ name = L["Buff Indicator"],
+ get = function(info) return E.db.unitframe.units.raidpet.buffIndicator[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.raidpet.buffIndicator[info[#info]] = value UF:CreateAndUpdateHeaderGroup("raidpet") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Buff Indicator"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ size = {
+ order = 3,
+ type = "range",
+ name = L["Size"],
+ desc = L["Size of the indicator icon."],
+ min = 4, max = 50, step = 1
+ },
+ fontSize = {
+ order = 4,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 7, max = 22, step = 1
+ },
+ configureButton = {
+ order = 5,
+ type = "execute",
+ name = L["Configure Auras"],
+ func = function() E:SetToFilterConfig("Buff Indicator") end
+ }
+ }
+ }
+ }
+}
+
+--Tank Frames
+E.Options.args.unitframe.args.tank = {
+ order = 1500,
+ type = "group",
+ name = L["TANK"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.tank[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.tank[info[#info]] = value UF:CreateAndUpdateHeaderGroup("tank") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ resetSettings = {
+ order = 2,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["TANK"], nil, {unit="tank"}) end
+ },
+ generalGroup = {
+ order = 3,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 2,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ disableDebuffHighlight = {
+ order = 5,
+ type = "toggle",
+ name = L["Disable Debuff Highlight"],
+ desc = L["Forces Debuff Highlight to be disabled for these frames"],
+ disabled = function() return E.db.unitframe.debuffHighlighting == "NONE" end
+ },
+ orientation = {
+ order = 6,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 8,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 9,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ targetsGroup = {
+ order = 4,
+ type = "group",
+ name = L["Tank Target"],
+ get = function(info) return E.db.unitframe.units.tank.targetsGroup[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.tank.targetsGroup[info[#info]] = value UF:CreateAndUpdateHeaderGroup("tank") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Tank Target"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ width = {
+ order = 3,
+ type = "range",
+ name = L["Width"],
+ min = 10, max = 500, step = 1
+ },
+ height = {
+ order = 4,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ anchorPoint = {
+ order = 5,
+ type = "select",
+ name = L["Anchor Point"],
+ desc = L["What point to anchor to the frame you set to attach to."],
+ values = petAnchors
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ desc = L["An X offset (in pixels) to be used when anchoring new frames."],
+ min = -500, max = 500, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ desc = L["An Y offset (in pixels) to be used when anchoring new frames."],
+ min = -500, max = 500, step = 1
+ },
+ name = GetOptionsTable_Name(UF.CreateAndUpdateHeaderGroup, "tank")
+ }
+ },
+ name = GetOptionsTable_Name(UF.CreateAndUpdateHeaderGroup, "tank"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateHeaderGroup, "tank"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateHeaderGroup, "tank"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateHeaderGroup, "tank"),
+ rdebuffs = GetOptionsTable_RaidDebuff(UF.CreateAndUpdateHeaderGroup, "tank"),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateHeaderGroup, "tank"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateHeaderGroup, "tank"),
+ buffIndicator = {
+ order = 800,
+ type = "group",
+ name = L["Buff Indicator"],
+ get = function(info) return E.db.unitframe.units.tank.buffIndicator[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.tank.buffIndicator[info[#info]] = value UF:CreateAndUpdateHeaderGroup("tank") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Buff Indicator"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ size = {
+ order = 3,
+ type = "range",
+ name = L["Size"],
+ desc = L["Size of the indicator icon."],
+ min = 4, max = 50, step = 1
+ },
+ fontSize = {
+ order = 4,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 7, max = 22, step = 1
+ },
+ profileSpecific = {
+ order = 5,
+ type = "toggle",
+ name = L["Profile Specific"],
+ desc = L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."]
+ },
+ configureButton = {
+ order = 6,
+ type = "execute",
+ name = L["Configure Auras"],
+ func = function()
+ if E.db.unitframe.units.tank.buffIndicator.profileSpecific then
+ E:SetToFilterConfig("Buff Indicator (Profile)")
+ else
+ E:SetToFilterConfig("Buff Indicator")
+ end
+ end
+ }
+ }
+ }
+ }
+}
+E.Options.args.unitframe.args.tank.args.name.args.attachTextTo.values = {["Health"] = L["HEALTH"], ["Frame"] = L["Frame"]}
+E.Options.args.unitframe.args.tank.args.targetsGroup.args.name.args.attachTextTo.values = {["Health"] = L["HEALTH"], ["Frame"] = L["Frame"]}
+E.Options.args.unitframe.args.tank.args.targetsGroup.args.name.get = function(info) return E.db.unitframe.units.tank.targetsGroup.name[info[#info]] end
+E.Options.args.unitframe.args.tank.args.targetsGroup.args.name.set = function(info, value) E.db.unitframe.units.tank.targetsGroup.name[info[#info]] = value UF.CreateAndUpdateHeaderGroup(UF, "tank") end
+
+--Assist Frames
+E.Options.args.unitframe.args.assist = {
+ order = 1600,
+ type = "group",
+ name = L["Assist"],
+ childGroups = "tab",
+ get = function(info) return E.db.unitframe.units.assist[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.assist[info[#info]] = value UF:CreateAndUpdateHeaderGroup("assist") end,
+ disabled = function() return not E.UnitFrames.Initialized end,
+ args = {
+ enable = {
+ order = 1,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ resetSettings = {
+ order = 2,
+ type = "execute",
+ name = L["Restore Defaults"],
+ func = function(info) E:StaticPopup_Show("RESET_UF_UNIT", L["Assist"], nil, {unit="assist"}) end
+ },
+ generalGroup = {
+ order = 3,
+ type = "group",
+ name = L["General"],
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["General"]
+ },
+ width = {
+ order = 2,
+ type = "range",
+ name = L["Width"],
+ min = 50, max = 1000, step = 1
+ },
+ height = {
+ order = 3,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ disableDebuffHighlight = {
+ order = 5,
+ type = "toggle",
+ name = L["Disable Debuff Highlight"],
+ desc = L["Forces Debuff Highlight to be disabled for these frames"],
+ disabled = function() return E.db.unitframe.debuffHighlighting == "NONE" end
+ },
+ orientation = {
+ order = 6,
+ type = "select",
+ name = L["Frame Orientation"],
+ desc = L["Set the orientation of the UnitFrame."],
+ values = orientationValues
+ },
+ disableMouseoverGlow = {
+ order = 8,
+ type = "toggle",
+ name = L["Block Mouseover Glow"],
+ desc = L["Forces Mouseover Glow to be disabled for these frames"]
+ },
+ disableTargetGlow = {
+ order = 9,
+ type = "toggle",
+ name = L["Block Target Glow"],
+ desc = L["Forces Target Glow to be disabled for these frames"]
+ }
+ }
+ },
+ targetsGroup = {
+ order = 4,
+ type = "group",
+ name = L["Assist Target"],
+ get = function(info) return E.db.unitframe.units.assist.targetsGroup[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.assist.targetsGroup[info[#info]] = value UF:CreateAndUpdateHeaderGroup("assist") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Assist Target"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ width = {
+ order = 3,
+ type = "range",
+ name = L["Width"],
+ min = 10, max = 500, step = 1
+ },
+ height = {
+ order = 4,
+ type = "range",
+ name = L["Height"],
+ min = 10, max = 500, step = 1
+ },
+ anchorPoint = {
+ order = 5,
+ type = "select",
+ name = L["Anchor Point"],
+ desc = L["What point to anchor to the frame you set to attach to."],
+ values = petAnchors
+ },
+ xOffset = {
+ order = 6,
+ type = "range",
+ name = L["X-Offset"],
+ desc = L["An X offset (in pixels) to be used when anchoring new frames."],
+ min = -500, max = 500, step = 1
+ },
+ yOffset = {
+ order = 7,
+ type = "range",
+ name = L["Y-Offset"],
+ desc = L["An Y offset (in pixels) to be used when anchoring new frames."],
+ min = -500, max = 500, step = 1
+ },
+ name = GetOptionsTable_Name(UF.CreateAndUpdateHeaderGroup, "assist")
+ }
+ },
+ name = GetOptionsTable_Name(UF.CreateAndUpdateHeaderGroup, "assist"),
+ fader = GetOptionsTable_Fader(UF.CreateAndUpdateHeaderGroup, "assist"),
+ buffs = GetOptionsTable_Auras("buffs", UF.CreateAndUpdateHeaderGroup, "assist"),
+ debuffs = GetOptionsTable_Auras("debuffs", UF.CreateAndUpdateHeaderGroup, "assist"),
+ rdebuffs = GetOptionsTable_RaidDebuff(UF.CreateAndUpdateHeaderGroup, "assist"),
+ raidicon = GetOptionsTable_RaidIcon(UF.CreateAndUpdateHeaderGroup, "assist"),
+ cutaway = GetOptionsTable_Cutaway(UF.CreateAndUpdateHeaderGroup, "assist"),
+ buffIndicator = {
+ order = 800,
+ type = "group",
+ name = L["Buff Indicator"],
+ get = function(info) return E.db.unitframe.units.assist.buffIndicator[info[#info]] end,
+ set = function(info, value) E.db.unitframe.units.assist.buffIndicator[info[#info]] = value UF:CreateAndUpdateHeaderGroup("assist") end,
+ args = {
+ header = {
+ order = 1,
+ type = "header",
+ name = L["Buff Indicator"]
+ },
+ enable = {
+ order = 2,
+ type = "toggle",
+ name = L["Enable"]
+ },
+ size = {
+ order = 3,
+ type = "range",
+ name = L["Size"],
+ desc = L["Size of the indicator icon."],
+ min = 4, max = 50, step = 1
+ },
+ fontSize = {
+ order = 4,
+ type = "range",
+ name = L["FONT_SIZE"],
+ min = 7, max = 22, step = 1
+ },
+ profileSpecific = {
+ order = 5,
+ type = "toggle",
+ name = L["Profile Specific"],
+ desc = L["Use the profile specific filter 'Buff Indicator (Profile)' instead of the global filter 'Buff Indicator'."]
+ },
+ configureButton = {
+ order = 6,
+ type = "execute",
+ name = L["Configure Auras"],
+ func = function()
+ if E.db.unitframe.units.assist.buffIndicator.profileSpecific then
+ E:SetToFilterConfig("Buff Indicator (Profile)")
+ else
+ E:SetToFilterConfig("Buff Indicator")
+ end
+ end
+ }
+ }
+ }
+ }
+}
+E.Options.args.unitframe.args.assist.args.name.args.attachTextTo.values = {["Health"] = L["HEALTH"], ["Frame"] = L["Frame"]}
+E.Options.args.unitframe.args.assist.args.targetsGroup.args.name.args.attachTextTo.values = {["Health"] = L["HEALTH"], ["Frame"] = L["Frame"]}
+E.Options.args.unitframe.args.assist.args.targetsGroup.args.name.get = function(info) return E.db.unitframe.units.assist.targetsGroup.name[info[#info]] end
+E.Options.args.unitframe.args.assist.args.targetsGroup.args.name.set = function(info, value) E.db.unitframe.units.assist.targetsGroup.name[info[#info]] = value UF.CreateAndUpdateHeaderGroup(UF, "assist") end
+
+--MORE COLORING STUFF YAY
+E.Options.args.unitframe.args.generalOptionsGroup.args.allColorsGroup.args.classResourceGroup = {
+ order = -10,
+ type = "group",
+ name = L["Class Resources"],
+ get = function(info)
+ local t = E.db.unitframe.colors.classResources[info[#info]]
+ local d = P.unitframe.colors.classResources[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors.classResources[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end,
+ args = {
+ header = {
+ order = 0,
+ type = "header",
+ name = L["Class Resources"]
+ },
+ customclasspowerbackdrop = {
+ order = 0.1,
+ type = "toggle",
+ name = L["Custom Backdrop"],
+ desc = L["Use the custom backdrop color instead of a multiple of the main color."],
+ get = function(info) return E.db.unitframe.colors[info[#info]] end,
+ set = function(info, value) E.db.unitframe.colors[info[#info]] = value UF:Update_AllFrames() end,
+ },
+ classpower_backdrop = {
+ order = 0.2,
+ type = "color",
+ name = L["Custom Backdrop"],
+ desc = L["Use the custom backdrop color instead of a multiple of the main color."],
+ disabled = function() return not E.db.unitframe.colors.customclasspowerbackdrop end,
+ get = function(info)
+ local t = E.db.unitframe.colors[info[#info]]
+ local d = P.unitframe.colors[info[#info]]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors[info[#info]]
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end,
+ },
+ spacer2 = {
+ order = 0.3,
+ type = "description",
+ name = " ",
+ width = "full"
+ }
+ }
+}
+
+for i = 1, 5 do
+ E.Options.args.unitframe.args.generalOptionsGroup.args.allColorsGroup.args.classResourceGroup.args["combo"..i] = {
+ order = i + 2,
+ type = "color",
+ name = L["Combo Point"].." #"..i,
+ get = function(info)
+ local t = E.db.unitframe.colors.classResources.comboPoints[i]
+ local d = P.unitframe.colors.classResources.comboPoints[i]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors.classResources.comboPoints[i]
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end
+ }
+end
+
+if P.unitframe.colors.classResources[E.myclass] then
+ E.Options.args.unitframe.args.generalOptionsGroup.args.allColorsGroup.args.classResourceGroup.args.spacer3 = {
+ order = 10,
+ type = "description",
+ name = " ",
+ width = "full"
+ }
+
+ local ORDER = 20
+ if E.myclass == "DEATHKNIGHT" then
+ local names = {
+ [1] = L["COMBAT_TEXT_RUNE_BLOOD"],
+ [2] = L["COMBAT_TEXT_RUNE_UNHOLY"],
+ [3] = L["COMBAT_TEXT_RUNE_FROST"],
+ [4] = L["COMBAT_TEXT_RUNE_DEATH"]
+ }
+ for i = 1, 4 do
+ E.Options.args.unitframe.args.generalOptionsGroup.args.allColorsGroup.args.classResourceGroup.args["resource"..i] = {
+ order = ORDER + i,
+ type = "color",
+ name = names[i],
+ get = function(info)
+ local t = E.db.unitframe.colors.classResources.DEATHKNIGHT[i]
+ local d = P.unitframe.colors.classResources.DEATHKNIGHT[i]
+ return t.r, t.g, t.b, t.a, d.r, d.g, d.b
+ end,
+ set = function(info, r, g, b)
+ local t = E.db.unitframe.colors.classResources.DEATHKNIGHT[i]
+ t.r, t.g, t.b = r, g, b
+ UF:Update_AllFrames()
+ end
+ }
+ end
+ end
+end
+
+--Custom Texts
+function E:RefreshCustomTextsConfigs()
+ --Hide any custom texts that don't belong to current profile
+ for _, customText in pairs(CUSTOMTEXT_CONFIGS) do
+ customText.hidden = true
+ end
+ twipe(CUSTOMTEXT_CONFIGS)
+
+ for unit in pairs(E.db.unitframe.units) do
+ if E.db.unitframe.units[unit].customTexts then
+ for objectName in pairs(E.db.unitframe.units[unit].customTexts) do
+ CreateCustomTextGroup(unit, objectName)
+ end
+ end
+ end
+end
+E:RefreshCustomTextsConfigs()
\ No newline at end of file
diff --git a/README.md b/README.md
index 226db33..3a64069 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,3 @@
-# Addon Name
+# ElvUI
-This is the repository for . Modified for Ascension.gg.
\ No newline at end of file
+This is the repository for ElvUI. Modified for Ascension.gg.
\ No newline at end of file