mirror of
https://github.com/Bluewhale1337/ElvUIModernized.git
synced 2026-07-27 16:34:45 +00:00
1099 lines
32 KiB
Lua
1099 lines
32 KiB
Lua
local E, L, V, P, G = unpack(ElvUI)
|
|
local UF = E:NewModule("UnitFrames", "AceTimer-3.0", "AceEvent-3.0", "AceHook-3.0")
|
|
local LSM = LibStub("LibSharedMedia-3.0")
|
|
UF.LSM = LSM
|
|
|
|
--Cache global variables
|
|
--Lua functions
|
|
local _G = _G
|
|
local select, pairs, type, unpack, assert, tostring = select, pairs, type, unpack, assert, tostring
|
|
local min = math.min
|
|
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 UnitFrame_OnEnter = UnitFrame_OnEnter
|
|
local UnitFrame_OnLeave = UnitFrame_OnLeave
|
|
local IsInInstance = IsInInstance
|
|
local UnregisterStateDriver = UnregisterStateDriver
|
|
local RegisterStateDriver = RegisterStateDriver
|
|
local MAX_RAID_MEMBERS = MAX_RAID_MEMBERS
|
|
|
|
local ns = oUF
|
|
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
|
|
}
|
|
|
|
UF.mapIDs = {
|
|
[443] = 10, -- Warsong Gulch
|
|
[461] = 15, -- Arathi Basin
|
|
[401] = 40, -- Alterac Valley
|
|
[566] = 15, -- Eye of the Storm
|
|
}
|
|
|
|
UF.headerGroupBy = {
|
|
["CLASS"] = function(header)
|
|
header:SetAttribute("groupingOrder", "DRUID,HUNTER,MAGE,PALADIN,PRIEST,SHAMAN,WARLOCK,WARRIOR")
|
|
header:SetAttribute("sortMethod", "NAME")
|
|
header:SetAttribute("groupBy", "CLASS")
|
|
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:SetFrameStrata("LOW")
|
|
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.HAPPINESS_WIDTH = 0
|
|
frame.CLASSBAR_YOFFSET = 0 --placeholder
|
|
frame.BOTTOM_OFFSET = 0 --placeholder
|
|
|
|
frame.RaisedElementParent = CreateFrame("Frame", nil, frame)
|
|
frame.RaisedElementParent:SetFrameLevel(frame:GetFrameLevel() + 100)
|
|
frame.RaisedElementParent.TextureParent = CreateFrame("Frame", nil, frame.RaisedElementParent)
|
|
frame.RaisedElementParent.TextureParent:SetFrameLevel(frame.RaisedElementParent:GetFrameLevel() + 1)
|
|
|
|
local stringTitle = E:StringTitle(unit)
|
|
if string.find(stringTitle, "target") then
|
|
stringTitle = gsub(stringTitle, "target", "Target")
|
|
end
|
|
self["Construct_"..stringTitle.."Frame"](self, frame, unit)
|
|
|
|
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 == "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
|
|
else
|
|
return frame
|
|
end
|
|
end
|
|
|
|
function UF:UpdateColors()
|
|
local db = self.db.colors
|
|
|
|
local good = E:GetColorTable(db.reaction.GOOD)
|
|
local bad = E:GetColorTable(db.reaction.BAD)
|
|
local neutral = E:GetColorTable(db.reaction.NEUTRAL)
|
|
|
|
ElvUF.colors.tapped = E:GetColorTable(db.tapped);
|
|
ElvUF.colors.disconnected = E:GetColorTable(db.disconnected);
|
|
ElvUF.colors.health = E:GetColorTable(db.health);
|
|
ElvUF.colors.power[0] = E:GetColorTable(db.power.MANA);
|
|
ElvUF.colors.power[1] = E:GetColorTable(db.power.RAGE);
|
|
ElvUF.colors.power[2] = E:GetColorTable(db.power.FOCUS);
|
|
ElvUF.colors.power[3] = E:GetColorTable(db.power.ENERGY);
|
|
|
|
ElvUF.colors.ComboPoints = {}
|
|
ElvUF.colors.ComboPoints[1] = E:GetColorTable(db.classResources.comboPoints[1])
|
|
ElvUF.colors.ComboPoints[2] = E:GetColorTable(db.classResources.comboPoints[2])
|
|
ElvUF.colors.ComboPoints[3] = E:GetColorTable(db.classResources.comboPoints[3])
|
|
ElvUF.colors.ComboPoints[4] = E:GetColorTable(db.classResources.comboPoints[4])
|
|
ElvUF.colors.ComboPoints[5] = E:GetColorTable(db.classResources.comboPoints[5])
|
|
|
|
ElvUF.colors.reaction[1] = bad
|
|
ElvUF.colors.reaction[2] = bad
|
|
ElvUF.colors.reaction[3] = bad
|
|
ElvUF.colors.reaction[4] = neutral
|
|
ElvUF.colors.reaction[5] = good
|
|
ElvUF.colors.reaction[6] = good
|
|
ElvUF.colors.reaction[7] = good
|
|
ElvUF.colors.reaction[8] = good
|
|
ElvUF.colors.smooth = {1, 0, 0,
|
|
1, 1, 0,
|
|
unpack(E:GetColorTable(db.health))}
|
|
|
|
ElvUF.colors.castColor = E:GetColorTable(db.castColor);
|
|
end
|
|
|
|
function UF:Update_StatusBars()
|
|
local statusBarTexture = LSM:Fetch("statusbar", self.db.statusbar)
|
|
for statusbar in pairs(UF.statusbars) do
|
|
if statusbar and statusbar:GetObjectType() == "StatusBar" and not statusbar.isTransparent then
|
|
statusbar:SetStatusBarTexture(statusBarTexture)
|
|
elseif statusbar and statusbar:GetObjectType() == "Texture" then
|
|
statusbar:SetTexture(statusBarTexture)
|
|
end
|
|
end
|
|
end
|
|
|
|
function UF:Update_StatusBar(bar)
|
|
bar:SetStatusBarTexture(LSM:Fetch("statusbar", self.db.statusbar))
|
|
end
|
|
|
|
function UF:Update_FontString(object)
|
|
E:FontTemplate(object, 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
|
|
E:FontTemplate(font, stringFont, self.db.fontSize, self.db.fontOutline)
|
|
end
|
|
end
|
|
|
|
function UF:Configure_FontString(obj)
|
|
UF.fontstrings[obj] = true
|
|
E:FontTemplate(obj) --This is temporary.
|
|
end
|
|
|
|
function UF:Update_AllFrames()
|
|
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]:Enable()
|
|
self[unit]:Update()
|
|
E:EnableMover(self[unit].mover:GetName())
|
|
else
|
|
self[unit]:Disable()
|
|
E:DisableMover(self[unit].mover:GetName())
|
|
end
|
|
end
|
|
|
|
self:UpdateAllHeaders()
|
|
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
|
|
|
|
--Keep an eye on this one, it may need to be changed too
|
|
--Reference: http://www.tukui.org/forums/topic.php?id=35332
|
|
function UF.groupPrototype:GetAttribute(name)
|
|
return self.groups[1]:GetAttribute(name)
|
|
end
|
|
|
|
function UF.groupPrototype:Configure_Groups(self)
|
|
local db = UF.db.units[self.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 numGroups = self.numGroups
|
|
for i = 1, numGroups do
|
|
local group = self.groups[i]
|
|
|
|
point = DIRECTION_TO_POINT[direction]
|
|
|
|
if group then
|
|
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)
|
|
UF.headerGroupBy[db.groupBy](group)
|
|
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
|
|
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 math.mod(i - 1, db.groupsPerRowCol) == 0 then
|
|
if DIRECTION_TO_POINT[direction] == "LEFT" or DIRECTION_TO_POINT[direction] == "RIGHT" then
|
|
if group then
|
|
E:Point(group, point, self, point, 0, height * yMult)
|
|
end
|
|
height = height + UNIT_HEIGHT + db.verticalSpacing
|
|
newRows = newRows + 1
|
|
else
|
|
if group then
|
|
E:Point(group, point, self, point, width * xMult, 0)
|
|
end
|
|
width = width + db.width + db.horizontalSpacing
|
|
|
|
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
|
|
E:Point(group, point, self, point, width * xMult, 0)
|
|
end
|
|
width = width + ((db.width + db.horizontalSpacing) * 5)
|
|
newCols = newCols + 1
|
|
elseif group then
|
|
E:Point(group, point, self, point, (((db.width + db.horizontalSpacing) * 5) * (math.mod(i-1, db.groupsPerRowCol))) * xMult, ((UNIT_HEIGHT + db.verticalSpacing) * (newRows - 1)) * yMult)
|
|
end
|
|
else
|
|
if newCols == 1 then
|
|
if group then
|
|
E:Point(group, point, self, point, 0, height * yMult)
|
|
end
|
|
height = height + ((UNIT_HEIGHT + db.verticalSpacing) * 5)
|
|
newRows = newRows + 1
|
|
elseif group then
|
|
E:Point(group, point, self, point, ((db.width + db.horizontalSpacing) * (newCols - 1)) * xMult, (((UNIT_HEIGHT + db.verticalSpacing) * 5) * (math.mod(i-1, db.groupsPerRowCol))) * yMult)
|
|
end
|
|
end
|
|
end
|
|
|
|
if height == 0 then
|
|
height = height + ((UNIT_HEIGHT + db.verticalSpacing) * 5)
|
|
elseif width == 0 then
|
|
width = width + ((db.width + db.horizontalSpacing) * 5)
|
|
end
|
|
end
|
|
|
|
if not self.isInstanceForced then
|
|
self.dirtyWidth = width - db.horizontalSpacing
|
|
self.dirtyHeight = height - db.verticalSpacing
|
|
end
|
|
|
|
if self.mover then
|
|
self.mover.positionOverride = DIRECTION_TO_GROUP_ANCHOR_POINT[direction]
|
|
E:UpdatePositionOverride(self.mover:GetName())
|
|
self:GetScript("OnSizeChanged")(self) --Mover size is not updated if frame is hidden, so call an update manually
|
|
end
|
|
|
|
E:Size(self, width - db.horizontalSpacing, height - db.verticalSpacing)
|
|
end
|
|
|
|
function UF.groupPrototype:Update(self)
|
|
local group = self.groupName
|
|
|
|
UF[group].db = UF.db.units[group]
|
|
for i = 1, getn(self.groups) do
|
|
self.groups[i].db = UF.db.units[group]
|
|
self.groups[i]:Update()
|
|
end
|
|
end
|
|
|
|
function UF.groupPrototype:AdjustVisibility(self)
|
|
if not self.isForced then
|
|
local numGroups = self.numGroups
|
|
for i = 1, getn(self.groups) do
|
|
local group = self.groups[i]
|
|
if (i <= numGroups) and ((self.db.raidWideSorting and i <= 1) or not self.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.groupPrototype:UpdateHeader(self)
|
|
local group = self.groupName;
|
|
UF["Update_"..E:StringTitle(group).."Header"](UF, self, UF.db.units[group]);
|
|
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(isForced)
|
|
local group = self.groupName
|
|
local db = UF.db.units[group]
|
|
|
|
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
|
|
local db = UF.db.units[group]
|
|
ElvUF:SetActiveStyle("ElvUF_"..E:StringTitle(group))
|
|
local header = ElvUF:SpawnHeader(overrideName, headerTemplate, nil,
|
|
"groupFilter", groupFilter,
|
|
"showParty", true,
|
|
"showRaid", true,
|
|
"showSolo", false,
|
|
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)
|
|
local db = self.db.units[group]
|
|
local numGroups = db.numGroups
|
|
|
|
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, E.UIParent)
|
|
self[group]:SetFrameStrata("LOW")
|
|
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(E.UIParent, 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 > getn(self[group].groups) do
|
|
local index = tostring(getn(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
|
|
else
|
|
UF.headerFunctions[group]:Configure_Groups(self[group])
|
|
UF.headerFunctions[group]:UpdateHeader(self[group])
|
|
UF.headerFunctions[group]:Update(self[group])
|
|
end
|
|
|
|
if db.enable then
|
|
self[group]:Show()
|
|
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.")
|
|
|
|
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.db.units[unit].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
|
|
|
|
function UF:LoadUnits()
|
|
for _, unit in pairs(self.unitstoload) do
|
|
self:CreateAndUpdateUF(unit)
|
|
end
|
|
self.unitstoload = 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:UpdateAllHeaders(event)
|
|
local _, instanceType = IsInInstance()
|
|
local ORD = ns.oUF_RaidDebuffs or oUF_RaidDebuffs
|
|
if ORD then
|
|
ORD:ResetDebuffData()
|
|
|
|
--[[if instanceType == "party" or instanceType == "raid" then
|
|
ORD:RegisterDebuffs(E.global.unitframe.aurafilters.RaidDebuffs.spells)
|
|
else
|
|
ORD:RegisterDebuffs(E.global.unitframe.aurafilters.CCDebuffs.spells)
|
|
end--]]
|
|
end
|
|
|
|
if E.private.unitframe.disabledBlizzardFrames.party then
|
|
ElvUF:DisableBlizzard("party")
|
|
end
|
|
|
|
for group, header in pairs(self.headers) do
|
|
if header.numGroups then
|
|
UF.headerFunctions[group]:UpdateHeader(header)
|
|
end
|
|
UF.headerFunctions[group]:Update(header)
|
|
|
|
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: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 then return end
|
|
|
|
if(unit == "player") and E.private.unitframe.disabledBlizzardFrames.player then
|
|
HandleFrame(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(TargetofTargetFrame)
|
|
elseif string.match(unit, "(party)%d?$") == "party" and E.private.unitframe.disabledBlizzardFrames.party then
|
|
local id = string.match(unit, "party(%d)")
|
|
if id then
|
|
HandleFrame("PartyMemberFrame"..id)
|
|
else
|
|
for i = 1, 4 do
|
|
HandleFrame(format("PartyMemberFrame%d", i))
|
|
end
|
|
end
|
|
HandleFrame(PartyMemberBackground)
|
|
end
|
|
end
|
|
|
|
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
|
|
self: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
|
|
|
|
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
|
|
E.UnitFrames = UF
|
|
|
|
self:UpdateColors()
|
|
ElvUF:RegisterStyle("ElvUF", function(frame, unit)
|
|
self:Construct_UF(frame, unit)
|
|
end)
|
|
|
|
self:LoadUnits()
|
|
self:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
|
|
local ORD = ns.oUF_RaidDebuffs or oUF_RaidDebuffs
|
|
if not ORD then return end
|
|
ORD.ShowDispelableDebuff = true
|
|
ORD.FilterDispellableDebuff = true
|
|
|
|
-- self:UpdateRangeCheckSpells()
|
|
-- self:RegisterEvent("LEARNED_SPELL_IN_TAB", "UpdateRangeCheckSpells")
|
|
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,
|
|
["playerOnly"] = true,
|
|
["noConsolidated"] = true,
|
|
["useBlacklist"] = true,
|
|
["useWhitelist"] = true,
|
|
["noDuration"] = true,
|
|
["onlyDispellable"] = true,
|
|
["useFilter"] = 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
|
|
|
|
local function updateColor(self, r, g, b)
|
|
if not self.isTransparent then return end
|
|
if self.backdrop then
|
|
local _, _, _, a = self.backdrop:GetBackdropColor()
|
|
self.backdrop:SetBackdropColor(r * 0.58, g * 0.58, b * 0.58, a)
|
|
elseif self:GetParent().template then
|
|
local _, _, _, a = self:GetParent():GetBackdropColor()
|
|
self:GetParent():SetBackdropColor(r * 0.58, g * 0.58, b * 0.58, a)
|
|
end
|
|
|
|
if self.bg and self.bg:GetObjectType() == "Texture" and not self.bg.multiplier then
|
|
self.bg:SetTexture(r * 0.35, g * 0.35, b * 0.35)
|
|
end
|
|
end
|
|
|
|
function UF:ToggleTransparentStatusBar(isTransparent, statusBar, backdropTex, adjustBackdropPoints, invertBackdropTex)
|
|
statusBar.isTransparent = isTransparent
|
|
|
|
local statusBarTex = statusBar.texturePointer
|
|
local statusBarOrientation = statusBar:GetOrientation()
|
|
if isTransparent then
|
|
if statusBar.backdrop then
|
|
E:SetTemplate(statusBar.backdrop, "Transparent", nil, nil, nil, true)
|
|
statusBar.backdrop.ignoreUpdates = true
|
|
elseif statusBar:GetParent().template then
|
|
E:SetTemplate(statusBar:GetParent(), "Transparent", nil, nil, nil, true)
|
|
statusBar:GetParent().ignoreUpdates = true
|
|
end
|
|
|
|
statusBar:SetStatusBarTexture("")
|
|
if statusBar.texture then statusBar.texture = statusBar:GetStatusBarTexture() end --Needed for Power element
|
|
|
|
backdropTex:ClearAllPoints()
|
|
if statusBarOrientation == "VERTICAL" then
|
|
backdropTex:SetPoint("TOPLEFT", statusBar, "TOPLEFT")
|
|
backdropTex:SetPoint("BOTTOMLEFT", statusBarTex, "TOPLEFT")
|
|
backdropTex:SetPoint("BOTTOMRIGHT", statusBarTex, "TOPRIGHT")
|
|
else
|
|
backdropTex:SetPoint("TOPLEFT", statusBarTex, "TOPRIGHT")
|
|
backdropTex:SetPoint("BOTTOMLEFT", statusBarTex, "BOTTOMRIGHT")
|
|
backdropTex:SetPoint("BOTTOMRIGHT", statusBar, "BOTTOMRIGHT")
|
|
end
|
|
|
|
if invertBackdropTex then
|
|
backdropTex:Show()
|
|
end
|
|
|
|
if not invertBackdropTex and not statusBar.hookedColor then
|
|
hooksecurefunc(statusBar, "SetStatusBarColor", updateColor)
|
|
statusBar.hookedColor = true
|
|
end
|
|
|
|
if backdropTex.multiplier then
|
|
backdropTex.multiplier = 0.25
|
|
end
|
|
else
|
|
if statusBar.backdrop then
|
|
E:SetTemplate(statusBar.backdrop, "Default", nil, nil, not statusBar.PostCastStart and self.thinBorders, true)
|
|
statusBar.backdrop.ignoreUpdates = nil
|
|
elseif statusBar:GetParent().template then
|
|
E:SetTemplate(statusBar:GetParent(), "Default", nil, nil, self.thinBorders, true)
|
|
statusBar:GetParent().ignoreUpdates = nil
|
|
end
|
|
statusBar:SetStatusBarTexture(LSM:Fetch("statusbar", self.db.statusbar))
|
|
if statusBar.texture then statusBar.texture = statusBar:GetStatusBarTexture() end
|
|
|
|
if adjustBackdropPoints then
|
|
backdropTex:ClearAllPoints()
|
|
if statusBarOrientation == "VERTICAL" then
|
|
backdropTex:SetPoint("TOPLEFT", statusBar, "TOPLEFT")
|
|
backdropTex:SetPoint("BOTTOMLEFT", statusBarTex, "TOPLEFT")
|
|
backdropTex:SetPoint("BOTTOMRIGHT", statusBarTex, "TOPRIGHT")
|
|
else
|
|
backdropTex:SetPoint("TOPLEFT", statusBarTex, "TOPRIGHT")
|
|
backdropTex:SetPoint("BOTTOMLEFT", statusBarTex, "BOTTOMRIGHT")
|
|
backdropTex:SetPoint("BOTTOMRIGHT", statusBar, "BOTTOMRIGHT")
|
|
end
|
|
end
|
|
|
|
if invertBackdropTex then
|
|
backdropTex:Hide()
|
|
end
|
|
|
|
if backdropTex.multiplier then
|
|
backdropTex.multiplier = 0.25
|
|
end
|
|
end
|
|
end
|
|
|
|
local function InitializeCallback()
|
|
UF:Initialize()
|
|
end
|
|
|
|
E:RegisterInitialModule(UF:GetName(), InitializeCallback)
|