missing files

This commit is contained in:
andrew6180
2024-12-23 06:56:21 -07:00
parent d40388b8b7
commit 3dada108b9
20 changed files with 6576 additions and 0 deletions
@@ -0,0 +1,648 @@
local L = ShadowUF.L
local playerClass = select(2, UnitClass("player"))
local function finalizeData(config, useMerge)
local self = ShadowUF
-- Merges all of the parentUnit options into the child if they weren't set.
-- if it's a table, it recurses inside the table and copies any nil values in too
local function mergeToChild(parent, child, forceMerge)
for key, value in pairs(parent) do
if( type(child[key]) == "table" ) then
mergeToChild(value, child[key], forceMerge)
elseif( type(value) == "table" ) then
child[key] = CopyTable(value)
elseif( forceMerge or ( value ~= nil and child[key] == nil ) ) then
child[key] = value
end
end
end
-- This makes sure that the unit has no values it shouldn't, for example if the defaults do not set incHeal for targettarget
-- and I try to set incHeal table here, then it'll remove it since it can't do that.
local function verifyTable(tbl, checkTable)
for key, value in pairs(tbl) do
if( type(value) == "table" ) then
if( not checkTable[key] ) then
tbl[key] = nil
else
for subKey, subValue in pairs(value) do
if( type(subValue) == "table" ) then
verifyTable(value, checkTable[key])
end
end
end
end
end
end
-- Set everything
for unit, child in pairs(config.units) do
if( self.defaults.profile.units[unit] ) then
if( not useMerge or ( useMerge and not self.db.profile.units[unit].enabled and self.db.profile.units[unit].height == 0 and self.db.profile.units[unit].width == 0 and self.db.profile.positions[unit].anchorPoint == "" and self.db.profile.positions[unit].point == "" ) ) then
-- Merge the primary parent table
mergeToChild(config.parentUnit, child)
-- Strip any invalid tables
verifyTable(child, self.defaults.profile.units[unit])
-- Merge it in
mergeToChild(child, self.db.profile.units[unit], true)
-- Merge position in too
if( useMerge and self.db.profile.positions[unit].point == "" and self.db.profile.positions[unit].relativePoint == "" and self.db.profile.positions[unit].anchorPoint == "" and self.db.profile.positions[unit].x == 0 and self.db.profile.positions[unit].y == 0 ) then
self.db.profile.positions[unit] = config.positions[unit]
end
end
end
end
self.db.profile.loadedLayout = true
if( not useMerge ) then
config.parentUnit = nil
config.units = nil
for key, data in pairs(config) do
self.db.profile[key] = data
end
end
end
function ShadowUF:LoadDefaultLayout(useMerge)
local config = {}
config.bars = {
texture = "Minimalist",
spacing = -1.25,
alpha = 1.0,
backgroundAlpha = 0.20,
}
config.auras = {
borderType = "light",
}
config.backdrop = {
tileSize = 1,
edgeSize = 5,
clip = 1,
inset = 3,
backgroundTexture = "Chat Frame",
backgroundColor = {r = 0, g = 0, b = 0, a = 0.80},
borderTexture = "None",
borderColor = {r = 0.30, g = 0.30, b = 0.50, a = 1},
}
config.hidden = {
cast = false, runes = true, buffs = false, party = true, player = true, pet = true, target = true, focus = true, boss = true, arena = true
}
config.font = {
name = "Myriad Condensed Web",
size = 11,
extra = "",
shadowColor = {r = 0, g = 0, b = 0, a = 1},
color = {r = 1, g = 1, b = 1, a = 1},
shadowX = 0.80,
shadowY = -0.80,
}
-- Some localizations do not work with Myriad Condensed Web, need to automatically swap it to a localization that will work for it
local SML = LibStub:GetLibrary("LibSharedMedia-3.0")
if( GetLocale() == "koKR" or GetLocale() == "zhCN" or GetLocale() == "zhTW" or GetLocale() == "ruRU" ) then
config.font.name = SML.DefaultMedia.font
end
config.classColors = {
HUNTER = {r = 0.67, g = 0.83, b = 0.45},
WARLOCK = {r = 0.58, g = 0.51, b = 0.79},
PRIEST = {r = 1.0, g = 1.0, b = 1.0},
PALADIN = {r = 0.96, g = 0.55, b = 0.73},
MAGE = {r = 0.41, g = 0.8, b = 0.94},
ROGUE = {r = 1.0, g = 0.96, b = 0.41},
DRUID = {r = 1.0, g = 0.49, b = 0.04},
SHAMAN = {r = 0.14, g = 0.35, b = 1.0},
WARRIOR = {r = 0.78, g = 0.61, b = 0.43},
DEATHKNIGHT = {r = 0.77, g = 0.12 , b = 0.23},
PET = {r = 0.20, g = 0.90, b = 0.20},
VEHICLE = {r = 0.23, g = 0.41, b = 0.23},
}
config.powerColors = {
MANA = {r = 0.30, g = 0.50, b = 0.85},
RAGE = {r = 0.90, g = 0.20, b = 0.30},
FOCUS = {r = 1.0, g = 0.85, b = 0},
ENERGY = {r = 1.0, g = 0.85, b = 0.10},
HAPPINESS = {r = 0.50, g = 0.90, b = 0.70},
RUNES = {r = 0.50, g = 0.50, b = 0.50},
RUNIC_POWER = {b = 0.60, g = 0.45, r = 0.35},
AMMOSLOT = {r = 0.85, g = 0.60, b = 0.55},
FUEL = {r = 0.85, g = 0.47, b = 0.36},
}
config.healthColors = {
tapped = {r = 0.5, g = 0.5, b = 0.5},
red = {r = 0.90, g = 0.0, b = 0.0},
green = {r = 0.20, g = 0.90, b = 0.20},
static = {r = 0.70, g = 0.20, b = 0.90},
yellow = {r = 0.93, g = 0.93, b = 0.0},
inc = {r = 0, g = 0.35, b = 0.23},
enemyUnattack = {r = 0.60, g = 0.20, b = 0.20},
hostile = {r = 0.90, g = 0.0, b = 0.0},
friendly = {r = 0.20, g = 0.90, b = 0.20},
neutral = {r = 0.93, g = 0.93, b = 0.0},
offline = {r = 0.50, g = 0.50, b = 0.50}
}
config.castColors = {
channel = {r = 0.25, g = 0.25, b = 1.0},
cast = {r = 1.0, g = 0.70, b = 0.30},
interrupted = {r = 1, g = 0, b = 0},
uninterruptible = {r = 0.71, g = 0, b = 1},
finished = {r = 0.10, g = 1.0, b = 0.10},
}
config.xpColors = {
normal = {r = 0.58, g = 0.0, b = 0.55},
rested = {r = 0.0, g = 0.39, b = 0.88},
}
config.positions = {
targettargettarget = {anchorPoint = "RC", anchorTo = "#SUFUnittargettarget", x = 0, y = 0},
targettarget = {anchorPoint = "TL", anchorTo = "#SUFUnittarget", x = 0, y = 0},
focustarget = {anchorPoint = "TL", anchorTo = "#SUFUnitfocus", x = 0, y = 0},
party = {point = "TOPLEFT", anchorTo = "#SUFUnitplayer", relativePoint = "TOPLEFT", movedAnchor = "TL", x = 0, y = -60},
focus = {anchorPoint = "RB", anchorTo = "#SUFUnittarget", x = 35, y = -4},
target = {anchorPoint = "RC", anchorTo = "#SUFUnitplayer", x = 50, y = 0},
player = {point = "TOPLEFT", anchorTo = "UIParent", relativePoint = "TOPLEFT", y = -25, x = 20},
pet = {anchorPoint = "TL", anchorTo = "#SUFUnitplayer", x = 0, y = 0},
pettarget = {anchorPoint = "C", anchorTo = "UIParent", x = 0, y = 0},
partypet = {anchorPoint = "RB", anchorTo = "$parent", x = 0, y = 0},
partytarget = {anchorPoint = "RT", anchorTo = "$parent", x = 0, y = 0},
raid = {anchorPoint = "C", anchorTo = "UIParent", x = 0, y = 0},
raidpet = {anchorPoint = "C", anchorTo = "UIParent", x = 0, y = 0},
maintank = {anchorPoint = "C", anchorTo = "UIParent", x = 0, y = 0},
maintanktarget = {anchorPoint = "RT", anchorTo = "$parent", x = 0, y = 0},
mainassist = {anchorPoint = "C", anchorTo = "UIParent", x = 0, y = 0},
mainassisttarget = {anchorPoint = "RT", anchorTo = "$parent", x = 0, y = 0},
arena = {anchorPoint = "C", anchorTo = "UIParent", point = "", relativePoint = "", x = 0, y = 0},
arenapet = {anchorPoint = "RB", anchorTo = "$parent", x = 0, y = 0},
arenatarget = {anchorPoint = "RT", anchorTo = "$parent", x = 0, y = 0},
boss = {anchorPoint = "C", anchorTo = "UIParent", point = "", relativePoint = "", x = 0, y = 0},
bosstarget = {anchorPoint = "RB", anchorTo = "$parent", x = 0, y = 0},
}
-- Parent unit options that all the children will inherit unless they override it
config.parentUnit = {
portrait = {enabled = false, type = "3D", alignment = "LEFT", width = 0.22, height = 0.50, order = 15, fullBefore = 0, fullAfter = 100},
auras = {
buffs = {enabled = false, anchorPoint = "BL", size = 16, perRow = 10, x = 0, y = 0},
debuffs = {enabled = false, anchorPoint = "BL", size = 16, perRow = 10, x = 0, y = 0},
},
text = {
{width = 0.50, name = L["Left text"], anchorTo = "$healthBar", anchorPoint = "CLI", x = 3, y = 0, size = 0},
{width = 0.60, name = L["Right text"], anchorTo = "$healthBar", anchorPoint = "CRI", x = -3, y = 0, size = 0},
{width = 0.50, name = L["Left text"], anchorTo = "$powerBar", anchorPoint = "CLI", x = 3, y = 0, size = 0},
{width = 0.60, name = L["Right text"], anchorTo = "$powerBar", anchorPoint = "CRI", x = -3, y = 0, size = 0},
{width = 1, name = L["Text"], anchorTo = "$emptyBar", anchorPoint = "CLI", x = 3, y = 0, size = 0},
},
indicators = {
raidTarget = {anchorTo = "$parent", anchorPoint = "C", size = 20, x = 0, y = 0},
class = {anchorTo = "$parent", anchorPoint = "BL", size = 16, x = 0, y = 0},
masterLoot = {anchorTo = "$parent", anchorPoint = "TL", size = 12, x = 16, y = -10},
leader = {anchorTo = "$parent", anchorPoint = "TL", size = 14, x = 2, y = -12},
pvp = {anchorTo = "$parent", anchorPoint = "TR", size = 22, x = 11, y = -21},
ready = {anchorTo = "$parent", anchorPoint = "LC", size = 24, x = 35, y = 0},
role = {anchorTo = "$parent", anchorPoint = "TL", size = 14, x = 30, y = -11},
status = {anchorTo = "$parent", anchorPoint = "LB", size = 16, x = 12, y = -2},
lfdRole = {enabled = true, anchorPoint = "BR", size = 14, x = 3, y = 14, anchorTo = "$parent"}
},
highlight = {size = 10},
combatText = {anchorTo = "$parent", anchorPoint = "C", x = 0, y = 0},
emptyBar = {background = true, height = 1, reactionType = "none", order = 0},
healthBar = {background = true, colorType = "class", reactionType = "npc", height = 1.20, order = 10},
powerBar = {background = true, height = 1.0, order = 20},
druidBar = {background = true, height = 0.40, order = 25},
xpBar = {background = true, height = 0.25, order = 55},
castBar = {background = true, height = 0.60, order = 40, icon = "HIDE", name = {enabled = true, size = 0, anchorTo = "$parent", rank = true, anchorPoint = "CLI", x = 1, y = 0}, time = {enabled = true, size = 0, anchorTo = "$parent", anchorPoint = "CRI", x = -1, y = 0}},
runeBar = {background = false, height = 0.40, order = 70},
totemBar = {background = false, height = 0.40, order = 70},
}
-- Units configuration
config.units = {
raid = {
width = 100,
height = 30,
scale = 0.85,
unitsPerColumn = 8,
maxColumns = 8,
columnSpacing = 5,
groupsPerRow = 8,
groupSpacing = 0,
attribPoint = "TOP",
attribAnchorPoint = "LEFT",
healthBar = {reactionType = "none"},
powerBar = {height = 0.30},
incHeal = {cap = 1},
indicators = {
pvp = {anchorTo = "$parent", anchorPoint = "BL", size = 22, x = 0, y = 11},
masterLoot = {anchorTo = "$parent", anchorPoint = "TR", size = 12, x = -2, y = -10},
role = {enabled = false, anchorTo = "$parent", anchorPoint = "BR", size = 14, x = 0, y = 14},
ready = {anchorTo = "$parent", anchorPoint = "LC", size = 24, x = 25, y = 0},
},
text = {
{text = "[(()afk() )][name]"},
{text = "[missinghp]"},
{text = ""},
{text = ""},
{text = "[(()afk() )][name]"},
},
},
raidpet = {
width = 90,
height = 30,
scale = 0.85,
unitsPerColumn = 8,
maxColumns = 8,
columnSpacing = 5,
groupsPerRow = 8,
groupSpacing = 0,
attribPoint = "TOP",
attribAnchorPoint = "LEFT",
healthBar = {reactionType = "none"},
powerBar = {height = 0.30},
incHeal = {cap = 1},
indicators = {
pvp = {anchorTo = "$parent", anchorPoint = "BL", size = 22, x = 0, y = 11},
masterLoot = {anchorTo = "$parent", anchorPoint = "TR", size = 12, x = -2, y = -10},
role = {enabled = false, anchorTo = "$parent", anchorPoint = "BR", size = 14, x = 0, y = 14},
ready = {anchorTo = "$parent", anchorPoint = "LC", size = 24, x = 25, y = 0},
},
text = {
{text = "[name]"},
{text = "[missinghp]"},
{text = ""},
{text = ""},
{text = "[name]"},
},
},
player = {
width = 190,
height = 45,
scale = 1.0,
portrait = {enabled = true, fullAfter = 50},
castBar = {order = 60},
xpBar = {order = 55},
runeBar = {enabled = true, order = 70},
totemBar = {enabled = true, order = 70},
auras = {
buffs = {enabled = false, maxRows = 1, temporary = playerClass == "ROGUE" or playerClass == "SHAMAN"},
debuffs = {enabled = false, maxRows = 1},
},
text = {
{text = "[(()afk() )][name][( ()group())]"},
{text = "[curmaxhp]"},
{text = "[perpp]"},
{text = "[curmaxpp]"},
{text = "[(()afk() )][name][( ()group())]"},
},
},
party = {
width = 190,
height = 45,
scale = 1.0,
attribPoint = "TOP",
attribAnchorPoint = "LEFT",
unitsPerColumn = 5,
columnSpacing = 30,
portrait = {enabled = true, fullAfter = 50},
castBar = {order = 60},
offset = 23,
auras = {
buffs = {enabled = true, maxRows = 1},
debuffs = {enabled = true, maxRows = 1},
},
text = {
{text = "[(()afk() )][name]"},
{text = "[curmaxhp]"},
{text = "[level( )][perpp]"},
{text = "[curmaxpp]"},
{text = "[(()afk() )][name]"},
},
},
boss = {
enabled = true,
width = 160,
height = 40,
scale = 1.0,
attribPoint = "TOP",
attribAnchorPoint = "LEFT",
offset = 20,
auras = {
buffs = {enabled = true, maxRows = 1, perRow = 8},
debuffs = {enabled = true, maxRows = 1, perRow = 8},
},
text = {
{text = "[name]"},
{text = "[curmaxhp]"},
{text = "[perpp]"},
{text = "[curmaxpp]"},
{text = "[name]"},
},
portrait = {enabled = false},
},
bosstarget = {
width = 90,
height = 25,
scale = 1.0,
powerBar = {height = 0.60},
text = {
{text = "[name]"},
{text = "[curhp]"},
{text = ""},
{text = ""},
{text = "[name]"},
},
},
arena = {
width = 170,
height = 45,
scale = 1.0,
attribPoint = "TOP",
attribAnchorPoint = "LEFT",
portrait = {enabled = false, fullAfter = 50},
castBar = {order = 60},
offset = 25,
auras = {
buffs = {enabled = true, maxRows = 1, perRow = 9},
debuffs = {enabled = true, maxRows = 1, perRow = 9},
},
text = {
{text = "[name]"},
{text = "[curmaxhp]"},
{text = "[perpp]"},
{text = "[curmaxpp]"},
{text = "[name]"},
},
},
arenapet = {
width = 90,
height = 25,
scale = 1.0,
powerBar = {height = 0.60},
text = {
{text = "[name]"},
{text = "[curhp]"},
{text = ""},
{text = ""},
{text = "[name]"},
},
},
arenatarget = {
width = 90,
height = 25,
scale = 1.0,
powerBar = {height = 0.60},
indicators = {
pvp = {anchorTo = "$parent", anchorPoint = "BL", size = 22, x = 0, y = 11},
},
text = {
{text = "[name]"},
{text = "[curhp]"},
{text = ""},
{text = ""},
{text = "[name]"},
},
},
maintank = {
width = 150,
height = 40,
scale = 1.0,
attribPoint = "TOP",
attribAnchorPoint = "LEFT",
offset = 5,
unitsPerColumn = 5,
maxColumns = 1,
columnSpacing = 5,
incHeal = {cap = 1},
portrait = {enabled = false, fullAfter = 50},
castBar = {order = 60},
auras = {
buffs = {enabled = false},
debuffs = {enabled = false},
},
text = {
{text = "[(()afk() )][name]"},
{text = "[curmaxhp]"},
{text = "[perpp]"},
{text = "[curmaxpp]"},
{text = "[(()afk() )][name]"},
},
},
maintanktarget = {
width = 150,
height = 40,
scale = 1.0,
auras = {
buffs = {enabled = false},
debuffs = {enabled = false},
},
text = {
{text = "[(()afk() )][name]"},
{text = "[curmaxhp]"},
{text = "[classification( )][perpp]", width = 0.50},
{text = "[curmaxpp]", anchorTo = "$powerBar", width = 0.60},
{text = "[(()afk() )][name]"},
},
},
mainassist = {
width = 150,
height = 40,
scale = 1.0,
attribPoint = "TOP",
attribAnchorPoint = "LEFT",
offset = 5,
unitsPerColumn = 5,
maxColumns = 1,
columnSpacing = 5,
incHeal = {cap = 1},
portrait = {enabled = false, fullAfter = 50},
castBar = {order = 60},
auras = {
buffs = {enabled = false},
debuffs = {enabled = false},
},
text = {
{text = "[(()afk() )][name]"},
{text = "[curmaxhp]"},
{text = "[level( )][perpp]"},
{text = "[curmaxpp]"},
{text = "[(()afk() )][name]"},
},
},
mainassisttarget = {
width = 150,
height = 40,
scale = 1.0,
auras = {
buffs = {enabled = false},
debuffs = {enabled = false},
},
text = {
{text = "[(()afk() )][name]"},
{text = "[curmaxhp]"},
{text = "[level( )][classification( )][perpp]", width = 0.50},
{text = "[curmaxpp]", anchorTo = "$powerBar", width = 0.60},
{text = "[(()afk() )][name]"},
},
},
partypet = {
width = 90,
height = 25,
scale = 1.0,
powerBar = {height = 0.60},
text = {
{text = "[name]"},
{text = "[curhp]"},
{text = ""},
{text = ""},
{text = "[name]"},
},
},
partytarget = {
width = 90,
height = 25,
scale = 1.0,
powerBar = {height = 0.60},
indicators = {
pvp = {anchorTo = "$parent", anchorPoint = "BL", size = 22, x = 0, y = 11},
},
text = {
{text = "[name]"},
{text = "[curhp]"},
{text = ""},
{text = ""},
{text = "[name]"},
},
},
target = {
width = 190,
height = 45,
scale = 1.0,
portrait = {enabled = true, alignment = "RIGHT", fullAfter = 50},
castBar = {order = 60},
comboPoints = {anchorTo = "$parent", order = 60, anchorPoint = "BR", x = -3, y = 8, size = 14, spacing = -4, growth = "LEFT", isBar = true},
indicators = {
lfdRole = {enabled = false}
},
auras = {
buffs = {enabled = true},
debuffs = {enabled = true},
},
text = {
{text = "[(()afk() )][name]"},
{text = "[curmaxhp]"},
{text = "[level( )][classification( )][perpp]", width = 0.50},
{text = "[curmaxpp]", anchorTo = "$powerBar", width = 0.60},
{text = "[(()afk() )][name]"},
},
},
pet = {
width = 190,
height = 30,
scale = 1.0,
powerBar = {height = 0.70},
healthBar = {reactionType = "none"},
portrait = {enabled = false, fullAfter = 50},
castBar = {order = 60},
indicators = {
happiness = {enabled = false, anchorTo = "$parent", anchorPoint = "BR", size = 14, x = 3, y = 13},
},
text = {
{text = "[name]"},
{text = "[curmaxhp]"},
{text = "[perpp]"},
{text = "[curmaxpp]"},
{text = "[name]"},
},
},
pettarget = {
width = 190,
height = 30,
scale = 1.0,
powerBar = {height = 0.70},
indicators = {
},
text = {
{text = "[name]"},
{text = "[curmaxhp]"},
{text = "[perpp]"},
{text = "[curmaxpp]"},
{text = "[name]"},
},
},
focus = {
width = 120,
height = 28,
scale = 1.0,
powerBar = {height = 0.60},
portrait = {enabled = false, fullAfter = 50},
castBar = {order = 60},
indicators = {
lfdRole = {enabled = false},
},
text = {
{text = "[(()afk() )][name]"},
{text = "[curhp]"},
{text = "[perpp]"},
{text = "[curpp]"},
{text = "[(()afk() )][name]"},
},
},
focustarget = {
width = 120,
height = 25,
scale = 1.0,
powerBar = {height = 0.60},
portrait = {alignment = "RIGHT"},
indicators = {
pvp = {anchorTo = "$parent", anchorPoint = "BL", size = 22, x = -3, y = 11},
},
text = {
{text = "[(()afk() )][name]"},
{text = "[curhp]"},
{text = ""},
{text = ""},
{text = "[(()afk() )][name]"},
},
},
targettarget = {
width = 110,
height = 30,
scale = 1.0,
powerBar = {height = 0.6},
portrait = {alignment = "RIGHT"},
indicators = {
pvp = {anchorTo = "$parent", anchorPoint = "BL", size = 22, x = -3, y = 11},
},
text = {
{text = "[name]"},
{text = "[curhp]"},
{text = "[perpp]"},
{text = "[curpp]"},
},
},
targettargettarget = {
width = 80,
height = 30,
scale = 1.0,
powerBar = {height = 0.6},
portrait = {alignment = "RIGHT"},
indicators = {
pvp = {anchorTo = "$parent", anchorPoint = "BL", size = 22, x = -3, y = 11},
},
text = {
{text = "[name]", width = 1.0},
{text = ""},
{text = ""},
{text = ""},
},
},
}
finalizeData(config, useMerge)
end
+46
View File
@@ -0,0 +1,46 @@
local Druid = {}
ShadowUF:RegisterModule(Druid, "druidBar", ShadowUF.L["Druid mana bar"], true, "DRUID")
function Druid:OnEnable(frame)
frame.druidBar = frame.druidBar or ShadowUF.Units:CreateBar(frame)
frame:RegisterUnitEvent("UNIT_MAXMANA", self, "Update")
frame:RegisterUnitEvent("UNIT_MANA", self, "Update")
frame:RegisterUnitEvent("UNIT_DISPLAYPOWER", self, "PowerChanged")
frame:RegisterUpdateFunc(self, "PowerChanged")
frame:RegisterUpdateFunc(self, "Update")
end
function Druid:OnDisable(frame)
frame:UnregisterAll(self)
end
function Druid:OnLayoutApplied(frame)
if( frame.visibility.druidBar ) then
local color = ShadowUF.db.profile.powerColors.MANA
if( not ShadowUF.db.profile.units[frame.unitType].druidBar.invert ) then
frame.druidBar:SetStatusBarColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.alpha)
if( not frame.druidBar.background.overrideColor ) then
frame.druidBar.background:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.backgroundAlpha)
end
else
frame.druidBar.background:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.alpha)
color = frame.druidBar.background.overrideColor or color
frame.druidBar:SetStatusBarColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.backgroundAlpha)
end
end
end
-- While power type is mana, show the bar once it is mana hide it.
function Druid:PowerChanged(frame)
local powerType = UnitPowerType(frame.unit)
ShadowUF.Layout:SetBarVisibility(frame, "druidBar", powerType == 1 or powerType == 3)
end
function Druid:Update(frame)
frame.druidBar:SetMinMaxValues(0, UnitPowerMax(frame.unit, 0))
frame.druidBar:SetValue(UnitIsDeadOrGhost(frame.unit) and 0 or not UnitIsConnected(frame.unit) and 0 or UnitPower(frame.unit, 0))
end
+59
View File
@@ -0,0 +1,59 @@
local Empty = {}
local fallbackColor
ShadowUF:RegisterModule(Empty, "emptyBar", ShadowUF.L["Empty bar"], true)
function Empty:OnEnable(frame)
frame.emptyBar = frame.emptyBar or ShadowUF.Units:CreateBar(frame)
frame.emptyBar:SetMinMaxValues(0, 1)
frame.emptyBar:SetValue(0)
fallbackColor = fallbackColor or {r = 0, g = 0, b = 0}
end
function Empty:OnDisable(frame)
frame:UnregisterAll(self)
end
function Empty:OnLayoutApplied(frame)
if( frame.visibility.emptyBar ) then
local color = frame.emptyBar.background.overrideColor or fallbackColor
frame.emptyBar.background:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.alpha)
if( ShadowUF.db.profile.units[frame.unitType].emptyBar.reaction or ShadowUF.db.profile.units[frame.unitType].emptyBar.class ) then
frame:RegisterUnitEvent("UNIT_FACTION", self, "UpdateColor")
frame:RegisterUpdateFunc(self, "UpdateColor")
else
self:OnDisable(frame)
end
end
end
function Empty:UpdateColor(frame)
local color
local reactionType = ShadowUF.db.profile.units[frame.unitType].emptyBar.reactionType
if( not UnitPlayerOrPetInRaid(frame.unit) and not UnitPlayerOrPetInParty(frame.unit) and ( ( ( reactionType == "player" or reactionType == "both" ) and UnitIsPlayer(frame.unit) and not UnitIsFriend(frame.unit, "player") ) or ( ( reactionType == "npc" or reactionType == "both" ) and not UnitIsPlayer(frame.unit) ) ) ) then
if( not UnitIsFriend(frame.unit, "player") and UnitPlayerControlled(frame.unit) ) then
if( UnitCanAttack("player", frame.unit) ) then
color = ShadowUF.db.profile.healthColors.hostile
else
color = ShadowUF.db.profile.healthColors.enemyUnattack
end
elseif( UnitReaction(frame.unit, "player") ) then
local reaction = UnitReaction(frame.unit, "player")
if( reaction > 4 ) then
color = ShadowUF.db.profile.healthColors.friendly
elseif( reaction == 4 ) then
color = ShadowUF.db.profile.healthColors.neutral
elseif( reaction < 4 ) then
color = ShadowUF.db.profile.healthColors.hostile
end
end
elseif( ShadowUF.db.profile.units[frame.unitType].emptyBar.class and ( UnitIsPlayer(frame.unit) or UnitCreatureFamily(frame.unit) ) ) then
local class = UnitCreatureFamily(frame.unit) or select(2, UnitClass(frame.unit))
color = class and ShadowUF.db.profile.classColors[class]
end
color = color or frame.emptyBar.background.overrideColor or fallbackColor
frame.emptyBar.background:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.alpha)
end
+140
View File
@@ -0,0 +1,140 @@
local Fader = {}
ShadowUF:RegisterModule(Fader, "fader", ShadowUF.L["Combat fader"])
local function faderUpdate(self, elapsed)
self.timeElapsed = self.timeElapsed + elapsed
if( self.timeElapsed >= self.fadeTime ) then
self.parent:SetAlpha(self.alphaEnd)
self:Hide()
if( self.fadeType == "in" ) then
self.parent:DisableRangeAlpha(false)
end
return
end
if( self.fadeType == "in" ) then
self.parent:SetAlpha((self.timeElapsed / self.fadeTime) * (self.alphaEnd - self.alphaStart) + self.alphaStart)
else
self.parent:SetAlpha(((self.fadeTime - self.timeElapsed) / self.fadeTime) * (self.alphaStart - self.alphaEnd) + self.alphaEnd)
end
end
local function startFading(self, type, alpha, speedyFade)
if( self.fader.fadeType == type ) then return end
if( type == "out" ) then
self:DisableRangeAlpha(true)
end
self.fader.fadeTime = speedyFade and 0.15 or type == "in" and 0.25 or type == "out" and 0.75
self.fader.fadeType = type
self.fader.timeElapsed = 0
self.fader.alphaEnd = alpha
self.fader.alphaStart = self:GetAlpha()
self.fader:Show()
end
function Fader:OnEnable(frame)
if( not frame.fader ) then
frame.fader = CreateFrame("Frame", nil, frame)
frame.fader.timeElapsed = 0
frame.fader.parent = frame
frame.fader:SetScript("OnUpdate", faderUpdate)
frame.fader:Hide()
end
frame:RegisterNormalEvent("PLAYER_REGEN_ENABLED", self, "Update")
frame:RegisterNormalEvent("PLAYER_REGEN_DISABLED", self, "Update")
frame:RegisterUpdateFunc(self, "Update")
if( InCombatLockdown() ) then
Fader:PLAYER_REGEN_DISABLED(frame, "PLAYER_REGEN_DISABLED")
else
Fader:PLAYER_REGEN_ENABLED(frame, "PLAYER_REGEN_ENABLED")
end
end
function Fader:OnLayoutApplied(frame)
if( frame.visibility.fader ) then
frame.fader.fadeType = nil
frame:DisableRangeAlpha(false)
end
end
function Fader:OnDisable(frame)
frame:UnregisterAll(self)
frame:SetAlpha(1.0)
if( frame.fader ) then
frame.fader.fadeType = nil
frame.fader:Hide()
end
end
-- While we're in combat, we don't care about the other events so we might as well unregister them
function Fader:PLAYER_REGEN_ENABLED(frame, event)
self:Update(frame, event)
frame:RegisterNormalEvent("PLAYER_TARGET_CHANGED", self, "Update")
frame:RegisterNormalEvent("UNIT_SPELLCAST_CHANNEL_START", self, "CastStart")
frame:RegisterNormalEvent("UNIT_SPELLCAST_CHANNEL_STOP", self, "CastStop")
frame:RegisterNormalEvent("UNIT_SPELLCAST_START", self, "CastStart")
frame:RegisterNormalEvent("UNIT_SPELLCAST_STOP", self, "CastStop")
frame:RegisterUnitEvent("UNIT_HEALTH", self, "Update")
frame:RegisterUnitEvent("UNIT_MANA", self, "Update")
frame:RegisterUnitEvent("UNIT_MAXHEALTH", self, "Update")
frame:RegisterUnitEvent("UNIT_MAXMANA", self, "Update")
end
function Fader:PLAYER_REGEN_DISABLED(frame, event)
self:Update(frame, event)
frame:UnregisterEvent("PLAYER_TARGET_CHANGED")
frame:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START")
frame:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
frame:UnregisterEvent("UNIT_SPELLCAST_START")
frame:UnregisterEvent("UNIT_SPELLCAST_STOP")
frame:UnregisterEvent("UNIT_HEALTH")
frame:UnregisterEvent("UNIT_MANA")
frame:UnregisterEvent("UNIT_MAXHEALTH")
frame:UnregisterEvent("UNIT_MAXMANA")
end
local activeCastID
function Fader:CastStart(frame, event, unit, spellName, spellRank, id)
if( unit ~= "player" or activeCastID == id ) then return end
activeCastID = id
frame.fader.playerCasting = true
self:Update(frame)
end
function Fader:CastStop(frame, event, unit, spellName, spellRank, id)
if( unit ~= "player" or activeCastID ~= id ) then return end
activeCastID = nil
frame.fader.playerCasting = nil
self:Update(frame)
end
function Fader:Update(frame, event)
-- In combat, fade back in
if( InCombatLockdown() or event == "PLAYER_REGEN_DISABLED" ) then
startFading(frame, "in", ShadowUF.db.profile.units[frame.unitType].fader.combatAlpha)
-- Player is casting, fade in
elseif( frame.fader.playerCasting ) then
startFading(frame, "in", ShadowUF.db.profile.units[frame.unitType].fader.combatAlpha, true)
-- Ether mana or energy is not at 100%, fade in
elseif( ( UnitPowerType(frame.unit) == 0 or UnitPowerType(frame.unit) == 3 ) and UnitPower(frame.unit) ~= UnitPowerMax(frame.unit) ) then
startFading(frame, "in", ShadowUF.db.profile.units[frame.unitType].fader.combatAlpha)
-- Health is not at max, fade in
elseif( UnitHealth(frame.unit) ~= UnitHealthMax(frame.unit) ) then
startFading(frame, "in", ShadowUF.db.profile.units[frame.unitType].fader.combatAlpha)
-- Targetting somebody, fade in
elseif( frame.unitType == "player" and UnitExists("target") ) then
startFading(frame, "in", ShadowUF.db.profile.units[frame.unitType].fader.combatAlpha)
-- Nothing else? Fade out!
else
startFading(frame, "out", ShadowUF.db.profile.units[frame.unitType].fader.inactiveAlpha)
end
end
+181
View File
@@ -0,0 +1,181 @@
local Health = {}
ShadowUF:RegisterModule(Health, "healthBar", ShadowUF.L["Health bar"], true)
local function getGradientColor(unit)
local percent = UnitHealth(unit) / UnitHealthMax(unit)
if( percent >= 1 ) then return ShadowUF.db.profile.healthColors.green.r, ShadowUF.db.profile.healthColors.green.g, ShadowUF.db.profile.healthColors.green.b end
if( percent == 0 ) then return ShadowUF.db.profile.healthColors.red.r, ShadowUF.db.profile.healthColors.red.g, ShadowUF.db.profile.healthColors.red.b end
local sR, sG, sB, eR, eG, eB = 0, 0, 0, 0, 0, 0
local modifier, inverseModifier = percent * 2, 0
if( percent > 0.50 ) then
sR, sG, sB = ShadowUF.db.profile.healthColors.green.r, ShadowUF.db.profile.healthColors.green.g, ShadowUF.db.profile.healthColors.green.b
eR, eG, eB = ShadowUF.db.profile.healthColors.yellow.r, ShadowUF.db.profile.healthColors.yellow.g, ShadowUF.db.profile.healthColors.yellow.b
modifier = modifier - 1
else
sR, sG, sB = ShadowUF.db.profile.healthColors.yellow.r, ShadowUF.db.profile.healthColors.yellow.g, ShadowUF.db.profile.healthColors.yellow.b
eR, eG, eB = ShadowUF.db.profile.healthColors.red.r, ShadowUF.db.profile.healthColors.red.g, ShadowUF.db.profile.healthColors.red.b
end
inverseModifier = 1 - modifier
return eR * inverseModifier + sR * modifier, eG * inverseModifier + sG * modifier, eB * inverseModifier + sB * modifier
end
Health.getGradientColor = getGradientColor
-- Not doing full health update, because other checks can lag behind without much issue
local function updateTimer(self)
local currentHealth = UnitHealth(self.parent.unit)
if( currentHealth == self.currentHealth ) then return end
self.currentHealth = currentHealth
self:SetValue(currentHealth)
-- As much as I would rather not have to do this in an OnUpdate, I don't have much choice large health changes in a single update will make them very clearly be lagging behind
for _, fontString in pairs(self.parent.fontStrings) do
if( fontString.fastHealth ) then
fontString:UpdateTags()
end
end
-- Update incoming heal number
if( self.parent.incHeal and self.parent.incHeal.healed ) then
self.parent.incHeal:SetValue(currentHealth + self.parent.incHeal.healed)
end
-- The target is not offline, and we have a health percentage so update the gradient
if( not self.parent.healthBar.wasOffline and self.parent.healthBar.hasPercent ) then
Health:SetBarColor(self.parent.healthBar, ShadowUF.db.profile.units[self.parent.unitType].healthBar.invert, getGradientColor(self.parent.unit))
end
end
function Health:OnEnable(frame)
if( not frame.healthBar ) then
frame.healthBar = ShadowUF.Units:CreateBar(frame)
end
frame:RegisterUnitEvent("UNIT_HEALTH", self, "Update")
frame:RegisterUnitEvent("UNIT_MAXHEALTH", self, "Update")
frame:RegisterUnitEvent("UNIT_FACTION", self, "UpdateColor")
frame:RegisterUnitEvent("UNIT_THREAT_SITUATION_UPDATE", self, "UpdateColor")
if( frame.unit == "pet" ) then
frame:RegisterUnitEvent("UNIT_HAPPINESS", self, "UpdateColor")
end
frame:RegisterUpdateFunc(self, "UpdateColor")
frame:RegisterUpdateFunc(self, "Update")
end
function Health:OnLayoutApplied(frame)
if( not frame.visibility.healthBar ) then return end
if( ShadowUF.db.profile.units[frame.unitType].healthBar.predicted ) then
frame.healthBar:SetScript("OnUpdate", updateTimer)
frame.healthBar.parent = frame
else
frame.healthBar:SetScript("OnUpdate", nil)
end
end
function Health:OnDisable(frame)
frame:UnregisterAll(self)
end
function Health:SetBarColor(bar, invert, r, g, b)
if( not invert ) then
bar:SetStatusBarColor(r, g, b, ShadowUF.db.profile.bars.alpha)
if( not bar.background.overrideColor ) then
bar.background:SetVertexColor(r, g, b, ShadowUF.db.profile.bars.backgroundAlpha)
end
else
bar.background:SetVertexColor(r, g, b, ShadowUF.db.profile.bars.alpha)
if( not bar.background.overrideColor ) then
bar:SetStatusBarColor(0, 0, 0, 1 - ShadowUF.db.profile.bars.backgroundAlpha)
else
bar:SetStatusBarColor(bar.background.overrideColor.r, bar.background.overrideColor.g, bar.background.overrideColor.b, 1 - ShadowUF.db.profile.bars.backgroundAlpha)
end
end
end
function Health:UpdateColor(frame)
frame.healthBar.hasReaction = nil
frame.healthBar.hasPercent = nil
frame.healthBar.wasOffline = nil
local color
local unit = frame.unit
local reactionType = ShadowUF.db.profile.units[frame.unitType].healthBar.reactionType
if( not UnitIsConnected(unit) ) then
frame.healthBar.wasOffline = true
self:SetBarColor(frame.healthBar, ShadowUF.db.profile.units[frame.unitType].healthBar.invert, ShadowUF.db.profile.healthColors.offline.r, ShadowUF.db.profile.healthColors.offline.g, ShadowUF.db.profile.healthColors.offline.b)
return
elseif( ShadowUF.db.profile.units[frame.unitType].healthBar.colorAggro and UnitThreatSituation(frame.unit) == 3 ) then
self:SetBarColor(frame.healthBar, ShadowUF.db.profile.units[frame.unitType].healthBar.invert, ShadowUF.db.profile.healthColors.hostile.r, ShadowUF.db.profile.healthColors.hostile.g, ShadowUF.db.profile.healthColors.hostile.b)
return
elseif( frame.inVehicle ) then
color = ShadowUF.db.profile.classColors.VEHICLE
elseif( not UnitIsTappedByPlayer(unit) and UnitIsTapped(unit) and UnitCanAttack("player", unit) ) then
color = ShadowUF.db.profile.healthColors.tapped
elseif( unit == "pet" and reactionType == "happiness" and GetPetHappiness() ) then
local happiness = GetPetHappiness()
if( happiness == 3 ) then
color = ShadowUF.db.profile.healthColors.friendly
elseif( happiness == 2 ) then
color = ShadowUF.db.profile.healthColors.neutral
elseif( happiness == 1 ) then
color = ShadowUF.db.profile.healthColors.hostile
end
elseif( not UnitPlayerOrPetInRaid(unit) and not UnitPlayerOrPetInParty(unit) and ( ( ( reactionType == "player" or reactionType == "both" ) and UnitIsPlayer(unit) and not UnitIsFriend(unit, "player") ) or ( ( reactionType == "npc" or reactionType == "both" ) and not UnitIsPlayer(unit) ) ) ) then
if( not UnitIsFriend(unit, "player") and UnitPlayerControlled(unit) ) then
if( UnitCanAttack("player", unit) ) then
color = ShadowUF.db.profile.healthColors.hostile
else
color = ShadowUF.db.profile.healthColors.enemyUnattack
end
elseif( UnitReaction(unit, "player") ) then
local reaction = UnitReaction(unit, "player")
if( reaction > 4 ) then
color = ShadowUF.db.profile.healthColors.friendly
elseif( reaction == 4 ) then
color = ShadowUF.db.profile.healthColors.neutral
elseif( reaction < 4 ) then
color = ShadowUF.db.profile.healthColors.hostile
end
end
elseif( ShadowUF.db.profile.units[frame.unitType].healthBar.colorType == "class" and ( UnitIsPlayer(unit) or UnitCreatureFamily(unit) ) ) then
local class = UnitCreatureFamily(frame.unit) or select(2, UnitClass(frame.unit))
color = class and ShadowUF.db.profile.classColors[class]
elseif( ShadowUF.db.profile.units[frame.unitType].healthBar.colorType == "static" ) then
color = ShadowUF.db.profile.healthColors.static
end
if( color ) then
self:SetBarColor(frame.healthBar, ShadowUF.db.profile.units[frame.unitType].healthBar.invert, color.r, color.g, color.b)
else
frame.healthBar.hasPercent = true
self:SetBarColor(frame.healthBar, ShadowUF.db.profile.units[frame.unitType].healthBar.invert, getGradientColor(unit))
end
end
function Health:Update(frame)
local isOffline = not UnitIsConnected(frame.unit)
frame.isDead = UnitIsDeadOrGhost(frame.unit)
frame.healthBar.currentHealth = UnitHealth(frame.unit)
frame.healthBar:SetMinMaxValues(0, UnitHealthMax(frame.unit))
frame.healthBar:SetValue(isOffline and UnitHealthMax(frame.unit) or frame.isDead and 0 or frame.healthBar.currentHealth)
-- Unit is offline, fill bar up + grey it
if( isOffline ) then
frame.healthBar.wasOffline = true
frame.unitIsOnline = nil
self:SetBarColor(frame.healthBar, ShadowUF.db.profile.units[frame.unitType].healthBar.invert, ShadowUF.db.profile.healthColors.offline.r, ShadowUF.db.profile.healthColors.offline.g, ShadowUF.db.profile.healthColors.offline.b)
-- The unit was offline, but they no longer are so we need to do a forced color update
elseif( frame.healthBar.wasOffline ) then
frame.healthBar.wasOffline = nil
self:UpdateColor(frame)
-- Color health by percentage
elseif( frame.healthBar.hasPercent ) then
self:SetBarColor(frame.healthBar, ShadowUF.db.profile.units[frame.unitType].healthBar.invert, getGradientColor(frame.unit))
end
end
+155
View File
@@ -0,0 +1,155 @@
local Highlight = {}
local goldColor, mouseColor = {r = 0.75, g = 0.75, b = 0.35}, {r = 0.75, g = 0.75, b = 0.50}
ShadowUF:RegisterModule(Highlight, "highlight", ShadowUF.L["Highlight"])
-- Might seem odd to hook my code in the core manually, but HookScript is ~40% slower due to it being a secure hook
local function OnEnter(frame)
if( ShadowUF.db.profile.units[frame.unitType].highlight.mouseover ) then
frame.highlight.hasMouseover = true
Highlight:Update(frame)
end
frame.highlight.OnEnter(frame)
end
local function OnLeave(frame)
if( ShadowUF.db.profile.units[frame.unitType].highlight.mouseover ) then
frame.highlight.hasMouseover = nil
Highlight:Update(frame)
end
frame.highlight.OnLeave(frame)
end
function Highlight:OnEnable(frame)
if( not frame.highlight ) then
frame.highlight = CreateFrame("Frame", nil, frame)
frame.highlight:SetFrameLevel(frame.topFrameLevel)
frame.highlight:SetAllPoints(frame)
frame.highlight:SetSize(1, 1)
frame.highlight.top = frame.highlight:CreateTexture(nil, "OVERLAY")
frame.highlight.top:SetBlendMode("ADD")
frame.highlight.top:SetTexture("Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\highlight")
frame.highlight.top:SetPoint("TOPLEFT", frame, ShadowUF.db.profile.backdrop.inset, -ShadowUF.db.profile.backdrop.inset)
frame.highlight.top:SetPoint("TOPRIGHT", frame, -ShadowUF.db.profile.backdrop.inset, ShadowUF.db.profile.backdrop.inset)
frame.highlight.top:SetHeight(30)
frame.highlight.top:SetTexCoord(0.3125, 0.625, 0, 0.3125)
frame.highlight.top:SetHorizTile(false)
frame.highlight.left = frame.highlight:CreateTexture(nil, "OVERLAY")
frame.highlight.left:SetBlendMode("ADD")
frame.highlight.left:SetTexture("Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\highlight")
frame.highlight.left:SetPoint("TOPLEFT", frame, ShadowUF.db.profile.backdrop.inset, -ShadowUF.db.profile.backdrop.inset)
frame.highlight.left:SetPoint("BOTTOMLEFT", frame, -ShadowUF.db.profile.backdrop.inset, ShadowUF.db.profile.backdrop.inset)
frame.highlight.left:SetWidth(30)
frame.highlight.left:SetTexCoord(0, 0.3125, 0.3125, 0.625)
frame.highlight.left:SetHorizTile(false)
frame.highlight.right = frame.highlight:CreateTexture(nil, "OVERLAY")
frame.highlight.right:SetBlendMode("ADD")
frame.highlight.right:SetTexture("Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\highlight")
frame.highlight.right:SetPoint("TOPRIGHT", frame, -ShadowUF.db.profile.backdrop.inset, -ShadowUF.db.profile.backdrop.inset)
frame.highlight.right:SetPoint("BOTTOMRIGHT", frame, 0, ShadowUF.db.profile.backdrop.inset)
frame.highlight.right:SetWidth(30)
frame.highlight.right:SetTexCoord(0.625, 0.93, 0.3125, 0.625)
frame.highlight.right:SetHorizTile(false)
frame.highlight.bottom = frame.highlight:CreateTexture(nil, "OVERLAY")
frame.highlight.bottom:SetBlendMode("ADD")
frame.highlight.bottom:SetTexture("Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\highlight")
frame.highlight.bottom:SetPoint("BOTTOMLEFT", frame, ShadowUF.db.profile.backdrop.inset, ShadowUF.db.profile.backdrop.inset)
frame.highlight.bottom:SetPoint("BOTTOMRIGHT", frame, -ShadowUF.db.profile.backdrop.inset, ShadowUF.db.profile.backdrop.inset)
frame.highlight.bottom:SetHeight(30)
frame.highlight.bottom:SetTexCoord(0.3125, 0.625, 0.625, 0.93)
frame.highlight.bottom:SetHorizTile(false)
frame.highlight:Hide()
end
frame.highlight.top:SetHeight(ShadowUF.db.profile.units[frame.unitType].highlight.size)
frame.highlight.bottom:SetHeight(ShadowUF.db.profile.units[frame.unitType].highlight.size)
frame.highlight.left:SetWidth(ShadowUF.db.profile.units[frame.unitType].highlight.size)
frame.highlight.right:SetWidth(ShadowUF.db.profile.units[frame.unitType].highlight.size)
if( ShadowUF.db.profile.units[frame.unitType].highlight.aggro ) then
frame:RegisterUnitEvent("UNIT_THREAT_SITUATION_UPDATE", self, "UpdateThreat")
frame:RegisterUpdateFunc(self, "UpdateThreat")
end
if( ShadowUF.db.profile.units[frame.unitType].highlight.attention and frame.unitType ~= "target" and frame.unitType ~= "focus" ) then
frame:RegisterNormalEvent("PLAYER_TARGET_CHANGED", self, "UpdateAttention")
frame:RegisterNormalEvent("PLAYER_FOCUS_CHANGED", self, "UpdateAttention")
frame:RegisterUpdateFunc(self, "UpdateAttention")
end
if( ShadowUF.db.profile.units[frame.unitType].highlight.debuff ) then
frame:RegisterNormalEvent("UNIT_AURA", self, "UpdateAura")
frame:RegisterUpdateFunc(self, "UpdateAura")
end
if( ShadowUF.db.profile.units[frame.unitType].highlight.mouseover and not frame.highlight.OnEnter ) then
frame.highlight.OnEnter = frame:GetScript("OnEnter")
frame.highlight.OnLeave = frame:GetScript("OnLeave")
frame:SetScript("OnEnter", OnEnter)
frame:SetScript("OnLeave", OnLeave)
end
end
function Highlight:OnLayoutApplied(frame)
if( frame.visibility.highlight ) then
self:OnDisable(frame)
self:OnEnable(frame)
end
end
function Highlight:OnDisable(frame)
frame:UnregisterAll(self)
frame.highlight.hasDebuff = nil
frame.highlight.hasThreat = nil
frame.highlight.hasAttention = nil
frame.highlight.hasMouseover = nil
frame.highlight:Hide()
end
function Highlight:Update(frame)
local color
if( frame.highlight.hasDebuff ) then
color = DebuffTypeColor[frame.highlight.hasDebuff]
elseif( frame.highlight.hasThreat ) then
color = ShadowUF.db.profile.healthColors.hostile
elseif( frame.highlight.hasAttention ) then
color = goldColor
elseif( frame.highlight.hasMouseover ) then
color = mouseColor
end
if( color ) then
frame.highlight.top:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.units[frame.unitType].highlight.alpha)
frame.highlight.left:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.units[frame.unitType].highlight.alpha)
frame.highlight.bottom:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.units[frame.unitType].highlight.alpha)
frame.highlight.right:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.units[frame.unitType].highlight.alpha)
frame.highlight:Show()
else
frame.highlight:Hide()
end
end
function Highlight:UpdateThreat(frame)
frame.highlight.hasThreat = UnitThreatSituation(frame.unit) == 3 or nil
self:Update(frame)
end
function Highlight:UpdateAttention(frame)
frame.highlight.hasAttention = UnitIsUnit(frame.unit, "target") or UnitIsUnit(frame.unit, "focus") or nil
self:Update(frame)
end
function Highlight:UpdateAura(frame)
-- In theory, we don't need aura scanning because the first debuff returned is always one we can cure... in theory
frame.highlight.hasDebuff = UnitIsFriend(frame.unit, "player") and select(5, UnitDebuff(frame.unit, 1, "RAID")) or nil
self:Update(frame)
end
+195
View File
@@ -0,0 +1,195 @@
local HealComm = LibStub("LibHealComm-4.0", true)
if( not HealComm ) then return end
local IncHeal = {}
local frames = {}
local playerEndTime, playerGUID
ShadowUF:RegisterModule(IncHeal, "incHeal", ShadowUF.L["Incoming heals"])
ShadowUF.Tags.customEvents["HEALCOMM"] = IncHeal
-- How far ahead to show heals at most
local INCOMING_SECONDS = 3
function IncHeal:OnEnable(frame)
frames[frame] = true
frame.incHeal = frame.incHeal or ShadowUF.Units:CreateBar(frame)
frame:RegisterUnitEvent("UNIT_MAXHEALTH", self, "UpdateFrame")
frame:RegisterUnitEvent("UNIT_HEALTH", self, "UpdateFrame")
frame:RegisterUpdateFunc(self, "UpdateFrame")
self:Setup()
end
function IncHeal:OnDisable(frame)
frame:UnregisterAll(self)
frame.incHeal:Hide()
if( not frame.hasHCTag ) then
frames[frame] = nil
self:Setup()
end
end
function IncHeal:OnLayoutApplied(frame)
if( frame.visibility.incHeal and frame.visibility.healthBar ) then
frame.incHeal:SetHeight(frame.healthBar:GetHeight())
frame.incHeal:SetStatusBarTexture(ShadowUF.Layout.mediaPath.statusbar)
frame.incHeal:SetStatusBarColor(ShadowUF.db.profile.healthColors.inc.r, ShadowUF.db.profile.healthColors.inc.g, ShadowUF.db.profile.healthColors.inc.b, ShadowUF.db.profile.bars.alpha)
frame.incHeal:GetStatusBarTexture():SetHorizTile(false)
frame.incHeal:Hide()
-- When we can cheat and put the incoming bar right behind the health bar, we can efficiently show the incoming heal bar
-- if the main bar has a transparency set, then we need a more complicated method to stop the health bar from being darker with incoming heals up
if( ( ShadowUF.db.profile.units[frame.unitType].healthBar.invert and ShadowUF.db.profile.bars.backgroundAlpha == 0 ) or ( not ShadowUF.db.profile.units[frame.unitType].healthBar.invert and ShadowUF.db.profile.bars.alpha == 1 ) ) then
frame.incHeal.simple = true
frame.incHeal:SetWidth(frame.healthBar:GetWidth() * ShadowUF.db.profile.units[frame.unitType].incHeal.cap)
frame.incHeal:SetFrameLevel(frame.topFrameLevel - 3)
frame.incHeal:ClearAllPoints()
frame.incHeal:SetPoint("TOPLEFT", frame.healthBar)
frame.incHeal:SetPoint("BOTTOMLEFT", frame.healthBar)
else
frame.incHeal.simple = nil
frame.incHeal:SetFrameLevel(frame.topFrameLevel)
frame.incHeal:SetWidth(1)
frame.incHeal:SetMinMaxValues(0, 1)
frame.incHeal:SetValue(1)
local x, y = select(4, frame.healthBar:GetPoint())
frame.incHeal:ClearAllPoints()
frame.incHeal.healthX = x
frame.incHeal.healthY = y
frame.incHeal.healthWidth = frame.healthBar:GetWidth()
frame.incHeal.maxWidth = frame.incHeal.healthWidth * ShadowUF.db.profile.units[frame.unitType].incHeal.cap
frame.incHeal.cappedWidth = frame.incHeal.healthWidth * (ShadowUF.db.profile.units[frame.unitType].incHeal.cap - 1)
end
end
end
-- Since I don't want a more complicated system where both incheal.lua and tags.lua are watching the same events
-- I'll update the HC tags through here instead
function IncHeal:EnableTag(frame)
frames[frame] = true
frame.hasHCTag = true
self:Setup()
end
function IncHeal:DisableTag(frame)
frame.hasHCTag = nil
if( not frame.visibility.incHeal ) then
frames[frame] = nil
self:Setup()
end
end
-- Check if we need to register callbacks
function IncHeal:Setup()
playerGUID = UnitGUID("player")
local enabled
for frame in pairs(frames) do
enabled = true
break
end
if( not enabled ) then
if( HealComm ) then
HealComm:UnregisterAllCallbacks(IncHeal)
end
return
end
HealComm.RegisterCallback(self, "HealComm_HealStarted", "HealComm_HealUpdated")
HealComm.RegisterCallback(self, "HealComm_HealStopped")
HealComm.RegisterCallback(self, "HealComm_HealDelayed", "HealComm_HealUpdated")
HealComm.RegisterCallback(self, "HealComm_HealUpdated")
HealComm.RegisterCallback(self, "HealComm_ModifierChanged")
HealComm.RegisterCallback(self, "HealComm_GUIDDisappeared")
end
-- Update any tags using HC
function IncHeal:UpdateTags(frame, amount)
if( not frame.fontStrings or not frame.hasHCTag ) then return end
for _, fontString in pairs(frame.fontStrings) do
if( fontString.HEALCOMM ) then
fontString.incoming = amount > 0 and amount or nil
fontString:UpdateTags()
end
end
end
local function updateHealthBar(frame, interrupted)
-- This makes sure that when a heal like Tranquility is cast, it won't show the entire cast but cap it at 4 seconds into the future
local time = GetTime()
local timeBand = playerEndTime and math.min(playerEndTime - time, INCOMING_SECONDS) or INCOMING_SECONDS
local healed = (HealComm:GetHealAmount(frame.unitGUID, HealComm.ALL_HEALS, time + timeBand) or 0) * HealComm:GetHealModifier(frame.unitGUID)
-- Update any tags that are using HC data
IncHeal:UpdateTags(frame, healed)
-- Bar is also supposed to be enabled, lets update that too
if( frame.visibility.incHeal and frame.visibility.healthBar ) then
if( healed > 0 ) then
frame.incHeal.healed = healed
frame.incHeal:Show()
-- When the primary bar has an alpha of 100%, we can cheat and do incoming heals easily. Otherwise we need to do it a more complex way to keep it looking good
if( frame.incHeal.simple ) then
frame.incHeal.total = UnitHealth(frame.unit) + healed
frame.incHeal:SetMinMaxValues(0, UnitHealthMax(frame.unit) * ShadowUF.db.profile.units[frame.unitType].incHeal.cap)
frame.incHeal:SetValue(frame.incHeal.total)
else
local health, maxHealth = UnitHealth(frame.unit), UnitHealthMax(frame.unit)
local healthWidth = frame.incHeal.healthWidth * (health / maxHealth)
local incWidth = frame.healthBar:GetWidth() * (healed / health)
if( (healthWidth + incWidth) > frame.incHeal.maxWidth ) then
incWidth = frame.incHeal.cappedWidth
end
frame.incHeal:SetWidth(incWidth)
frame.incHeal:SetPoint("TOPLEFT", SUFUnitplayer, "TOPLEFT", frame.incHeal.healthX + healthWidth, frame.incHeal.healthY)
end
else
frame.incHeal.total = nil
frame.incHeal.healed = nil
frame.incHeal:Hide()
end
end
end
function IncHeal:UpdateFrame(frame)
updateHealthBar(frame, true)
end
function IncHeal:UpdateIncoming(interrupted, ...)
for frame in pairs(frames) do
for i=1, select("#", ...) do
if( select(i, ...) == frame.unitGUID ) then
updateHealthBar(frame, interrupted)
end
end
end
end
-- Handle callbacks from HealComm
function IncHeal:HealComm_HealUpdated(event, casterGUID, spellID, healType, endTime, ...)
if( casterGUID == playerGUID and bit.band(healType, HealComm.CASTED_HEALS) > 0 ) then playerEndTime = endTime end
self:UpdateIncoming(nil, ...)
end
function IncHeal:HealComm_HealStopped(event, casterGUID, spellID, healType, interrupted, ...)
if( casterGUID == playerGUID and bit.band(healType, HealComm.CASTED_HEALS) > 0 ) then playerEndTime = nil end
self:UpdateIncoming(interrupted, ...)
end
function IncHeal:HealComm_ModifierChanged(event, guid)
self:UpdateIncoming(nil, guid)
end
function IncHeal:HealComm_GUIDDisappeared(event, guid)
self:UpdateIncoming(true, guid)
end
+394
View File
@@ -0,0 +1,394 @@
local Indicators = {list = {"status", "pvp", "leader", "masterLoot", "raidTarget", "happiness", "ready", "role", "lfdRole", "class"}}
local leavingWorld
ShadowUF:RegisterModule(Indicators, "indicators", ShadowUF.L["Indicators"])
function Indicators:UpdateClass(frame)
if( not frame.indicators.class or not frame.indicators.class.enabled ) then return end
local class = select(2, UnitClass(frame.unit))
if( UnitIsPlayer(frame.unit) and class ) then
local coords = CLASS_BUTTONS[class]
frame.indicators.class:SetTexture("Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Classes")
frame.indicators.class:SetTexCoord(coords[1], coords[2], coords[3], coords[4])
frame.indicators.class:Show()
else
frame.indicators.class:Hide()
end
end
function Indicators:UpdateHappiness(frame)
if( not frame.indicators.happiness or not frame.indicators.happiness.enabled ) then return end
local happiness = GetPetHappiness()
if( not happiness ) then
frame.indicators.happiness:Hide()
elseif( happiness == 3 ) then
frame.indicators.happiness:SetTexCoord(0, 0.1875, 0, 0.359375)
frame.indicators.happiness:Show()
elseif( happiness == 2 ) then
frame.indicators.happiness:SetTexCoord(0.1875, 0.375, 0, 0.359375)
frame.indicators.happiness:Show()
elseif( happiness == 1 ) then
frame.indicators.happiness:SetTexCoord(0.375, 0.5625, 0, 0.359375)
frame.indicators.happiness:Show()
end
end
function Indicators:UpdateMasterLoot(frame)
if( not frame.indicators.masterLoot or not frame.indicators.masterLoot.enabled ) then return end
local lootType, partyID, raidID = GetLootMethod()
if( lootType ~= "master" ) then
frame.indicators.masterLoot:Hide()
elseif( ( partyID and partyID == 0 and UnitIsUnit(frame.unit, "player") ) or ( partyID and partyID > 0 and UnitIsUnit(frame.unit, ShadowUF.partyUnits[partyID]) ) or ( raidID and raidID > 0 and UnitIsUnit(frame.unit, ShadowUF.raidUnits[raidID]) ) ) then
frame.indicators.masterLoot:Show()
else
frame.indicators.masterLoot:Hide()
end
end
function Indicators:UpdateRaidTarget(frame)
if( not frame.indicators.raidTarget or not frame.indicators.raidTarget.enabled ) then return end
if( UnitExists(frame.unit) and GetRaidTargetIndex(frame.unit) ) then
SetRaidTargetIconTexture(frame.indicators.raidTarget, GetRaidTargetIndex(frame.unit))
frame.indicators.raidTarget:Show()
else
frame.indicators.raidTarget:Hide()
end
end
function Indicators:UpdateLFDRole(frame, event)
if( not frame.indicators.lfdRole or not frame.indicators.lfdRole.enabled ) then return end
local isTank, isHealer, isDamage = UnitGroupRolesAssigned(frame.unitOwner)
if( isTank ) then
frame.indicators.lfdRole:SetTexCoord(0, 19/64, 22/64, 41/64)
frame.indicators.lfdRole:Show()
elseif( isHealer ) then
frame.indicators.lfdRole:SetTexCoord(20/64, 39/64, 1/64, 20/64)
frame.indicators.lfdRole:Show()
elseif( isDamage ) then
frame.indicators.lfdRole:SetTexCoord(20/64, 39/64, 22/64, 41/64)
frame.indicators.lfdRole:Show()
else
frame.indicators.lfdRole:Hide()
end
end
function Indicators:UpdateRole(frame, event)
if( not frame.indicators.role or not frame.indicators.role.enabled ) then return end
if( leavingWorld or not UnitInRaid(frame.unit) and not UnitInParty(frame.unit) ) then
frame.indicators.role:Hide()
elseif( GetPartyAssignment("MAINTANK", frame.unit) ) then
frame.indicators.role:SetTexture("Interface\\GroupFrame\\UI-Group-MainTankIcon")
frame.indicators.role:Show()
elseif( GetPartyAssignment("MAINASSIST", frame.unit) ) then
frame.indicators.role:SetTexture("Interface\\GroupFrame\\UI-Group-MainAssistIcon")
frame.indicators.role:Show()
else
frame.indicators.role:Hide()
end
end
function Indicators:UpdateLeader(frame)
self:UpdateMasterLoot(frame)
self:UpdateRole(frame)
self:UpdateLFDRole(frame)
if( not frame.indicators.leader or not frame.indicators.leader.enabled ) then return end
if( UnitIsPartyLeader(frame.unit) ) then
frame.indicators.leader:Show()
else
frame.indicators.leader:Hide()
end
end
function Indicators:UpdatePVPFlag(frame)
if( not frame.indicators.pvp or not frame.indicators.pvp.enabled ) then return end
if( UnitIsPVP(frame.unit) and UnitFactionGroup(frame.unit) ) then
frame.indicators.pvp:SetTexture(string.format("Interface\\TargetingFrame\\UI-PVP-%s", UnitFactionGroup(frame.unit)))
frame.indicators.pvp:Show()
elseif( UnitIsPVPFreeForAll(frame.unit) ) then
frame.indicators.pvp:SetTexture("Interface\\TargetingFrame\\UI-PVP-FFA")
frame.indicators.pvp:Show()
else
frame.indicators.pvp:Hide()
end
end
-- Non-player units do not give events when they enter or leave combat, so polling is necessary
local function combatMonitor(self, elapsed)
self.timeElapsed = self.timeElapsed + elapsed
if( self.timeElapsed < 1 ) then return end
self.timeElapsed = self.timeElapsed - 1
if( UnitAffectingCombat(self.parent.unit) ) then
self.status:Show()
else
self.status:Hide()
end
end
-- It looks like the combat check for players is a bit buggy when they are in a vehicle, so swap it to also check polling
function Indicators:CheckVehicle(frame)
frame.indicators.timeElapsed = 0
frame.indicators:SetScript("OnUpdate", frame.inVehicle and combatMonitor or nil)
end
function Indicators:UpdateStatus(frame)
if( not frame.indicators.status or not frame.indicators.status.enabled ) then return end
if( UnitAffectingCombat(frame.unitOwner) ) then
frame.indicators.status:SetTexCoord(0.50, 1.0, 0.0, 0.49)
frame.indicators.status:Show()
elseif( frame.unitRealType == "player" and IsResting() ) then
frame.indicators.status:SetTexCoord(0.0, 0.50, 0.0, 0.421875)
frame.indicators.status:Show()
else
frame.indicators.status:Hide()
end
end
-- Ready check fading once the check complete
local function fadeReadyStatus(self, elapsed)
self.timeLeft = self.timeLeft - elapsed
self.ready:SetAlpha(self.timeLeft / self.startTime)
if( self.timeLeft <= 0 ) then
self:SetScript("OnUpdate", nil)
self.ready.status = nil
self.ready:Hide()
end
end
local FADEOUT_TIME = 6
function Indicators:UpdateReadyCheck(frame, event)
if( not frame.indicators.ready or not frame.indicators.ready.enabled ) then return end
-- We're done, and should fade it out if it's shown
if( event == "READY_CHECK_FINISHED" ) then
if( not frame.indicators.ready:IsShown() ) then return end
-- Create the central timer frame if ones not already made
if( not self.fadeTimer ) then
self.fadeTimer = CreateFrame("Frame", nil)
self.fadeTimer.fadeList = {}
self.fadeTimer:Hide()
self.fadeTimer:SetScript("OnUpdate", function(self, elapsed)
local hasTimer
for frame, timeLeft in pairs(self.fadeList) do
hasTimer = true
self.fadeList[frame] = timeLeft - elapsed
frame:SetAlpha(self.fadeList[frame] / FADEOUT_TIME)
if( self.fadeList[frame] <= 0 ) then
self.fadeList[frame] = nil
frame:Hide()
end
end
if( not hasTimer ) then self:Hide() end
end)
end
-- Start the timer
self.fadeTimer.fadeList[frame.indicators.ready] = FADEOUT_TIME
self.fadeTimer:Show()
-- Player never responded so they are AFK
if( frame.indicators.ready.status == "waiting" ) then
frame.indicators.ready:SetTexture("Interface\\RaidFrame\\ReadyCheck-NotReady")
end
return
end
-- Have a state change in ready status
local status = GetReadyCheckStatus(frame.unit)
if( not status ) then
frame.indicators.ready.status = nil
frame.indicators.ready:Hide()
return
end
if( status == "ready" ) then
frame.indicators.ready:SetTexture(READY_CHECK_READY_TEXTURE)
elseif( status == "notready" ) then
frame.indicators.ready:SetTexture(READY_CHECK_NOT_READY_TEXTURE)
elseif( status == "waiting" ) then
frame.indicators.ready:SetTexture(READY_CHECK_WAITING_TEXTURE)
end
frame.indicators:SetScript("OnUpdate", nil)
frame.indicators.ready.status = status
frame.indicators.ready:SetAlpha(1.0)
frame.indicators.ready:Show()
end
function Indicators:OnEnable(frame)
-- Forces the indicators to be above the bars/portraits/etc
if( not frame.indicators ) then
frame.indicators = CreateFrame("Frame", nil, frame)
frame.indicators:SetFrameLevel(frame.topFrameLevel + 1)
end
-- Now lets enable all the indicators
local config = ShadowUF.db.profile.units[frame.unitType]
if( config.indicators.status and config.indicators.status.enabled ) then
frame:RegisterUpdateFunc(self, "UpdateStatus")
frame.indicators.status = frame.indicators.status or frame.indicators:CreateTexture(nil, "OVERLAY")
frame.indicators.status:SetTexture("Interface\\CharacterFrame\\UI-StateIcon")
frame.indicators.timeElapsed = 0
frame.indicators.parent = frame
if( frame.unitType == "player" ) then
frame:RegisterUpdateFunc(self, "CheckVehicle")
frame:RegisterNormalEvent("PLAYER_REGEN_ENABLED", self, "UpdateStatus")
frame:RegisterNormalEvent("PLAYER_REGEN_DISABLED", self, "UpdateStatus")
frame:RegisterNormalEvent("PLAYER_UPDATE_RESTING", self, "UpdateStatus")
frame:RegisterNormalEvent("UPDATE_FACTION", self, "UpdateStatus")
else
frame.indicators.status:SetTexCoord(0.50, 1.0, 0.0, 0.49)
frame.indicators:SetScript("OnUpdate", combatMonitor)
end
elseif( frame.indicators.status ) then
frame.indicators:SetScript("OnUpdate", nil)
end
if( config.indicators.pvp and config.indicators.pvp.enabled ) then
frame:RegisterUnitEvent("PLAYER_FLAGS_CHANGED", self, "UpdatePVPFlag")
frame:RegisterUnitEvent("UNIT_FACTION", self, "UpdatePVPFlag")
frame:RegisterUpdateFunc(self, "UpdatePVPFlag")
frame.indicators.pvp = frame.indicators.pvp or frame.indicators:CreateTexture(nil, "OVERLAY")
end
if( config.indicators.class and config.indicators.class.enabled ) then
frame:RegisterUpdateFunc(self, "UpdateClass")
frame.indicators.class = frame.indicators.class or frame.indicators:CreateTexture(nil, "OVERLAY")
end
if( config.indicators.leader and config.indicators.leader.enabled ) then
frame:RegisterNormalEvent("PARTY_LEADER_CHANGED", self, "UpdateLeader")
frame:RegisterUpdateFunc(self, "UpdateLeader")
frame.indicators.leader = frame.indicators.leader or frame.indicators:CreateTexture(nil, "OVERLAY")
frame.indicators.leader:SetTexture("Interface\\GroupFrame\\UI-Group-LeaderIcon")
end
if( config.indicators.masterLoot and config.indicators.masterLoot.enabled ) then
frame:RegisterNormalEvent("PARTY_LOOT_METHOD_CHANGED", self, "UpdateMasterLoot")
frame:RegisterNormalEvent("RAID_ROSTER_UPDATE", self, "UpdateMasterLoot")
frame:RegisterUpdateFunc(self, "UpdateMasterLoot")
frame.indicators.masterLoot = frame.indicators.masterLoot or frame.indicators:CreateTexture(nil, "OVERLAY")
frame.indicators.masterLoot:SetTexture("Interface\\GroupFrame\\UI-Group-MasterLooter")
end
if( config.indicators.role and config.indicators.role.enabled ) then
frame:RegisterUpdateFunc(self, "UpdateRole")
frame.indicators.role = frame.indicators.role or frame.indicators:CreateTexture(nil, "OVERLAY")
frame.indicators.role:SetTexture("Interface\\GroupFrame\\UI-Group-MainAssistIcon")
-- Silly hack to fix the fact that Blizzard bugged an API and causes "<unit> is not in your party" errors
if( not self.leavingFrame ) then
self.leavingFrame = CreateFrame("Frame")
self.leavingFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
self.leavingFrame:RegisterEvent("PLAYER_LEAVING_WORLD")
self.leavingFrame:SetScript("OnEvent", function(self, event)
if( event == "PLAYER_LEAVING_WORLD" ) then
leavingWorld = true
else
leavingWorld = nil
for frame in pairs(ShadowUF.Units.frameList) do
if( frame:IsVisible() and frame.indicators and frame.indicators.role and frame.indicators.role.enabled ) then
Indicators:UpdateRole(frame)
end
end
end
end)
end
end
if( config.indicators.raidTarget and config.indicators.raidTarget.enabled ) then
frame:RegisterNormalEvent("RAID_TARGET_UPDATE", self, "UpdateRaidTarget")
frame:RegisterUpdateFunc(self, "UpdateRaidTarget")
frame.indicators.raidTarget = frame.indicators.raidTarget or frame.indicators:CreateTexture(nil, "OVERLAY")
frame.indicators.raidTarget:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons")
end
if( config.indicators.ready and config.indicators.ready.enabled ) then
frame:RegisterNormalEvent("READY_CHECK", self, "UpdateReadyCheck")
frame:RegisterNormalEvent("READY_CHECK_CONFIRM", self, "UpdateReadyCheck")
frame:RegisterNormalEvent("READY_CHECK_FINISHED", self, "UpdateReadyCheck")
frame:RegisterUpdateFunc(self, "UpdateReadyCheck")
frame.indicators.ready = frame.indicators.ready or frame.indicators:CreateTexture(nil, "OVERLAY")
end
if( config.indicators.happiness and config.indicators.happiness.enabled ) then
frame:RegisterUnitEvent("UNIT_HAPPINESS", self, "UpdateHappiness")
frame:RegisterUpdateFunc(self, "UpdateHappiness")
frame.indicators.happiness = frame.indicators.happiness or frame.indicators:CreateTexture(nil, "OVERLAY")
frame.indicators.happiness:SetTexture("Interface\\PetPaperDollFrame\\UI-PetHappiness")
end
if( config.indicators.lfdRole and config.indicators.lfdRole.enabled ) then
if( frame.unit == "player" ) then
frame:RegisterNormalEvent("PLAYER_ROLES_ASSIGNED", self, "UpdateLFDRole")
end
frame.indicators.lfdRole = frame.indicators.lfdRole or frame.indicators:CreateTexture(nil, "OVERLAY")
frame.indicators.lfdRole:SetTexture("Interface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES")
end
-- As they all share the function, register it as long as one is active
if( frame.indicators.leader or frame.indicators.masterLoot or frame.indicators.role or ( frame.unit ~= "player" and frame.indicators.lfdRole ) ) then
frame:RegisterNormalEvent("PARTY_MEMBERS_CHANGED", self, "UpdateLeader")
end
end
function Indicators:OnDisable(frame)
frame:UnregisterAll(self)
for _, key in pairs(self.list) do
if( frame.indicators[key] ) then
frame.indicators[key].enabled = nil
frame.indicators[key]:Hide()
end
end
end
function Indicators:OnLayoutApplied(frame, config)
if( frame.visibility.indicators ) then
self:OnDisable(frame)
self:OnEnable(frame)
for _, key in pairs(self.list) do
local indicator = frame.indicators[key]
if( indicator and config.indicators[key].enabled and config.indicators[key].size ) then
indicator.enabled = true
indicator:SetHeight(config.indicators[key].size)
indicator:SetWidth(config.indicators[key].size)
ShadowUF.Layout:AnchorFrame(frame, indicator, config.indicators[key])
elseif( indicator ) then
indicator.enabled = nil
indicator:Hide()
end
end
-- Disable the polling
if( config.indicators.status and not config.indicators.status.enabled and frame.indicators.status ) then
frame.indicators:SetScript("OnUpdate", nil)
end
end
end
+540
View File
@@ -0,0 +1,540 @@
local Layout = {mediaPath = {}}
local SML, mediaRequired, anchoringQueued
local mediaPath = Layout.mediaPath
local backdropTbl = {insets = {}}
local _G = getfenv(0)
ShadowUF.Layout = Layout
-- Someone is using another mod that is forcing a media type for all mods using SML
function Layout:MediaForced(mediaType)
local oldPath = mediaPath[mediaType]
self:CheckMedia()
if( mediaPath[mediaType] ~= oldPath ) then
self:Reload()
end
end
local function loadMedia(type, name, default)
if( name == "" ) then return "" end
local media = SML:Fetch(type, name, true)
if( not media ) then
mediaRequired = mediaRequired or {}
mediaRequired[type] = name
return default
end
return media
end
-- Updates the background table
local function updateBackdrop()
-- Update the backdrop table
local backdrop = ShadowUF.db.profile.backdrop
backdropTbl.bgFile = mediaPath.background
backdropTbl.edgeFile = mediaPath.border
backdropTbl.tile = backdrop.tileSize > 0 and true or false
backdropTbl.edgeSize = backdrop.edgeSize
backdropTbl.tileSize = backdrop.tileSize
backdropTbl.insets.left = backdrop.inset
backdropTbl.insets.right = backdrop.inset
backdropTbl.insets.top = backdrop.inset
backdropTbl.insets.bottom = backdrop.inset
end
-- Tries to load media, if it fails it will default to whatever I set
function Layout:CheckMedia()
mediaPath[SML.MediaType.STATUSBAR] = loadMedia(SML.MediaType.STATUSBAR, ShadowUF.db.profile.bars.texture, "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\Aluminium")
mediaPath[SML.MediaType.FONT] = loadMedia(SML.MediaType.FONT, ShadowUF.db.profile.font.name, "Interface\\AddOns\\ShadowedUnitFrames\\media\\fonts\\Myriad Condensed Web.ttf")
mediaPath[SML.MediaType.BACKGROUND] = loadMedia(SML.MediaType.BACKGROUND, ShadowUF.db.profile.backdrop.backgroundTexture, "Interface\\ChatFrame\\ChatFrameBackground")
mediaPath[SML.MediaType.BORDER] = loadMedia(SML.MediaType.BORDER, ShadowUF.db.profile.backdrop.borderTexture, "")
updateBackdrop()
end
-- We might not have had a media we required at initial load, wait for it to load and then update everything when it does
function Layout:MediaRegistered(event, mediaType, key)
if( mediaRequired and mediaRequired[mediaType] and mediaRequired[mediaType] == key ) then
mediaPath[mediaType] = SML:Fetch(mediaType, key)
mediaRequired[mediaType] = nil
self:Reload()
end
end
-- Helper functions
function Layout:ToggleVisibility(frame, visible)
if( frame and visible ) then
frame:Show()
elseif( frame ) then
frame:Hide()
end
end
function Layout:SetBarVisibility(frame, key, status)
if( status and not frame[key]:IsVisible() ) then
frame[key]:Show()
ShadowUF.Layout:PositionWidgets(frame, ShadowUF.db.profile.units[frame.unitType])
elseif( not status and frame[key]:IsVisible() ) then
frame[key]:Hide()
ShadowUF.Layout:PositionWidgets(frame, ShadowUF.db.profile.units[frame.unitType])
end
end
-- Frame changed somehow between when we first set it all up and now
function Layout:Reload(unit)
updateBackdrop()
-- Now update them
for frame in pairs(ShadowUF.Units.frameList) do
if( frame.unit and ( not unit or frame.unitType == unit ) and not frame.isHeaderFrame ) then
frame:SetVisibility()
self:Load(frame)
frame:FullUpdate()
end
end
ShadowUF:FireModuleEvent("OnLayoutReload", unit)
end
-- Do a full update
function Layout:Load(frame)
local unitConfig = ShadowUF.db.profile.units[frame.unitType]
-- About to set layout
ShadowUF:FireModuleEvent("OnPreLayoutApply", frame, unitConfig)
-- Load all of the layout things
self:SetupFrame(frame, unitConfig)
self:SetupBars(frame, unitConfig)
self:PositionWidgets(frame, unitConfig)
self:SetupText(frame, unitConfig)
-- Layouts been fully set
ShadowUF:FireModuleEvent("OnLayoutApplied", frame, unitConfig)
end
-- Register it on file load because authors seem to do a bad job at registering the callbacks
SML = LibStub:GetLibrary("LibSharedMedia-3.0")
SML:Register(SML.MediaType.FONT, "Myriad Condensed Web", "Interface\\AddOns\\ShadowedUnitFrames\\media\\fonts\\Myriad Condensed Web.ttf")
SML:Register(SML.MediaType.BORDER, "Square Clean", "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\ABFBorder")
SML:Register(SML.MediaType.BACKGROUND, "Chat Frame", "Interface\\ChatFrame\\ChatFrameBackground")
SML:Register(SML.MediaType.STATUSBAR, "BantoBar", "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\banto")
SML:Register(SML.MediaType.STATUSBAR, "Smooth", "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\smooth")
SML:Register(SML.MediaType.STATUSBAR, "Perl", "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\perl")
SML:Register(SML.MediaType.STATUSBAR, "Glaze", "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\glaze")
SML:Register(SML.MediaType.STATUSBAR, "Charcoal", "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\Charcoal")
SML:Register(SML.MediaType.STATUSBAR, "Otravi", "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\otravi")
SML:Register(SML.MediaType.STATUSBAR, "Striped", "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\striped")
SML:Register(SML.MediaType.STATUSBAR, "LiteStep", "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\LiteStep")
SML:Register(SML.MediaType.STATUSBAR, "Aluminium", "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\Aluminium")
SML:Register(SML.MediaType.STATUSBAR, "Minimalist", "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\Minimalist")
function Layout:LoadSML()
SML.RegisterCallback(self, "LibSharedMedia_Registered", "MediaRegistered")
SML.RegisterCallback(self, "LibSharedMedia_SetGlobal", "MediaForced")
self:CheckMedia()
end
--[[
Keep in mind this is relative to where you're parenting it, RT will put the object outside of the frame, on the right side, at the top of it while ITR will put it inside the frame, at the top to the right
* Positions OUTSIDE the frame
RT = Right Top, RC = Right Center, RB = Right Bottom
LT = Left Top, LC = Left Center, LB = Left Bottom,
BL = Bottom Left, BC = Bottom Center, BR = Bottom Right
TR = Top Right, TC = Top Center, TL = Top Left
* Positions INSIDE the frame
CLI = Inside Center Left, CRI = Inside Center Right
TRI = Inside Top Right, TLI = Inside Top Left
BRI = Inside Bottom Right, BRI = Inside Bottom left
]]
local preDefPoint = {C = "CENTER", CLI = "LEFT", RT = "TOPLEFT", BC = "TOP", CRI = "RIGHT", LT = "TOPRIGHT", TR = "BOTTOMRIGHT", BL = "TOPLEFT", LB = "BOTTOMRIGHT", LC = "RIGHT", RB = "BOTTOMLEFT", RC = "LEFT", TC = "BOTTOM", BR = "TOPRIGHT", TL = "BOTTOMLEFT", BRI = "BOTTOMRIGHT", BLI = "BOTTOMLEFT", TRI = "TOPRIGHT", TLI = "TOPLEFT"}
local preDefRelative = {C = "CENTER", CLI = "LEFT", RT = "TOPRIGHT", BC = "BOTTOM", CRI = "RIGHT", LT = "TOPLEFT", TR = "TOPRIGHT", BL = "BOTTOMLEFT", LB = "BOTTOMLEFT", LC = "LEFT", RB = "BOTTOMRIGHT", RC = "RIGHT", TC = "TOP", BR = "BOTTOMRIGHT", TL = "TOPLEFT", BRI = "BOTTOMRIGHT", BLI = "BOTTOMLEFT", TRI = "TOPRIGHT", TLI = "TOPLEFT"}
local columnDirection = {RT = "RIGHT", C = "RIGHT", BC = "BOTTOM", LT = "LEFT", TR = "TOP", BL = "BOTTOM", LB = "LEFT", LC = "LEFT", TRI = "TOP", RB = "RIGHT", RC = "RIGHT", TC = "TOP", CLI = "RIGHT", TL = "TOP", BR = "BOTTOM", IBL = "RIGHT", IBR = "RIGHT", CRI = "RIGHT", TLI = "TOP"}
local auraDirection = {RT = "BOTTOM", C = "LEFT", BC = "LEFT", LT = "BOTTOM", TR = "LEFT", BL = "RIGHT", LB = "TOP", LC = "LEFT", TRI = "LEFT", RB = "TOP", RC = "LEFT", TC = "LEFT", CLI = "RIGHT", TL = "RIGHT", BR = "LEFT", IBL = "TOP", IBR = "TOP", CRI = "LEFT", TLI = "RIGHT"}
-- Figures out how text should be justified based on where it's anchoring
function Layout:GetJustify(config)
local point = config.anchorPoint and config.anchorPoint ~= "" and preDefPoint[config.anchorPoint] or config.point
if( point and point ~= "" ) then
if( string.match(point, "LEFT$") ) then
return "LEFT"
elseif( string.match(point, "RIGHT$") ) then
return "RIGHT"
end
end
return "CENTER"
end
function Layout:GetPoint(key)
return preDefPoint[key] or "CENTER"
end
function Layout:GetRelative(key)
return preDefRelative[key] or "CENTER"
end
function Layout:GetColumnGrowth(key)
return columnDirection[key] or "DOWN"
end
function Layout:GetAuraGrowth(key)
return auraDirection[key] or "LEFT"
end
function Layout:ReverseDirection(key)
return key == "LEFT" and "RIGHT" or key == "RIGHT" and "LEFT" or key == "TOP" and "BOTTOM" or key == "BOTTOM" and "TOP"
end
-- Gets the relative anchoring for Blizzards default raid frames, these differ from the split ones
function Layout:GetRelativeAnchor(point)
if( point == "TOP" ) then
return "BOTTOM", 0, -1
elseif( point == "BOTTOM" ) then
return "TOP", 0, 1
elseif( point == "LEFT" ) then
return "RIGHT", 1, 0
elseif( point == "RIGHT" ) then
return "LEFT", -1, 0
elseif( point == "TOPLEFT" ) then
return "BOTTOMRIGHT", 1, -1
elseif( point == "TOPRIGHT" ) then
return "BOTTOMLEFT", -1, -1
elseif( point == "BOTTOMLEFT" ) then
return "TOPRIGHT", 1, 1
elseif( point == "BOTTOMRIGHT" ) then
return "TOPLEFT", -1, 1
else
return "CENTER", 0, 0
end
end
function Layout:GetSplitRelativeAnchor(point, columnPoint)
-- Column is growing to the RIGHT
if( columnPoint == "LEFT" ) then
return "TOPLEFT", "TOPRIGHT", 1, 0
-- Column is growing to the LEFT
elseif( columnPoint == "RIGHT" ) then
return "TOPRIGHT", "TOPLEFT", -1, 0
-- Column is growing DOWN
elseif( columnPoint == "TOP" ) then
return "TOP" .. point, "BOTTOM" .. point, 0, -1
-- Column is growing UP
elseif( columnPoint == "BOTTOM" ) then
return "BOTTOM" .. point, "TOP" .. point, 0, 1
end
end
function Layout:AnchorFrame(parent, frame, config)
if( not config or not config.anchorTo or not config.x or not config.y ) then
return
end
local anchorTo = config.anchorTo
local prefix = string.sub(config.anchorTo, 0, 1)
if( config.anchorTo == "$parent" ) then
anchorTo = parent
-- $ is used as an indicator of a sub-frame inside a parent, $healthBar -> parent.healthBar and so on
elseif( prefix == "$" ) then
anchorTo = parent[string.sub(config.anchorTo, 2)]
-- # is used as an indicator of an actual frame created by SUF, it lets us know that the frame might not be created yet
-- and if so, to watch for it to be created and fix the anchoring
elseif( prefix == "#" ) then
anchorTo = string.sub(config.anchorTo, 2)
-- The frame we wanted to anchor to doesn't exist yet, so will queue and wait for it to exist
if( not _G[anchorTo] ) then
frame.queuedParent = parent
frame.queuedConfig = config
frame.queuedName = anchorTo
anchoringQueued = anchoringQueued or {}
anchoringQueued[frame] = true
-- For the time being, will take over the frame we wanted to anchor to's position.
local unit = string.match(anchorTo, "SUFUnit(%w+)") or string.match(anchorTo, "SUFHeader(%w+)")
if( unit and ShadowUF.db.profile.positions[unit] ) then
self:AnchorFrame(parent, frame, ShadowUF.db.profile.positions[unit])
end
return
end
end
-- Figure out where it's anchored
local point = config.point and config.point ~= "" and config.point or preDefPoint[config.anchorPoint] or "CENTER"
local relativePoint = config.relativePoint and config.relativePoint ~= "" and config.relativePoint or preDefRelative[config.anchorPoint] or "CENTER"
-- Effective scaling is only used for unit based frames and if they are anchored to UIParent
local scale = 1
if( config.anchorTo == "UIParent" and frame.unitType ) then
scale = frame:GetScale() * UIParent:GetScale()
end
frame:ClearAllPoints()
frame:SetPoint(point, anchorTo, relativePoint, config.x / scale, config.y / scale)
end
-- Setup the main frame
function Layout:SetupFrame(frame, config)
local backdrop = ShadowUF.db.profile.backdrop
frame:SetBackdrop(backdropTbl)
frame:SetBackdropColor(backdrop.backgroundColor.r, backdrop.backgroundColor.g, backdrop.backgroundColor.b, backdrop.backgroundColor.a)
frame:SetBackdropBorderColor(backdrop.borderColor.r, backdrop.borderColor.g, backdrop.borderColor.b, backdrop.borderColor.a)
-- Prevent these from updating while in combat to prevent tainting
if( not InCombatLockdown() ) then
frame:SetHeight(config.height)
frame:SetWidth(config.width)
frame:SetScale(config.scale)
-- Let the frame clip closer to the edge, not using inset + clip as that lets you move it too far in
local clamp = backdrop.inset + 0.20
frame:SetClampRectInsets(clamp, -clamp, -clamp, clamp)
frame:SetClampedToScreen(true)
-- This is wrong technically, I need to redo the backdrop stuff so it will accept insets and that will fit hitbox issues
-- for the time being, this is a temporary fix to it
local hit = backdrop.borderTexture == "None" and backdrop.inset or 0
frame:SetHitRectInsets(hit, hit, hit, hit)
if( not frame.ignoreAnchor ) then
self:AnchorFrame(frame.parent or UIParent, frame, ShadowUF.db.profile.positions[frame.unitType])
end
end
-- Check if we had anything parented to us
if( anchoringQueued ) then
for queued in pairs(anchoringQueued) do
if( queued.queuedName == frame:GetName() ) then
self:AnchorFrame(queued.queuedParent, queued, queued.queuedConfig)
queued.queuedParent = nil
queued.queuedConfig = nil
queued.queuedName = nil
anchoringQueued[queued] = nil
end
end
end
end
-- Setup bars
function Layout:SetupBars(frame, config)
for _, module in pairs(ShadowUF.modules) do
local key = module.moduleKey
local widget = frame[key]
if( widget and ( module.moduleHasBar or config[key] and config[key].isBar ) ) then
self:ToggleVisibility(widget, frame.visibility[key])
if( widget:IsShown() and widget.SetStatusBarTexture ) then
widget:SetStatusBarTexture(mediaPath.statusbar)
widget:GetStatusBarTexture():SetHorizTile(false)
end
if( widget.background ) then
if( config[key].background ) then
widget.background:SetTexture(mediaPath.statusbar)
widget.background:SetHorizTile(false)
widget.background:Show()
widget.background.overrideColor = ShadowUF.db.profile.bars.backgroundColor or config[key].backgroundColor
if( widget.background.overrideColor ) then
widget.background:SetVertexColor(widget.background.overrideColor.r, widget.background.overrideColor.g, widget.background.overrideColor.b, ShadowUF.db.profile.bars.backgroundAlpha)
end
else
widget.background:Hide()
end
end
end
end
end
-- Setup text
function Layout:SetupFontString(fontString, extraSize)
local size = ShadowUF.db.profile.font.size + (extraSize or 0)
if( size <= 0 ) then size = 1 end
fontString:SetFont(mediaPath.font, size, ShadowUF.db.profile.font.extra)
if( ShadowUF.db.profile.font.shadowColor and ShadowUF.db.profile.font.shadowX and ShadowUF.db.profile.font.shadowY ) then
fontString:SetShadowColor(ShadowUF.db.profile.font.shadowColor.r, ShadowUF.db.profile.font.shadowColor.g, ShadowUF.db.profile.font.shadowColor.b, ShadowUF.db.profile.font.shadowColor.a)
fontString:SetShadowOffset(ShadowUF.db.profile.font.shadowX, ShadowUF.db.profile.font.shadowY)
else
fontString:SetShadowColor(0, 0, 0, 0)
fontString:SetShadowOffset(0, 0)
end
end
local totalWeight = {}
function Layout:SetupText(frame, config)
-- Update tag text
frame.fontStrings = frame.fontStrings or {}
for _, fontString in pairs(frame.fontStrings) do
ShadowUF.Tags:Unregister(fontString)
fontString:Hide()
end
for k in pairs(totalWeight) do totalWeight[k] = nil end
-- Update the actual text, and figure out the weighting information now
for id, row in pairs(config.text) do
local parent = row.anchorTo == "$parent" and frame or frame[string.sub(row.anchorTo, 2)]
if( parent and parent:IsShown() and row.enabled and row.text ~= "" ) then
local fontString = frame.fontStrings[id] or frame.highFrame:CreateFontString(nil, "ARTWORK")
self:SetupFontString(fontString, row.size)
fontString:SetTextColor(ShadowUF.db.profile.font.color.r, ShadowUF.db.profile.font.color.g, ShadowUF.db.profile.font.color.b, ShadowUF.db.profile.font.color.a)
fontString:SetText(row.text)
fontString:SetJustifyH(self:GetJustify(row))
self:AnchorFrame(frame, fontString, row)
-- We figure out the anchor point so we can put text in the same area with the same width requirements
local anchorPoint = columnDirection[row.anchorPoint]
if( string.len(row.anchorPoint) == 3 ) then anchorPoint = anchorPoint .. "I" end
fontString.availableWidth = parent:GetWidth() - row.x
fontString.widthID = row.anchorTo .. anchorPoint .. row.y
totalWeight[fontString.widthID] = (totalWeight[fontString.widthID] or 0) + row.width
ShadowUF.Tags:Register(frame, fontString, row.text)
fontString:UpdateTags()
fontString:Show()
frame.fontStrings[id] = fontString
end
end
-- Now set all of the width using our weightings
for id, fontString in pairs(frame.fontStrings) do
if( fontString:IsShown() ) then
fontString:SetWidth(fontString.availableWidth * (config.text[id].width / totalWeight[fontString.widthID]))
fontString:SetHeight(ShadowUF.db.profile.font.size + 1)
frame:RegisterUpdateFunc(fontString, "UpdateTags")
else
frame:UnregisterAll(fontString)
end
end
end
-- Setup the bar barOrder/info
local currentConfig
local function sortOrder(a, b)
return currentConfig[a].order < currentConfig[b].order
end
local barOrder = {}
function Layout:PositionWidgets(frame, config)
-- Deal with setting all of the bar heights
local totalWeight, totalBars, hasFullSize = 0, -1
-- Figure out total weighting as well as what bars are full sized
for i=#(barOrder), 1, -1 do table.remove(barOrder, i) end
for key, module in pairs(ShadowUF.modules) do
if( ( module.moduleHasBar or config[key] and config[key].isBar ) and frame[key] and frame[key]:IsShown() and config[key].height > 0 ) then
totalWeight = totalWeight + config[key].height
totalBars = totalBars + 1
table.insert(barOrder, key)
-- Decide whats full sized
if( not frame.visibility.portrait or config.portrait.isBar or config[key].order < config.portrait.fullBefore or config[key].order > config.portrait.fullAfter ) then
hasFullSize = true
frame[key].fullSize = true
else
frame[key].fullSize = nil
end
end
end
-- Sort the barOrder so it's all nice and orderly (:>)
currentConfig = config
table.sort(barOrder, sortOrder)
-- Now deal with setting the heights and figure out how large the portrait should be.
local clip = ShadowUF.db.profile.backdrop.inset + ShadowUF.db.profile.backdrop.clip
local clipDoubled = clip * 2
local portraitOffset, portraitAlignment, portraitAnchor, portraitWidth
if( not config.portrait.isBar ) then
self:ToggleVisibility(frame.portrait, frame.visibility.portrait)
if( frame.visibility.portrait ) then
-- Figure out portrait alignment
portraitAlignment = config.portrait.alignment
-- Set the portrait width so we can figure out the offset to use on bars, will do height and position later
portraitWidth = math.floor(frame:GetWidth() * config.portrait.width) - ShadowUF.db.profile.backdrop.inset
frame.portrait:SetWidth(portraitWidth - (portraitAlignment == "RIGHT" and 1 or 0.5))
-- Disable portrait if there isn't enough room
if( portraitWidth <= 0 ) then
frame.portrait:Hide()
end
-- As well as how much to offset bars by (if it's using a left alignment) to keep them all fancy looking
portraitOffset = clip
if( portraitAlignment == "LEFT" ) then
portraitOffset = portraitOffset + portraitWidth
end
end
end
-- Position and size everything
local portraitHeight, xOffset = 0, -clip
local availableHeight = frame:GetHeight() - clipDoubled - (math.abs(ShadowUF.db.profile.bars.spacing) * totalBars)
for id, key in pairs(barOrder) do
local bar = frame[key]
-- Position the actual bar based on it's type
if( bar.fullSize ) then
bar:SetWidth(frame:GetWidth() - clipDoubled)
bar:SetHeight(availableHeight * (config[key].height / totalWeight))
bar:ClearAllPoints()
bar:SetPoint("TOPLEFT", frame, "TOPLEFT", clip, xOffset)
else
bar:SetWidth(frame:GetWidth() - portraitWidth - clipDoubled)
bar:SetHeight(availableHeight * (config[key].height / totalWeight))
bar:ClearAllPoints()
bar:SetPoint("TOPLEFT", frame, "TOPLEFT", portraitOffset, xOffset)
portraitHeight = portraitHeight + bar:GetHeight()
end
-- Figure out where the portrait is going to be anchored to
if( not portraitAnchor and config[key].order >= config.portrait.fullBefore ) then
portraitAnchor = bar
end
xOffset = xOffset - bar:GetHeight() + ShadowUF.db.profile.bars.spacing
end
-- Now position the portrait and set the height
if( frame.portrait and frame.portrait:IsShown() and portraitAnchor and portraitHeight > 0 ) then
if( portraitAlignment == "LEFT" ) then
frame.portrait:ClearAllPoints()
frame.portrait:SetPoint("TOPLEFT", portraitAnchor, "TOPLEFT", -frame.portrait:GetWidth() - 0.5, 0)
elseif( portraitAlignment == "RIGHT" ) then
frame.portrait:ClearAllPoints()
frame.portrait:SetPoint("TOPRIGHT", portraitAnchor, "TOPRIGHT", frame.portrait:GetWidth() + 1, 0)
end
if( hasFullSize ) then
frame.portrait:SetHeight(portraitHeight)
else
frame.portrait:SetHeight(frame:GetHeight() - clipDoubled)
end
end
ShadowUF:FireModuleEvent("OnLayoutWidgets", frame, config)
end
+496
View File
@@ -0,0 +1,496 @@
-- I am undecided if this is a brilliant idea or an insane one
local L = ShadowUF.L
local Movers = {}
local originalEnvs = {}
local unitConfig = {}
local attributeBlacklist = {["showplayer"] = true, ["showraid"] = true, ["showparty"] = true, ["showsolo"] = true, ["initial-unitwatch"] = true}
local playerClass = select(2, UnitClass("player"))
local noop = function() end
local OnDragStop, OnDragStart, configEnv
ShadowUF:RegisterModule(Movers, "movers")
-- This is the fun part, the env to fake units and make them show up as examples
local function getValue(func, unit, value)
unit = string.gsub(unit, "(%d+)", "")
if( unitConfig[func .. unit] == nil ) then unitConfig[func .. unit] = value end
return unitConfig[func .. unit]
end
local function createConfigEnv()
if( configEnv ) then return end
configEnv = setmetatable({
GetRaidTargetIndex = function(unit) return getValue("GetRaidTargetIndex", unit, math.random(1, 8)) end,
GetLootMethod = function(unit) return "master", 0, 0 end,
GetComboPoints = function() return MAX_COMBO_POINTS end,
GetPetHappiness = function() return getValue("GetPetHappiness", "pet", math.random(1, 3)) end,
UnitInRaid = function() return true end,
UnitInParty = function() return true end,
UnitIsUnit = function(unitA, unitB) return unitB == "player" and true or false end,
UnitIsDeadOrGhost = function(unit) return false end,
UnitIsConnected = function(unit) return true end,
UnitLevel = function(unit) return MAX_PLAYER_LEVEL end,
UnitIsPlayer = function(unit) return unit ~= "boss" and unit ~= "pet" and not string.match(unit, "(%w+)pet") end,
UnitHealth = function(unit) return getValue("UnitHealth", unit, math.random(20000, 50000)) end,
UnitHealthMax = function(unit) return 50000 end,
UnitPower = function(unit) return getValue("UnitPower", unit, math.random(20000, 50000)) end,
UnitExists = function(unit) return true end,
UnitPowerMax = function(unit) return 50000 end,
UnitIsPartyLeader = function() return true end,
UnitIsPVP = function(unit) return true end,
UnitIsDND = function(unit) return false end,
UnitIsAFK = function(unit) return false end,
UnitFactionGroup = function(unit) return _G.UnitFactionGroup("player") end,
UnitAffectingCombat = function() return true end,
UnitThreatSituation = function() return 0 end,
UnitDetailedThreatSituation = function() return nil end,
UnitThreatSituation = function() return 0 end,
UnitCastingInfo = function(unit)
-- 1 -> 10: spell, rank, displayName, icon, startTime, endTime, isTradeSkill, castID, notInterruptible
local data = unitConfig["UnitCastingInfo" .. unit] or {}
if( not data[6] or GetTime() < data[6] ) then
data[1] = L["Test spell"]
data[2] = L["Rank 1"]
data[3] = L["Test spell"]
data[4] = "Interface\\Icons\\Spell_Nature_Rejuvenation"
data[5] = GetTime() * 1000
data[6] = data[5] + 60000
data[7] = false
data[8] = math.floor(GetTime())
data[9] = math.random(0, 100) < 25
unitConfig["UnitCastingInfo" .. unit] = data
end
return unpack(data)
end,
UnitIsFriend = function(unit) return unit ~= "target" and unit ~= ShadowUF.fakeUnits[unit] and unit ~= "arena" end,
GetReadyCheckStatus = function(unit)
local status = getValue("GetReadyCheckStatus", unit, math.random(1, 3))
return status == 1 and "ready" or status == 2 and "notready" or "waiting"
end,
GetPartyAssignment = function(type, unit)
local assignment = getValue("GetPartyAssignment", unit, math.random(1, 2) == 1 and "MAINTANK" or "MAINASSIST")
return assignment == type
end,
UnitGroupRolesAssigned = function(unit)
local role = getValue("UnitGroupRolesAssigned", unit, math.random(1, 3))
return role == 1, role == 2, role == 3
end,
UnitPowerType = function(unit)
local powerType = math.random(0, 4)
powerType = getValue("UnitPowerType", unit, powerType == 4 and 6 or powerType)
return powerType, powerType == 0 and "MANA" or powerType == 1 and "RAGE" or powerType == 2 and "FOCUS" or powerType == 3 and "ENERGY" or powerType == 6 and "RUNIC_POWER"
end,
UnitAura = function(unit, id, filter)
if( type(id) ~= "number" or id > 40 ) then return end
local texture = filter == "HELPFUL" and "Interface\\Icons\\Spell_Nature_Rejuvenation" or "Interface\\Icons\\Ability_DualWield"
local mod = id % 5
local auraType = mod == 0 and "Magic" or mod == 1 and "Curse" or mod == 2 and "Poison" or mod == 3 and "Disease" or "none"
return L["Test Aura"], L["Rank 1"], texture, id, auraType, 0, 0, "player", id % 6 == 0
end,
UnitName = function(unit)
local unitID = string.match(unit, "(%d+)")
if( unitID ) then
return string.format("%s #%d", L.units[string.gsub(unit, "(%d+)", "")] or unit, unitID)
end
return L.units[unit]
end,
UnitClass = function(unit)
local classToken = getValue("UnitClass", unit, CLASS_SORT_ORDER[math.random(1, #(CLASS_SORT_ORDER))])
return LOCALIZED_CLASS_NAMES_MALE[classToken], classToken
end,
}, {
__index = _G,
__newindex = function(tbl, key, value) _G[key] = value end,
})
end
-- Child units have to manually be added to the list to make sure they function properly
local function prepareChildUnits(header, ...)
for i=1, select("#", ...) do
local frame = select(i, ...)
if( frame.unitType and not frame.configUnitID ) then
ShadowUF.Units.frameList[frame] = true
frame.configUnitID = header.groupID and (header.groupID * 5) - 5 + i or i
frame:SetAttribute("unit", ShadowUF[header.unitType .. "Units"][frame.configUnitID])
end
end
end
local function OnEnter(self)
local tooltip = self.tooltipText or self.unitID and string.format("%s #%d", L.units[self.unitType], self.unitID) or L.units[self.unit] or self.unit
local additionalText = ShadowUF.Units.childUnits[self.unitType] and L["Child units cannot be dragged, you will have to reposition them through /shadowuf."]
GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT")
GameTooltip:SetText(tooltip, 1, 0.81, 0, 1, true)
if( additionalText ) then GameTooltip:AddLine(additionalText, 0.90, 0.90, 0.90, 1) end
GameTooltip:Show()
end
local function OnLeave(self)
GameTooltip:Hide()
end
local function setupUnits(childrenOnly)
for frame in pairs(ShadowUF.Units.frameList) do
if( frame.configMode ) then
-- Units visible, but it's not supposed to be
if( frame:IsVisible() and not ShadowUF.db.profile.units[frame.unitType].enabled ) then
RegisterUnitWatch(frame, frame.hasStateWatch)
if( not UnitExists(frame.unit) ) then frame:Hide() end
-- Unit's not visible and it's enabled so it should
elseif( not frame:IsVisible() and ShadowUF.db.profile.units[frame.unitType].enabled ) then
UnregisterUnitWatch(frame)
frame:FullUpdate()
frame:Show()
end
elseif( not frame.configMode and ShadowUF.db.profile.units[frame.unitType].enabled ) then
frame.originalUnit = frame:GetAttribute("unit")
frame.originalOnEnter = frame:GetScript("OnEnter")
frame.originalOnLeave = frame:GetScript("OnLeave")
frame.originalOnUpdate = frame:GetScript("OnUpdate")
frame:SetMovable(not ShadowUF.Units.childUnits[frame.unitType])
frame:SetScript("OnDragStop", OnDragStop)
frame:SetScript("OnDragStart", OnDragStart)
frame:SetScript("OnEnter", OnEnter)
frame:SetScript("OnLeave", OnLeave)
frame:SetScript("OnEvent", nil)
frame:SetScript("OnUpdate", nil)
frame:RegisterForDrag("LeftButton")
frame.configMode = true
frame.unitOwner = nil
frame.originalMenu = frame.menu
frame.menu = nil
local unit
if( frame.isChildUnit ) then
local unitFormat = string.gsub(string.gsub(frame.unitType, "target$", "%%dtarget"), "pet$", "pet%%d")
unit = string.format(unitFormat, frame.parent.configUnitID or "")
else
unit = frame.unitType .. (frame.configUnitID or "")
end
ShadowUF.Units.OnAttributeChanged(frame, "unit", unit)
if( frame.healthBar ) then frame.healthBar:SetScript("OnUpdate", nil) end
if( frame.powerBar ) then frame.powerBar:SetScript("OnUpdate", nil) end
if( frame.indicators ) then frame.indicators:SetScript("OnUpdate", nil) end
UnregisterUnitWatch(frame)
frame:FullUpdate()
frame:Show()
end
end
end
function Movers:Enable()
createConfigEnv()
-- Force create zone headers
for type, zone in pairs(ShadowUF.Units.zoneUnits) do
if( ShadowUF.db.profile.units[type].enabled ) then
ShadowUF.Units:InitializeFrame(type)
end
end
-- Setup the headers
for _, header in pairs(ShadowUF.Units.headerFrames) do
for key in pairs(attributeBlacklist) do
header:SetAttribute(key, nil)
end
local config = ShadowUF.db.profile.units[header.unitType]
if( config.frameSplit ) then
header:SetAttribute("startingIndex", -4)
elseif( config.maxColumns ) then
local maxUnits = MAX_RAID_MEMBERS
if( config.filters ) then
for _, enabled in pairs(config.filters) do
if( not enabled ) then
maxUnits = maxUnits - 5
end
end
end
header:SetAttribute("startingIndex", -math.min(config.maxColumns * config.unitsPerColumn, maxUnits) + 1)
elseif( ShadowUF[header.unitType .. "Units"] ) then
header:SetAttribute("startingIndex", -#(ShadowUF[header.unitType .. "Units"]) + 1)
end
header.startingIndex = header:GetAttribute("startingIndex")
header:SetMovable(true)
prepareChildUnits(header, header:GetChildren())
end
-- Setup the test env
if( not self.isEnabled ) then
for _, func in pairs(ShadowUF.tagFunc) do
if( type(func) == "function" ) then
originalEnvs[func] = getfenv(func)
setfenv(func, configEnv)
end
end
for _, module in pairs(ShadowUF.modules) do
if( module.moduleName ) then
for key, func in pairs(module) do
if( type(func) == "function" ) then
originalEnvs[module[key]] = getfenv(module[key])
setfenv(module[key], configEnv)
end
end
end
end
end
-- Why is this called twice you ask? Child units are created on the OnAttributeChanged call
-- so the first call gets all the parent units, the second call gets the child units
setupUnits()
setupUnits(true)
-- Don't show the dialog if the configuration is opened through the configmode spec
if( not self.isConfigModeSpec ) then
self:CreateInfoFrame()
self.infoFrame:Show()
elseif( self.infoFrame ) then
self.infoFrame:Hide()
end
self.isEnabled = true
end
function Movers:Disable()
if( not self.isEnabled ) then return nil end
for func, env in pairs(originalEnvs) do
setfenv(func, env)
originalEnvs[func] = nil
end
for frame in pairs(ShadowUF.Units.frameList) do
if( frame.configMode ) then
if( frame.isMoving ) then
frame:GetScript("OnDragStop")(frame)
end
frame.configMode = nil
frame.unitOwner = nil
frame.unit = nil
frame.configUnitID = nil
frame.menu = frame.originalMenu
frame.originalMenu = nil
frame.Hide = frame.originalHide
frame:SetAttribute("unit", frame.originalUnit)
frame:SetScript("OnDragStop", nil)
frame:SetScript("OnDragStart", nil)
frame:SetScript("OnEvent", frame:IsVisible() and ShadowUF.Units.OnEvent)
frame:SetScript("OnUpdate", frame.originalOnUpdate)
frame:SetScript("OnEnter", frame.originalOnEnter)
frame:SetScript("OnLeave", frame.originalOnLeave)
frame:SetMovable(false)
frame:RegisterForDrag()
if( frame.isChildUnit ) then
ShadowUF.Units.OnAttributeChanged(frame, "unit", SecureButton_GetModifiedUnit(frame))
end
RegisterUnitWatch(frame, frame.hasStateWatch)
if( not UnitExists(frame.unit) ) then frame:Hide() end
end
end
for type, header in pairs(ShadowUF.Units.headerFrames) do
header:SetMovable(false)
header:SetAttribute("startingIndex", 1)
header:SetAttribute("initial-unitWatch", true)
if( header.unitType == type or type == "raidParent" ) then
ShadowUF.Units:ReloadHeader(header.unitType)
end
end
ShadowUF.Units:CheckPlayerZone(true)
ShadowUF.Layout:Reload()
if( self.infoFrame ) then
self.infoFrame:Hide()
end
self.isConfigModeSpec = nil
self.isEnabled = nil
end
OnDragStart = function(self)
if( not self:IsMovable() ) then return end
if( self.unitType == "raid" and ShadowUF.Units.headerFrames.raidParent and ShadowUF.Units.headerFrames.raidParent:IsVisible() ) then
self = ShadowUF.Units.headerFrames.raidParent
else
self = ShadowUF.Units.headerFrames[self.unitType] or ShadowUF.Units.unitFrames[self.unitType]
end
self.isMoving = true
self:StartMoving()
end
OnDragStop = function(self)
if( not self:IsMovable() ) then return end
if( self.unitType == "raid" and ShadowUF.Units.headerFrames.raidParent and ShadowUF.Units.headerFrames.raidParent:IsVisible() ) then
self = ShadowUF.Units.headerFrames.raidParent
else
self = ShadowUF.Units.headerFrames[self.unitType] or ShadowUF.Units.unitFrames[self.unitType]
end
self.isMoving = nil
self:StopMovingOrSizing()
-- When dragging the frame around, Blizzard changes the anchoring based on the closet portion of the screen
-- When a widget is near the top left it uses top left, near the left it uses left and so on, which messes up positioning for header frames
local scale = (self:GetScale() * UIParent:GetScale()) or 1
local position = ShadowUF.db.profile.positions[self.unitType]
local point, _, relativePoint, x, y = self:GetPoint()
-- Figure out the horizontal anchor
if( self.isHeaderFrame ) then
if( ShadowUF.db.profile.units[self.unitType].attribAnchorPoint == "RIGHT" ) then
x = self:GetRight()
point = "RIGHT"
else
x = self:GetLeft()
point = "LEFT"
end
if( ShadowUF.db.profile.units[self.unitType].attribPoint == "BOTTOM" ) then
y = self:GetBottom()
point = "BOTTOM" .. point
else
y = self:GetTop()
point = "TOP" .. point
end
relativePoint = "BOTTOMLEFT"
position.bottom = self:GetBottom() * scale
position.top = self:GetTop() * scale
end
position.anchorTo = "UIParent"
position.movedAnchor = nil
position.anchorPoint = ""
position.point = point
position.relativePoint = relativePoint
position.x = x * scale
position.y = y * scale
ShadowUF.Layout:AnchorFrame(UIParent, self, ShadowUF.db.profile.positions[self.unitType])
-- Unlock the parent frame from the mover now too
if( self.parent ) then
ShadowUF.Layout:AnchorFrame(UIParent, self.parent, ShadowUF.db.profile.positions[self.parent.unitType])
end
-- Notify the configuration it can update itself now
local ACR = LibStub("AceConfigRegistry-3.0", true)
if( ACR ) then
ACR:NotifyChange("ShadowedUF")
end
end
function Movers:Update()
if( not ShadowUF.db.profile.locked ) then
self:Enable()
elseif( ShadowUF.db.profile.locked ) then
self:Disable()
end
end
function Movers:CreateInfoFrame()
if( self.infoFrame ) then return end
-- Show an info frame that users can lock the frames through
local frame = CreateFrame("Frame", nil, UIParent)
frame:SetClampedToScreen(true)
frame:SetWidth(300)
frame:SetHeight(115)
frame:RegisterForDrag("LeftButton")
frame:EnableMouse(true)
frame:SetMovable(true)
frame:RegisterEvent("PLAYER_REGEN_DISABLED")
frame:SetScript("OnEvent", function(self)
if( not ShadowUF.db.profile.locked and self:IsVisible() ) then
ShadowUF.db.profile.locked = true
Movers:Disable()
DEFAULT_CHAT_FRAME:AddMessage(L["You have entered combat, unit frames have been locked. Once you leave combat you will need to unlock them again through /shadowuf."])
end
end)
frame:SetScript("OnShow", OnShow)
frame:SetScript("OnHide", OnHide)
frame:SetScript("OnDragStart", function(self)
self:StartMoving()
end)
frame:SetScript("OnDragStop", function(self)
self:StopMovingOrSizing()
end)
frame:SetBackdrop({
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
edgeSize = 26,
insets = {left = 9, right = 9, top = 9, bottom = 9},
})
frame:SetBackdropColor(0, 0, 0, 0.85)
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 225)
frame.titleBar = frame:CreateTexture(nil, "ARTWORK")
frame.titleBar:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
frame.titleBar:SetPoint("TOP", 0, 8)
frame.titleBar:SetWidth(350)
frame.titleBar:SetHeight(45)
frame.title = frame:CreateFontString(nil, "ARTWORK", "GameFontNormal")
frame.title:SetPoint("TOP", 0, 0)
frame.title:SetText("Shadowed Unit Frames")
frame.text = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
frame.text:SetText(L["The unit frames you see are examples, they are not perfect and do not show all the data they normally would.|n|nYou can hide them by locking them through /shadowuf or clicking the button below."])
frame.text:SetPoint("TOPLEFT", 12, -22)
frame.text:SetWidth(frame:GetWidth() - 20)
frame.text:SetJustifyH("LEFT")
frame.lock = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
frame.lock:SetText(L["Lock frames"])
frame.lock:SetHeight(20)
frame.lock:SetWidth(100)
frame.lock:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 6, 8)
frame.lock:SetScript("OnEnter", OnEnter)
frame.lock:SetScript("OnLeave", OnLeave)
frame.lock.tooltipText = L["Locks the unit frame positionings hiding the mover boxes."]
frame.lock:SetScript("OnClick", function()
ShadowUF.db.profile.locked = true
Movers:Update()
end)
frame.unlink = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
frame.unlink:SetText(L["Unlink frames"])
frame.unlink:SetHeight(20)
frame.unlink:SetWidth(100)
frame.unlink:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -6, 8)
frame.unlink:SetScript("OnEnter", OnEnter)
frame.unlink:SetScript("OnLeave", OnLeave)
frame.unlink.tooltipText = L["WARNING: This will unlink all frames from each other so you can move them without another frame moving with it."]
frame.unlink:SetScript("OnClick", function()
for frame in pairs(ShadowUF.Units.frameList) do
if( not ShadowUF.Units.childUnits[frame.unitType] and frame:GetScript("OnDragStart") and frame:GetScript("OnDragStop") ) then
frame:GetScript("OnDragStart")(frame)
frame:GetScript("OnDragStop")(frame)
end
end
Movers:Update()
end)
self.infoFrame = frame
end
+98
View File
@@ -0,0 +1,98 @@
local Portrait = {}
ShadowUF:RegisterModule(Portrait, "portrait", ShadowUF.L["Portrait"])
-- If the camera isn't reset OnShow, it'll show the entire character instead of just the head, odd I know
local function resetCamera(self)
self:SetCamera(0)
end
local function resetGUID(self)
self.guid = nil
end
function Portrait:OnEnable(frame)
frame:RegisterUnitEvent("UNIT_PORTRAIT_UPDATE", self, "UpdateFunc")
frame:RegisterUnitEvent("UNIT_MODEL_CHANGED", self, "Update")
if( frame.unitRealType == "party" ) then
-- frame:RegisterNormalEvent("PARTY_MEMBER_ENABLE", self, "Update")
-- frame:RegisterNormalEvent("PARTY_MEMBER_DISABLE", self, "Update")
end
frame:RegisterUpdateFunc(self, "UpdateFunc")
end
function Portrait:OnDisable(frame)
frame:UnregisterAll(self)
end
function Portrait:OnPreLayoutApply(frame, config)
if( not frame.visibility.portrait ) then return end
if( config.portrait.type == "3D" ) then
if( not frame.portraitModel ) then
frame.portraitModel = CreateFrame("PlayerModel", nil, frame)
frame.portraitModel:SetScript("OnShow", resetCamera)
frame.portraitModel:SetScript("OnHide", resetGUID)
frame.portraitModel.parent = frame
end
frame.portrait = frame.portraitModel
frame.portrait:Show()
ShadowUF.Layout:ToggleVisibility(frame.portraitTexture, false)
else
frame.portraitTexture = frame.portraitTexture or frame:CreateTexture(nil, "ARTWORK")
frame.portrait = frame.portraitTexture
frame.portrait:Show()
ShadowUF.Layout:ToggleVisibility(frame.portraitModel, false)
end
end
function Portrait:UpdateFunc(frame)
-- Portrait models can't be updated unless the GUID changed or else you have the animation jumping around
if( ShadowUF.db.profile.units[frame.unitType].portrait.type == "3D" ) then
local guid = UnitGUID(frame.unitOwner)
if( frame.portrait.guid ~= guid ) then
self:Update(frame)
end
frame.portrait.guid = guid
else
self:Update(frame)
end
end
function Portrait:Update(frame, event)
local type = ShadowUF.db.profile.units[frame.unitType].portrait.type
-- Use class thingy
if( type == "class" ) then
local classToken = select(2, UnitClass(frame.unitOwner))
if( classToken ) then
frame.portrait:SetTexture("Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Classes")
frame.portrait:SetTexCoord(CLASS_ICON_TCOORDS[classToken][1], CLASS_ICON_TCOORDS[classToken][2], CLASS_ICON_TCOORDS[classToken][3], CLASS_ICON_TCOORDS[classToken][4])
else
frame.portrait:SetTexture("")
end
-- Use 2D character image
elseif( type == "2D" ) then
frame.portrait:SetTexCoord(0.10, 0.90, 0.10, 0.90)
SetPortraitTexture(frame.portrait, frame.unitOwner)
-- Using 3D portrait, but the players not in range so swap to 2D
elseif( not UnitIsVisible(frame.unitOwner) or not UnitIsConnected(frame.unitOwner) ) then
frame.portrait:SetModelScale(4.25)
frame.portrait:SetPosition(0, 0, -1.5)
frame.portrait:SetModel("Interface\\Buttons\\talktomequestionmark.mdx")
-- Use animated 3D portrait
else
frame.portrait:SetUnit(frame.unitOwner)
frame.portrait:SetCamera(0)
frame.portrait:Show()
end
end
+75
View File
@@ -0,0 +1,75 @@
local Power = {}
ShadowUF:RegisterModule(Power, "powerBar", ShadowUF.L["Power bar"], true)
local function updatePower(self, elapsed)
local currentPower = UnitPower(self.parent.unit)
if( currentPower == self.currentPower ) then return end
self.currentPower = currentPower
self:SetValue(currentPower)
for _, fontString in pairs(self.parent.fontStrings) do
if( fontString.fastPower ) then
fontString:UpdateTags()
end
end
end
function Power:OnEnable(frame)
frame.powerBar = frame.powerBar or ShadowUF.Units:CreateBar(frame)
frame:RegisterUnitEvent("UNIT_MANA", self, "Update")
frame:RegisterUnitEvent("UNIT_RAGE", self, "Update")
frame:RegisterUnitEvent("UNIT_ENERGY", self, "Update")
frame:RegisterUnitEvent("UNIT_FOCUS", self, "Update")
frame:RegisterUnitEvent("UNIT_RUNIC_POWER", self, "Update")
frame:RegisterUnitEvent("UNIT_MAXMANA", self, "Update")
frame:RegisterUnitEvent("UNIT_MAXRAGE", self, "Update")
frame:RegisterUnitEvent("UNIT_MAXENERGY", self, "Update")
frame:RegisterUnitEvent("UNIT_MAXFOCUS", self, "Update")
frame:RegisterUnitEvent("UNIT_MAXRUNIC_POWER", self, "Update")
frame:RegisterUnitEvent("UNIT_DISPLAYPOWER", self, "UpdateColor")
frame:RegisterUpdateFunc(self, "UpdateColor")
frame:RegisterUpdateFunc(self, "Update")
end
function Power:OnLayoutApplied(frame)
-- Enable predicted updates which requires polling in an OnUpdate to get more up to date values
if( frame.visibility.powerBar ) then
if( ShadowUF.db.profile.units[frame.unitType].powerBar.predicted ) then
frame.powerBar:SetScript("OnUpdate", updatePower)
else
frame.powerBar:SetScript("OnUpdate", nil)
end
end
end
function Power:OnDisable(frame)
frame:UnregisterAll(self)
end
function Power:UpdateColor(frame)
local color = ShadowUF.db.profile.powerColors[select(2, UnitPowerType(frame.unit))] or ShadowUF.db.profile.powerColors.MANA
if( not ShadowUF.db.profile.units[frame.unitType].powerBar.invert ) then
frame.powerBar:SetStatusBarColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.alpha)
if( not frame.powerBar.background.overrideColor ) then
frame.powerBar.background:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.backgroundAlpha)
end
else
frame.powerBar.background:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.alpha)
color = frame.powerBar.background.overrideColor
if( not color ) then
frame.powerBar:SetStatusBarColor(0, 0, 0, 1 - ShadowUF.db.profile.bars.backgroundAlpha)
else
frame.powerBar:SetStatusBarColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.backgroundAlpha)
end
end
end
function Power:Update(frame)
frame.powerBar.currentPower = UnitPower(frame.unit)
frame.powerBar:SetMinMaxValues(0, UnitPowerMax(frame.unit))
frame.powerBar:SetValue(UnitIsDeadOrGhost(frame.unit) and 0 or not UnitIsConnected(frame.unit) and 0 or frame.powerBar.currentPower)
end
+87
View File
@@ -0,0 +1,87 @@
local Range = {
friendly = {["PRIEST"] = GetSpellInfo(2050), ["DRUID"] = GetSpellInfo(48378), ["PALADIN"] = GetSpellInfo(48782), ["SHAMAN"] = GetSpellInfo(49273)},
hostile = {["PRIEST"] = GetSpellInfo(48127), ["DRUID"] = GetSpellInfo(48461), ["PALADIN"] = GetSpellInfo(62124), ["HUNTER"] = GetSpellInfo(75), ["WARLOCK"] = GetSpellInfo(686), ["SHAMAN"] = GetSpellInfo(529), ["MAGE"] = GetSpellInfo(133), ["DEATHKNIGHT"] = GetSpellInfo(49576)},
resurrect = {["PALADIN"] = GetSpellInfo(48950), ["PRIEST"] = GetSpellInfo(25435), ["SHAMAN"] = GetSpellInfo(2008), ["DRUID"] = GetSpellInfo(48477)}
}
ShadowUF:RegisterModule(Range, "range", ShadowUF.L["Range indicator"])
local playerClass = select(2, UnitClass("player"))
local friendlySpell, hostileSpell
local resurrectSpell = Range.resurrect[playerClass]
local function checkRange(self, elapsed)
self.timeElapsed = self.timeElapsed + elapsed
if( self.timeElapsed <= 0.50 ) then return end
self.timeElapsed = 0
if( self.isFriendly and resurrectSpell and UnitIsDead(self.parent.unit) ) then
self.parent:SetRangeAlpha(IsSpellInRange(resurrectSpell, self.parent.unit) == 1 and ShadowUF.db.profile.units[self.parent.unitType].range.inAlpha or ShadowUF.db.profile.units[self.parent.unitType].range.oorAlpha)
-- We set a spell for them in our flags check, use that
elseif( self.spell ) then
self.parent:SetRangeAlpha(IsSpellInRange(self.spell, self.parent.unit) == 1 and ShadowUF.db.profile.units[self.parent.unitType].range.inAlpha or ShadowUF.db.profile.units[self.parent.unitType].range.oorAlpha)
-- That didn't work, but they are grouped lets try the actual API for this, it's a bit flaky though and not that useful generally
elseif( self.grouped ) then
self.parent:SetRangeAlpha(UnitInRange(self.parent.unit, "player") and ShadowUF.db.profile.units[self.parent.unitType].range.inAlpha or ShadowUF.db.profile.units[self.parent.unitType].range.oorAlpha)
-- Nope, fall back to interaction :(
elseif( self.isFriendly ) then
self.parent:SetRangeAlpha(CheckInteractDistance(self.parent.unit, 4) and ShadowUF.db.profile.units[self.parent.unitType].range.inAlpha or ShadowUF.db.profile.units[self.parent.unitType].range.oorAlpha)
else
self.parent:SetRangeAlpha(ShadowUF.db.profile.units[self.parent.unitType].range.inAlpha)
end
end
function Range:ForceUpdate(frame)
checkRange(frame.range, 1)
end
function Range:OnEnable(frame)
if( not frame.range ) then
frame.range = CreateFrame("Frame", nil, frame)
frame.range:SetScript("OnUpdate", checkRange)
frame.range.timeElapsed = 0
frame.range.parent = frame
frame.range:Hide()
end
-- I want to say UNIT_FACTION is the function thats called when a unit is MCed, but not 100% sure
frame:RegisterUnitEvent("UNIT_FACTION", self, "UpdateFlags")
frame:RegisterNormalEvent("PARTY_MEMBERS_CHANGED", self, "UpdateFlags")
frame:RegisterNormalEvent("RAID_ROSTER_UPDATE", self, "UpdateFlags")
frame:RegisterUpdateFunc(self, "UpdateFlags")
frame:RegisterUpdateFunc(self, "ForceUpdate")
end
function Range:OnLayoutApplied(frame)
if( frame.visibility.range ) then
frame.range.hostileSpell = ShadowUF.db.profile.range["hostile" .. playerClass] or self.hostile[playerClass]
frame.range.friendlySpell = ShadowUF.db.profile.range["friendly" .. playerClass] or self.friendly[playerClass]
end
end
function Range:OnDisable(frame)
frame:UnregisterAll(self)
if( frame.range ) then
frame.range:Hide()
frame:SetRangeAlpha(1.0)
end
end
-- I'd rather store the flags here, they rarely change and we can do that based off events, no sense in doing it eveyr 0.50s
function Range:UpdateFlags(frame)
frame.range.canAttack = UnitCanAttack("player", frame.unit)
frame.range.isFriendly = UnitIsFriend("player", frame.unit) and UnitCanAssist("player", frame.unit)
frame.range.grouped = UnitInRaid(frame.unit) or UnitInParty(frame.unit)
frame.range.spell = frame.range.canAttack and frame.range.hostileSpell or frame.range.isFriendly and frame.range.friendlySpell or nil
-- No sense in updating range if we have no data
if( UnitIsGhost(frame.unit) or not UnitIsConnected(frame.unit) or ( not frame.range.spell and not frame.range.grouped and not frame.range.isFriendly ) ) then
frame:SetRangeAlpha(ShadowUF.db.profile.units[frame.unitType].range.inAlpha)
frame.range:Hide()
else
frame.range:Show()
end
end
+115
View File
@@ -0,0 +1,115 @@
local Runes = {}
local RUNE_MAP = {[1] = 1, [2] = 2, [3] = 5, [4] = 6, [5] = 3, [6] = 4}
local runeColors = {{r = 1, g = 0, b = 0.4}, {r = 0, g = 1, b = 0.4}, {r = 0, g = 0.4, b = 1}, {r = 0.7, g = 0.5, b = 1}}
ShadowUF:RegisterModule(Runes, "runeBar", ShadowUF.L["Rune bar"], true, "DEATHKNIGHT")
function Runes:OnEnable(frame)
if( not frame.runeBar ) then
frame.runeBar = CreateFrame("StatusBar", nil, frame)
frame.runeBar:SetMinMaxValues(0, 1)
frame.runeBar:SetValue(0)
frame.runeBar.runes = {}
for id=1, 6 do
local rune = ShadowUF.Units:CreateBar(frame)
rune:SetFrameLevel(1)
if( id > 1 ) then
rune:SetPoint("TOPLEFT", frame.runeBar.runes[RUNE_MAP[id - 1]], "TOPRIGHT", 1, 0)
else
rune:SetPoint("TOPLEFT", frame.runeBar, "TOPLEFT", 0, 0)
end
frame.runeBar.runes[RUNE_MAP[id]] = rune
end
end
frame:RegisterNormalEvent("RUNE_POWER_UPDATE", self, "UpdateUsable")
frame:RegisterNormalEvent("RUNE_TYPE_UPDATE", self, "Update")
frame:RegisterUpdateFunc(self, "Update")
frame:RegisterUpdateFunc(self, "UpdateUsable")
end
function Runes:OnDisable(frame)
frame:UnregisterAll(self)
end
function Runes:OnLayoutApplied(frame)
if( frame.visibility.runeBar ) then
local barWidth = (frame.runeBar:GetWidth() - 5) / 6
for id, rune in pairs(frame.runeBar.runes) do
if( ShadowUF.db.profile.units[frame.unitType].runeBar.background ) then
rune.background:Show()
else
rune.background:Hide()
end
rune.background:SetTexture(ShadowUF.Layout.mediaPath.statusbar)
rune.background:SetHorizTile(false)
rune:SetStatusBarTexture(ShadowUF.Layout.mediaPath.statusbar)
rune:GetStatusBarTexture():SetHorizTile(false)
rune:SetHeight(frame.runeBar:GetHeight())
rune:SetWidth(barWidth)
end
end
end
local function runeMonitor(self, elapsed)
local time = GetTime()
self:SetValue(time)
if( time >= self.endTime ) then
self:SetValue(self.endTime)
self:SetAlpha(1.0)
self:SetScript("OnUpdate", nil)
end
end
-- Updates the timers on runes
function Runes:UpdateUsable(frame, event, id, usable)
if( not id ) then
self:UpdateColors(frame)
return
elseif( not frame.runeBar.runes[id] ) then
return
end
local rune = frame.runeBar.runes[id]
local startTime, cooldown, cooled = GetRuneCooldown(id)
if( not cooled ) then
rune.endTime = GetTime() + cooldown
rune:SetMinMaxValues(startTime, rune.endTime)
rune:SetValue(GetTime())
rune:SetAlpha(0.40)
rune:SetScript("OnUpdate", runeMonitor)
else
rune:SetMinMaxValues(0, 1)
rune:SetValue(1)
rune:SetAlpha(1.0)
rune:SetScript("OnUpdate", nil)
end
end
function Runes:UpdateColors(frame)
for id, rune in pairs(frame.runeBar.runes) do
local color = runeColors[GetRuneType(id)]
if( color ) then
rune:SetStatusBarColor(color.r, color.g, color.b)
color = ShadowUF.db.profile.bars.backgroundColor or ShadowUF.db.profile.units[frame.unitType].runeBar.backgroundColor or color
rune.background:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.backgroundAlpha)
end
end
end
-- No rune is passed for full update (Login), a single rune is passed when a single rune type changes, such as Blood Tap
function Runes:Update(frame, event, id)
if( id ) then
local color = runeColors[GetRuneType(id)]
frame.runeBar.runes[id]:SetStatusBarColor(color.r, color.g, color.b)
color = ShadowUF.db.profile.bars.backgroundColor or ShadowUF.db.profile.units[frame.unitType].runeBar.backgroundColor or color
frame.runeBar.runes[id].background:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.backgroundAlpha)
end
end
File diff suppressed because it is too large Load Diff
+111
View File
@@ -0,0 +1,111 @@
local Totems = {}
local totemColors = {}
local MAX_TOTEMS = MAX_TOTEMS
-- Death Knights untalented ghouls are guardians and are considered totems........... so set it up for them
if( select(2, UnitClass("player")) == "DEATHKNIGHT" ) then
MAX_TOTEMS = 1
ShadowUF:RegisterModule(Totems, "totemBar", ShadowUF.L["Guardian bar"], true, "DEATHKNIGHT")
else
ShadowUF:RegisterModule(Totems, "totemBar", ShadowUF.L["Totem bar"], true, "SHAMAN")
end
function Totems:OnEnable(frame)
if( not frame.totemBar ) then
frame.totemBar = CreateFrame("Frame", nil, frame)
frame.totemBar.totems = {}
for id=1, MAX_TOTEMS do
local totem = ShadowUF.Units:CreateBar(frame)
totem:SetFrameLevel(1)
totem:SetMinMaxValues(0, 1)
totem:SetValue(0)
totem.id = MAX_TOTEMS == 1 and 1 or TOTEM_PRIORITIES[id]
if( id > 1 ) then
totem:SetPoint("TOPLEFT", frame.totemBar.totems[id - 1], "TOPRIGHT", 1, 0)
else
totem:SetPoint("TOPLEFT", frame.totemBar, "TOPLEFT", 0, 0)
end
table.insert(frame.totemBar.totems, totem)
end
if( MAX_TOTEMS == 1 ) then
totemColors[1] = ShadowUF.db.profile.classColors.PET
else
totemColors[1] = {r = 1, g = 0, b = 0.4}
totemColors[2] = {r = 0, g = 1, b = 0.4}
totemColors[3] = {r = 0, g = 0.4, b = 1}
totemColors[4] = {r = 0.90, g = 0.90, b = 0.90}
end
end
frame:RegisterNormalEvent("PLAYER_TOTEM_UPDATE", self, "Update")
frame:RegisterUpdateFunc(self, "Update")
end
function Totems:OnDisable(frame)
frame:UnregisterAll(self)
end
function Totems:OnLayoutApplied(frame)
if( frame.visibility.totemBar ) then
local barWidth = (frame.totemBar:GetWidth() - (MAX_TOTEMS - 1)) / MAX_TOTEMS
for _, totem in pairs(frame.totemBar.totems) do
if( ShadowUF.db.profile.units[frame.unitType].totemBar.background ) then
local color = ShadowUF.db.profile.bars.backgroundColor or ShadowUF.db.profile.units[frame.unitType].totemBar.backgroundColor or totemColors[totem.id]
totem.background:SetTexture(ShadowUF.Layout.mediaPath.statusbar)
totem.background:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.backgroundAlpha)
totem.background:Show()
else
totem.background:Hide()
end
totem:SetHeight(frame.totemBar:GetHeight())
totem:SetWidth(barWidth)
totem:SetStatusBarTexture(ShadowUF.Layout.mediaPath.statusbar)
totem:SetStatusBarColor(totemColors[totem.id].r, totemColors[totem.id].g, totemColors[totem.id].b, ShadowUF.db.profile.bars.alpha)
totem:GetStatusBarTexture():SetHorizTile(false)
end
end
end
local function totemMonitor(self, elapsed)
local time = GetTime()
self:SetValue(self.endTime - time)
if( time >= self.endTime ) then
self:SetValue(0)
self:SetScript("OnUpdate", nil)
end
end
function Totems:Update(frame)
local totalActive = 0
for _, indicator in pairs(frame.totemBar.totems) do
local have, name, start, duration = GetTotemInfo(indicator.id)
if( have and start > 0 ) then
indicator.have = true
indicator.endTime = start + duration
indicator:SetMinMaxValues(0, duration)
indicator:SetValue(indicator.endTime - GetTime())
indicator:SetScript("OnUpdate", totemMonitor)
indicator:SetAlpha(1.0)
totalActive = totalActive + 1
elseif( indicator.have ) then
indicator.have = nil
indicator:SetScript("OnUpdate", nil)
indicator:SetMinMaxValues(0, 1)
indicator:SetValue(0)
end
end
-- Only guardian timers should auto hide, nothing else
if( MAX_TOTEMS == 1 ) then
ShadowUF.Layout:SetBarVisibility(frame, "totemBar", totalActive > 0)
end
end
File diff suppressed because it is too large Load Diff
+161
View File
@@ -0,0 +1,161 @@
local XP = {}
local L = ShadowUF.L
ShadowUF:RegisterModule(XP, "xpBar", L["XP/Rep bar"], true)
local function OnEnter(self)
if( self.tooltip ) then
GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT")
GameTooltip:SetText(self.tooltip)
end
end
local function OnLeave(self)
GameTooltip:Hide()
end
function XP:OnEnable(frame)
if( not frame.xpBar ) then
frame.xpBar = CreateFrame("Frame", nil, frame)
frame.xpBar:SetScript("OnEnter", OnEnter)
frame.xpBar:SetScript("OnLeave", OnLeave)
frame.xpBar:EnableMouse(true)
frame.xpBar.xp = ShadowUF.Units:CreateBar(frame.xpBar)
frame.xpBar.xp:SetPoint("BOTTOMLEFT", frame.xpBar)
frame.xpBar.xp:SetPoint("BOTTOMRIGHT", frame.xpBar)
if( frame.unitType == "player" ) then
frame.xpBar.rep = ShadowUF.Units:CreateBar(frame.xpBar)
frame.xpBar.rep:SetPoint("TOPLEFT", frame.xpBar)
frame.xpBar.rep:SetPoint("TOPRIGHT", frame.xpBar)
end
frame.xpBar.rested = CreateFrame("StatusBar", nil, frame.xpBar.xp)
frame.xpBar.rested:SetFrameLevel(frame.xpBar.xp:GetFrameLevel() - 1)
frame.xpBar.rested:SetAllPoints(frame.xpBar.xp)
end
frame:RegisterNormalEvent("ENABLE_XP_GAIN", self, "Update")
frame:RegisterNormalEvent("DISABLE_XP_GAIN", self, "Update")
if( frame.unitType == "player" ) then
frame:RegisterNormalEvent("PLAYER_XP_UPDATE", self, "Update")
frame:RegisterNormalEvent("UPDATE_EXHAUSTION", self, "Update")
frame:RegisterNormalEvent("PLAYER_LEVEL_UP", self, "Update")
frame:RegisterNormalEvent("UPDATE_FACTION", self, "Update")
else
frame:RegisterNormalEvent("UNIT_PET_EXPERIENCE", self, "Update")
frame:RegisterUnitEvent("UNIT_LEVEL", self, "Update")
end
frame:RegisterUpdateFunc(self, "Update")
end
function XP:OnDisable(frame)
frame:UnregisterAll(self)
end
function XP:OnLayoutApplied(frame)
if( frame.visibility.xpBar ) then
frame.xpBar.xp:SetStatusBarTexture(ShadowUF.Layout.mediaPath.statusbar)
frame.xpBar.xp:SetStatusBarColor(ShadowUF.db.profile.xpColors.normal.r, ShadowUF.db.profile.xpColors.normal.g, ShadowUF.db.profile.xpColors.normal.b, ShadowUF.db.profile.bars.alpha)
frame.xpBar.xp.background:SetVertexColor(ShadowUF.db.profile.xpColors.normal.r, ShadowUF.db.profile.xpColors.normal.g, ShadowUF.db.profile.xpColors.normal.b, ShadowUF.db.profile.bars.backgroundAlpha)
frame.xpBar.xp.background:SetTexture(ShadowUF.Layout.mediaPath.statusbar)
frame.xpBar.rested:SetStatusBarTexture(ShadowUF.Layout.mediaPath.statusbar)
frame.xpBar.rested:SetStatusBarColor(ShadowUF.db.profile.xpColors.rested.r, ShadowUF.db.profile.xpColors.rested.g, ShadowUF.db.profile.xpColors.rested.b, ShadowUF.db.profile.bars.alpha)
if( frame.xpBar.rep ) then
frame.xpBar.rep:SetStatusBarTexture(ShadowUF.Layout.mediaPath.statusbar)
frame.xpBar.rep.background:SetTexture(ShadowUF.Layout.mediaPath.statusbar)
end
end
end
-- Format 5000 into 5,000
local function formatNumber(number)
local found
while( true ) do
number, found = string.gsub(number, "^(-?%d+)(%d%d%d)", "%1,%2")
if( found == 0 ) then break end
end
return number
end
function XP:UpdateRep(frame)
if( not frame.xpBar.rep ) then return end
local name, reaction, min, max, current = GetWatchedFactionInfo()
if( not name ) then
frame.xpBar.rep:Hide()
return
end
-- Blizzard stores faction info related to Exalted, not your current level, so get more mathier to find the current reputation using the current standing tier
current = math.abs(min - current)
max = math.abs(min - max)
local color = FACTION_BAR_COLORS[reaction]
frame.xpBar.rep:SetMinMaxValues(0, max)
frame.xpBar.rep:SetValue(reaction == 8 and max or current)
frame.xpBar.rep.tooltip = string.format(L["%s (%s): %s/%s (%.2f%% done)"], name, GetText("FACTION_STANDING_LABEL" .. reaction, UnitSex("player")), formatNumber(current), formatNumber(max), reaction == 8 and 100 or (current / max) * 100)
frame.xpBar.rep:SetStatusBarColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.alpha)
frame.xpBar.rep.background:SetVertexColor(color.r, color.g, color.b, ShadowUF.db.profile.bars.backgroundAlpha)
frame.xpBar.rep:Show()
end
function XP:UpdateXP(frame)
-- At the level cap or XP is disabled, or the pet is actually a vehicle right now, swap to reputation bar (or hide it)
if( UnitLevel(frame.unitOwner) == MAX_PLAYER_LEVEL or IsXPUserDisabled() or ( frame.unitOwner == "pet" and UnitExists("vehicle") ) ) then
frame.xpBar.xp:Hide()
return
end
local current, max
if( frame.unitOwner == "player" ) then
current, max = UnitXP(frame.unitOwner), UnitXPMax(frame.unitOwner)
else
current, max = GetPetExperience()
end
local min = math.min(0, current)
frame.xpBar.xp:SetMinMaxValues(min, max)
frame.xpBar.xp:SetValue(current)
frame.xpBar.xp:Show()
if( frame.unitOwner == "player" and GetXPExhaustion() ) then
frame.xpBar.rested:SetMinMaxValues(min, max)
frame.xpBar.rested:SetValue(math.min(current + GetXPExhaustion(), max))
frame.xpBar.rested:Show()
frame.xpBar.xp.tooltip = string.format(L["Level %s - %s: %s/%s (%.2f%% done), %s rested."], UnitLevel(frame.unitOwner), UnitLevel(frame.unitOwner) + 1, formatNumber(current), formatNumber(max), (current / max) * 100, formatNumber(GetXPExhaustion()))
else
frame.xpBar.rested:Hide()
frame.xpBar.xp.tooltip = string.format(L["Level %s - %s: %s/%s (%.2f%% done)"], UnitLevel(frame.unitOwner), UnitLevel(frame.unitOwner) + 1, formatNumber(current), formatNumber(max), (current / max) * 100)
end
end
function XP:Update(frame)
self:UpdateRep(frame)
self:UpdateXP(frame)
if( ( not frame.xpBar.rep or not frame.xpBar.rep:IsShown() ) and not frame.xpBar.xp:IsShown() ) then
ShadowUF.Layout:SetBarVisibility(frame, "xpBar", false)
return
end
ShadowUF.Layout:SetBarVisibility(frame, "xpBar", true)
if( frame.xpBar.rep and frame.xpBar.rep:IsVisible() and frame.xpBar.xp:IsVisible() ) then
frame.xpBar.rep:SetHeight(frame.xpBar:GetHeight() * 0.48)
frame.xpBar.xp:SetHeight(frame.xpBar:GetHeight() * 0.48)
frame.xpBar.tooltip = frame.xpBar.rep.tooltip .. "\n" .. frame.xpBar.xp.tooltip
elseif( frame.xpBar.rep and frame.xpBar.rep:IsVisible() ) then
frame.xpBar.rep:SetHeight(frame.xpBar:GetHeight())
frame.xpBar.tooltip = frame.xpBar.rep.tooltip
elseif( frame.xpBar.xp:IsVisible() ) then
frame.xpBar.xp:SetHeight(frame.xpBar:GetHeight())
frame.xpBar.tooltip = frame.xpBar.xp.tooltip
end
end