missing files
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user