big commit

This commit is contained in:
Bunny67
2017-12-16 20:18:25 +03:00
parent 7f59921969
commit 5585bc44b6
103 changed files with 21575 additions and 2175 deletions
@@ -1,7 +1,8 @@
## Interface: 11200 ## Interface: 11200
## Title: !Compatibility ## Title: !Compatibility
## Notes: Compatibility functions for Vanilla ## Notes: Compatibility functions for Vanilla
## Version: 1.0 ## Version: 1.1
errorHandler.lua
api\api.xml api\api.xml
debugTools.lua slashCommands.lua
+2 -1
View File
@@ -1,4 +1,5 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="wowLua.lua"/> <Script file="luaAPI.lua"/>
<Include file="..\libs\libs.xml"/>
<Script file="wowAPI.lua"/> <Script file="wowAPI.lua"/>
</Ui> </Ui>
+201
View File
@@ -0,0 +1,201 @@
-- Cache global variables
local assert = assert
local error = error
local geterrorhandler = geterrorhandler
local pairs = pairs
local pcall = pcall
local tostring = tostring
local type = type
local unpack = unpack
local ceil, floor = math.ceil, math.floor
local find, format, gsub, sub = string.find, string.format, string.gsub, string.sub
local getn, insert = table.getn, table.insert
math.huge = 1/0
string.gmatch = string.gfind
function difftime(time2, time1)
assert(type(time2) == "number", format("bad argument #1 to 'difftime' (number expected, got %s)", time2 and type(time2) or "no value"))
assert(not time1 or type(time1) == "number", format("bad argument #2 to 'difftime' (number expected, got %s)", time1 and type(time1) or "no value"))
return time1 and time2 - time1 or time2
end
function select(n, ...)
assert(type(n) == "number" or type(n) == "string", format("bad argument #1 to 'select' (number expected, got %s)", n and type(n) or "no value"))
if type(n) == "string" and n == "#" then
if type(arg) == "table" then
return getn(arg)
else
return 1
end
end
local temp = {}
for i = n, getn(arg) do
insert(temp, arg[i])
end
return unpack(temp)
end
function math.modf(i)
assert(type(i) == "number", format("bad argument #1 to 'modf' (number expected, got %s)", i and type(i) or "no value"))
local int = i >= 0 and floor(i) or ceil(i)
return int, i - int
end
function string.join(delimiter, ...)
assert(type(delimiter) == "string" or type(delimiter) == "number", format("bad argument #1 to 'join' (string expected, got %s)", delimiter and type(delimiter) or "no value"))
local size = getn(arg)
if size == 0 then
return ""
end
local text = arg[1]
for i = 2, size do
text = text..delimiter..arg[i]
end
return text
end
strjoin = string.join
function string.match(str, pattern, index)
assert(type(str) == "string" or type(str) == "number", format("bad argument #1 to 'match' (string expected, got %s)", str and type(str) or "no value"))
assert(type(pattern) == "string", format("bad argument #2 to 'match' (string expected, got %s)", pattern and type(pattern) or "no value"))
str = type(str) == "number" and tostring(str) or str
local _, _, match = find(index and sub(str, index) or str, "("..pattern..")")
return match
end
strmatch = string.match
function string.split(delimiter, str)
assert(type(delimiter) == "string" or type(str) == "number", format("bad argument #1 to 'split' (string expected, got %s)", delimiter and type(delimiter) or "no value"))
assert(type(str) == "string", format("bad argument #2 to 'split' (string expected, got %s)", str and type(str) or "no value"))
local fields = {}
local pattern = format("([^%s]+)", delimiter)
str = type(str) == "number" and tostring(str) or str
gsub(str, pattern, function(c) fields[getn(fields) + 1] = c end)
return unpack(fields)
end
strsplit = string.split
function string.trim(str, chars)
assert(type(str) == "string" or type(str) == "number", format("bad argument #1 to 'trim' (string expected, got %s)", delimiter and type(delimiter) or "no value"))
str = type(str) == "number" and tostring(str) or str
--[[
if chars then
local size = string.len(chars)
local token = ""
for i = 1, size do
token = token .. string.sub(chars, i, i + 1) .. "*"
if size > 1 and i < size then
token = token.."|"
end
end
token = "["..token.."]"
local trimed = 1
while trimed == 1 do
str, trimed = string.gsub(str, "^"..token.."(._)"..token.."$", "")
end
else
-- remove leading/trailing [space][tab][return][newline]
str = string.gsub(str, "^%s*(.-)%s*$", "%1")
end
return str
]]
return string.gsub(str, "^%s*(.-)%s*$", "%1")
end
strtrim = string.trim
function table.wipe(t)
assert(type(t) == "table", format("bad argument #1 to 'wipe' (table expected, got %s)", t and type(t) or "no value"))
for k in pairs(t) do
t[k] = nil
end
return t
end
wipe = table.wipe
local LOCAL_ToStringAllTemp = {}
function tostringall(...)
local n = getn(arg)
-- Simple versions for common argument counts
if (n == 1) then
return tostring(arg[1])
elseif (n == 2) then
return tostring(arg[1]), tostring(arg[2])
elseif (n == 3) then
return tostring(arg[1]), tostring(arg[2]), tostring(arg[3])
elseif (n == 0) then
return
end
local needfix
for i = 1, n do
local v = arg[i]
if (type(v) ~= "string") then
needfix = i
break
end
end
if (not needfix) then return unpack(arg) end
wipe(LOCAL_ToStringAllTemp)
for i = 1, needfix - 1 do
LOCAL_ToStringAllTemp[i] = arg[i]
end
for i = needfix, n do
LOCAL_ToStringAllTemp[i] = tostring(arg[i])
end
return unpack(LOCAL_ToStringAllTemp)
end
local LOCAL_PrintHandler = function(...)
DEFAULT_CHAT_FRAME:AddMessage(strjoin(" ", tostringall(unpack(arg))))
end
function setprinthandler(func)
if (type(func) ~= "function") then
error("Invalid print handler")
else
LOCAL_PrintHandler = func
end
end
function getprinthandler() return LOCAL_PrintHandler end
local function print_inner(...)
local ok, err = pcall(LOCAL_PrintHandler, unpack(arg))
if (not ok) then
local func = geterrorhandler()
func(err)
end
end
function print(...)
pcall(print_inner, unpack(arg))
end
SLASH_PRINT1 = "/print"
SlashCmdList["PRINT"] = print
+318 -61
View File
@@ -1,39 +1,134 @@
--Cache global variables -- Cache global variables
local _G = getfenv() local _G = _G
local assert = assert local assert = assert
local error = error local date = date
local pairs = pairs
local tonumber = tonumber
local type = type local type = type
local unpack = unpack local unpack = unpack
local date = date local format, gsub, lower, match, upper = string.format, string.gsub, string.lower, string.match, string.upper
local gsub = string.gsub local getn = table.getn
-- WoW API
local GetQuestGreenRange = GetQuestGreenRange
local GetRealZoneText = GetRealZoneText
local IsInInstance = IsInInstance
local UnitBuff = UnitBuff
local UnitDebuff = UnitDebuff
local UnitLevel = UnitLevel
-- WoW Variables
local DUNGEON_DIFFICULTY1 = DUNGEON_DIFFICULTY1
local TIMEMANAGER_AM = gsub(TIME_TWELVEHOURAM, "^.-(%w+)$", "%1")
local TIMEMANAGER_PM = gsub(TIME_TWELVEHOURPM, "^.-(%w+)$", "%1")
-- Libs
local LBC = LibStub("LibBabble-Class-3.0"):GetLookupTable()
local LBZ = LibStub("LibBabble-Zone-3.0"):GetLookupTable()
function hooksecurefunc(arg1, arg2, arg3) CLASS_SORT_ORDER = {
if type(arg1) == "string" then "WARRIOR",
arg1, arg2, arg3 = _G, arg1, arg2 "PALADIN",
end "PRIEST",
"SHAMAN",
"DRUID",
"ROGUE",
"MAGE",
"WARLOCK",
"HUNTER"
}
MAX_CLASSES = getn(CLASS_SORT_ORDER)
local orig = arg1[arg2] LOCALIZED_CLASS_NAMES_MALE = {}
if type(orig) ~= "function" then LOCALIZED_CLASS_NAMES_FEMALE = {}
error("The function "..arg2.." does not exist", 2)
end
arg1[arg2] = function(...) CLASS_ICON_TCOORDS = {
local tmp = {orig(unpack(arg))} ["WARRIOR"] = {0, 0.25, 0, 0.25},
arg3(unpack(arg)) ["MAGE"] = {0.25, 0.49609375, 0, 0.25},
return unpack(tmp) ["ROGUE"] = {0.49609375, 0.7421875, 0, 0.25},
["DRUID"] = {0.7421875, 0.98828125, 0, 0.25},
["HUNTER"] = {0, 0.25, 0.25, 0.5},
["SHAMAN"] = {0.25, 0.49609375, 0.25, 0.5},
["PRIEST"] = {0.49609375, 0.7421875, 0.25, 0.5},
["WARLOCK"] = {0.7421875, 0.98828125, 0.25, 0.5},
["PALADIN"] = {0, 0.25, 0.5, 0.75}
}
QuestDifficultyColors = {
["impossible"] = {r = 1.00, g = 0.10, b = 0.10},
["verydifficult"] = {r = 1.00, g = 0.50, b = 0.25},
["difficult"] = {r = 1.00, g = 1.00, b = 0.00},
["standard"] = {r = 0.25, g = 0.75, b = 0.25},
["trivial"] = {r = 0.50, g = 0.50, b = 0.50},
["header"] = {r = 0.70, g = 0.70, b = 0.70}
}
function HookScript(frame, scriptType, handler)
assert(type(frame) == "table" and frame.GetScript and type(scriptType) == "string" and type(handler) == "function", "Usage: HookScript(frame, \"type\", function)")
local original_scipt = frame:GetScript(scriptType)
if original_scipt then
frame:SetScript(scriptType, function(...)
local original_return = {original_scipt(unpack(arg))}
handler(unpack(arg))
return unpack(original_return)
end)
else
frame:SetScript(scriptType, handler)
end end
end end
local function noop() end function hooksecurefunc(arg1, arg2, arg3)
function HookScript(frame, method, func) local isMethod = type(arg1) == "table" and type(arg2) == "string" and type(arg1[arg2]) == "function" and type(arg3) == "function"
assert(frame, "HookScript: frame argument missing") assert(isMethod or (type(arg1) == "string" and type(_G[arg1]) == "function" and type(arg2) == "function"), "Usage: hooksecurefunc([table,] \"functionName\", hookfunc)")
local orig = frame:GetScript(method) or noop if not isMethod then
frame:SetScript(method, function(...) arg1, arg2, arg3 = _G, arg1, arg2
local tmp = {orig(unpack(arg))} end
func(unpack(arg))
return unpack(tmp) local original_func = arg1[arg2]
end)
arg1[arg2] = function(...)
local original_return = {original_func(unpack(arg))}
arg3(unpack(arg))
return unpack(original_return)
end
end
--[[ issecurevariable
Returns 1, nil for undefined variables. This is because an undefined variable is secure since you have not tainted it.
Returns 1, nil for all untainted variables (i.e. Blizzard variables).
Returns nil for any global variable that is hooked insecurely (tainted), even unprotected ones like UnitName().
Returns nil for all user defined global variables.
If a table is passed first, it checks table.variable (e.g. issecurevariable(PlayerFrame, "Show") checks PlayerFrame["Show"] or PlayerFrame.Show (they are the same thing)).
]]
function issecurevariable(tab, var)
-- assert(type(tab) == "table" and type(var) == "string", "Usage: issecurevariable([table,] \"variable\")")
return
end
function tContains(table, item)
local index = 1
while table[index] do
if item == table[index] then
return 1
end
index = index + 1
end
return
end
function UnitAura(unit, i, filter)
assert((type(unit) == "string" or type(unit) == "number") and (type(i) == "string" or type(i) == "number"), "Usage: UnitAura(\"unit\", index [, filter])")
if not filter or match(filter, "(HELPFUL)") then
local name, rank, aura, count, duration, maxDuration = UnitBuff(unit, i, filter)
return name, rank, aura, count, nil, duration or 0, maxDuration or 0
else
local name, rank, aura, count, dType, duration, maxDuration = UnitDebuff(unit, i, filter)
return name, rank, aura, count, dType, duration or 0, maxDuration or 0
end
end end
function BetterDate(formatString, timeVal) function BetterDate(formatString, timeVal)
@@ -47,29 +142,8 @@ function BetterDate(formatString, timeVal)
return date(formatString, timeVal) return date(formatString, timeVal)
end end
RAID_CLASS_COLORS = {
["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},
["WARRIOR"] = {r = 0.78, g = 0.61, b = 0.43},
};
QuestDifficultyColors = {
["impossible"] = {r = 1.00, g = 0.10, b = 0.10};
["verydifficult"] = {r = 1.00, g = 0.50, b = 0.25};
["difficult"] = {r = 1.00, g = 1.00, b = 0.00};
["standard"] = {r = 0.25, g = 0.75, b = 0.25};
["trivial"] = {r = 0.50, g = 0.50, b = 0.50};
["header"] = {r = 0.70, g = 0.70, b = 0.70};
};
function GetQuestDifficultyColor(level) function GetQuestDifficultyColor(level)
local levelDiff = level - UnitLevel("player") local levelDiff = level - UnitLevel("player")
local color
if levelDiff >= 5 then if levelDiff >= 5 then
return QuestDifficultyColors["impossible"] return QuestDifficultyColors["impossible"]
elseif levelDiff >= 3 then elseif levelDiff >= 3 then
@@ -83,21 +157,204 @@ function GetQuestDifficultyColor(level)
end end
end end
function EasyMenu(menuList, menuFrame, anchor, x, y, displayMode, autoHideDelay) function FillLocalizedClassList(tab, female)
if displayMode == "MENU" then assert(type(tab) == "table", "Usage: FillLocalizedClassList(classTable[, isFemale])")
menuFrame.displayMode = displayMode
end
UIDropDownMenu_Initialize(menuFrame, EasyMenu_Initialize, displayMode)
ToggleDropDownMenu(1, nil, menuFrame, anchor, x, y, menuList)
end
function EasyMenu_Initialize() for _, engClass in ipairs(CLASS_SORT_ORDER) do
print(level, info) if female then
for index = 1, getn(menuList) do tab[engClass] = LBC[engClass]
local value = menuList[index] else
if value.text then tab[engClass] = LBC[gsub(lower(engClass), "^%l", upper)]
value.index = index;
UIDropDownMenu_AddButton(value, level)
end end
end end
return true
end
FillLocalizedClassList(LOCALIZED_CLASS_NAMES_MALE)
FillLocalizedClassList(LOCALIZED_CLASS_NAMES_FEMALE, true)
local zoneInfo = {
-- Battlegrounds
[LBZ["Warsong Gulch"]] = {mapID = 443, maxPlayers = 10},
[LBZ["Arathi Basin"]] = {mapID = 461, maxPlayers = 15},
[LBZ["Alterac Valley"]] = {mapID = 401, maxPlayers = 40},
-- Raids
[LBZ["Zul'Gurub"]] = {mapID = 309, maxPlayers = 20},
[LBZ["Onyxia's Lair"]] = {mapID = 249, maxPlayers = 40},
[LBZ["Molten Core"]] = {mapID = 409, maxPlayers = 40},
[LBZ["Ruins of Ahn'Qiraj"]] = {mapID = 509, maxPlayers = 20},
[LBZ["Temple of Ahn'Qiraj"]] = {mapID = 531, maxPlayers = 40},
[LBZ["Blackwing Lair"]] = {mapID = 469, maxPlayers = 40},
[LBZ["Naxxramas"]] = {mapID = 533, maxPlayers = 40},
}
local mapByID = {}
for mapName in pairs(zoneInfo) do
mapByID[zoneInfo[mapName].mapID] = mapName
end
local function GetMaxPlayersByType(instanceType, zoneName)
if instanceType == "none" then
return 40
elseif instanceType == "party" then
return 5
elseif instanceType == "arena" then
return 5
elseif zoneName ~= "" and zoneInfo[zoneName] then
if instanceType == "pvp" then
return zoneInfo[zoneName].maxPlayers
elseif instanceType == "raid" then
return zoneInfo[zoneName].maxPlayers
end
else
return 0
end
end
function GetInstanceInfo()
local inInstance, instanceType = IsInInstance()
if not inInstance then return end
local name = GetRealZoneText()
local difficulty = 1
local difficultyName = DUNGEON_DIFFICULTY1
local maxPlayers = GetMaxPlayersByType(instanceType, name)
difficultyName = format("%d %s", maxPlayers, difficultyName)
return name, instanceType, difficulty, difficultyName, maxPlayers
end
function GetCurrentMapAreaID()
if not IsInInstance() then return end
local zoneName = GetRealZoneText()
if zoneName ~= "" and zoneInfo[zoneName] then
return zoneInfo[zoneName].mapID
else
return 0
end
end
function GetMapNameByID(id)
assert(type(id) == "string" or type(id) == "number", format("Bad argument #1 to \"GetMapNameByID\" (number expected, got %s)", id and type(id) or "no value"))
return mapByID[tonumber(id)]
end
local arrow
function GetPlayerFacing()
if not arrow then
local obj = Minimap
for i = 1, obj:GetNumChildren() do
local child = select(i, obj:GetChildren())
if child and child.GetModel and child:GetModel() == "interface\\minimap\\minimaparrow.m2" then
arrow = child
break
end
end
end
return arrow and arrow:GetFacing()
end
function ToggleFrame(frame)
if frame:IsShown() then
HideUIPanel(frame)
else
ShowUIPanel(frame)
end
end
local function OnOrientationChanged(self, orientation)
self.texturePointer.verticalOrientation = orientation == "VERTICAL"
if self.texturePointer.verticalOrientation then
self.texturePointer:SetPoint("BOTTOMLEFT", self)
else
self.texturePointer:SetPoint("LEFT", self)
end
end
local function OnSizeChanged()
local width, height = ElvUF_Player.Health:GetWidth(), ElvUF_Player.Health:GetHeight()
this.texturePointer.width = width
this.texturePointer.height = height
this.texturePointer:SetWidth(width)
this.texturePointer:SetHeight(height)
end
local function OnValueChanged()
local _, max = this:GetMinMaxValues()
if this.texturePointer.verticalOrientation then
this.texturePointer:SetHeight(this.texturePointer.height * (arg1 / max))
else
this.texturePointer:SetWidth(this.texturePointer.width * (arg1 / max))
end
end
function CreateStatusBarTexturePointer(statusbar)
assert(type(statusbar) == "table", format("Bad argument #1 to \"CreateStatusBarTexturePointer\" (table expected, got %s)", statusbar and type(statusbar) or "no value"))
assert(statusbar.GetObjectType and statusbar:GetObjectType() == "StatusBar", "Bad argument #1 to \"CreateStatusBarTexturePointer\" (statusbar object expected)")
local f = statusbar:CreateTexture()
f.width = statusbar:GetWidth()
f.height = statusbar:GetHeight()
f.vertical = statusbar:GetOrientation() == "VERTICAL"
f:SetWidth(f.width)
f:SetHeight(f.height)
if f.verticalOrientation then
f:SetPoint("BOTTOMLEFT", statusbar)
else
f:SetPoint("LEFT", statusbar)
end
statusbar.texturePointer = f
statusbar:SetScript("OnSizeChanged", OnSizeChanged)
statusbar:SetScript("OnValueChanged", OnValueChanged)
hooksecurefunc(statusbar, "SetOrientation", OnOrientationChanged)
return f
end
local threatColors = {
[0] = {0.69, 0.69, 0.69},
[1] = {1, 1, 0.47},
[2] = {1, 0.6, 0},
[3] = {1, 0, 0}
}
function GetThreatStatusColor(statusIndex)
if not (type(statusIndex) == "number" and statusIndex >= 0 and statusIndex < 4) then
statusIndex = 0
end
return threatColors[statusIndex][1], threatColors[statusIndex][2], threatColors[statusIndex][3]
end
function GetThreatStatus(currentThreat, maxThreat)
assert(type(currentThreat) == "number" and type(maxThreat) == "number", "Usage: GetThreatStatus(currentThreat, maxThreat)")
if not maxThreat or maxThreat == 0 then
maxThreat = 0
maxThreat = 1
end
local threatPercent = currentThreat / maxThreat * 100
if threatPercent >= 100 then
return 3, threatPercent
elseif threatPercent < 100 and threatPercent >= 80 then
return 2, threatPercent
elseif threatPercent < 80 and threatPercent >= 50 then
return 1, threatPercent
else
return 0, threatPercent
end
end end
-142
View File
@@ -1,142 +0,0 @@
--Cache global variables
local assert = assert
local error = error
local geterrorhandler = geterrorhandler
local pairs = pairs
local pcall = pcall
local tostring = tostring
local type = type
local unpack = unpack
local ceil, floor = math.ceil, math.floor
local format, gsub = string.format, string.gsub
local getn, insert = table.getn, table.insert
function select(n, ...)
assert(type(n) == "number" or type(n) == "string", "bad argument #1 to 'select' (number expected, got no value)")
if type(n) == "string" and n == "#" then
if type(arg) == "table" then
return getn(arg)
else
return 1
end
end
local temp = {}
for i = n, getn(arg) do
insert(temp, arg[i])
end
return unpack(temp)
end
function math.modf(i)
assert(type(i) == "number", "bad argument #1 to 'modf' (number expected, got no value)")
local int = i >= 0 and floor(i) or ceil(i)
return int, i - int
end
function string.join(delimiter, ...)
-- assert(type(delimiter) == "number", "bad argument #1 to 'join' (string expected, got no value)")
local size = getn(arg)
if size == 0 then
return ""
end
local text = arg[1]
for i = 2, size do
text = text..delimiter..arg[i]
end
return text
end
strjoin = string.join
function string.split(delimiter, subject)
assert(type(delimiter) == "string", "bad argument #1 to 'split' (string expected, got no value)")
local delimiter, fields = delimiter or ":", {}
local pattern = format("([^%s]+)", delimiter)
gsub(subject, pattern, function(c) fields[getn(fields) + 1] = c end)
return unpack(fields)
end
strsplit = string.split
function table.wipe(t)
assert(type(t) == "table", "bad argument #1 to 'wipe' (table expected, got no value)")
for k in pairs(t) do
t[k] = nil
end
return t
end
wipe = table.wipe
local LOCAL_ToStringAllTemp = {}
function tostringall(...)
local n = getn(arg)
-- Simple versions for common argument counts
if (n == 1) then
return tostring(arg[1])
elseif (n == 2) then
return tostring(arg[1]), tostring(arg[2])
elseif (n == 3) then
return tostring(arg[1]), tostring(arg[2]), tostring(arg[3])
elseif (n == 0) then
return
end
local needfix
for i = 1, n do
local v = arg[i]
if (type(v) ~= "string") then
needfix = i
break
end
end
if (not needfix) then return unpack(arg) end
wipe(LOCAL_ToStringAllTemp)
for i = 1, needfix - 1 do
LOCAL_ToStringAllTemp[i] = arg[i]
end
for i = needfix, n do
LOCAL_ToStringAllTemp[i] = tostring(arg[i])
end
return unpack(LOCAL_ToStringAllTemp)
end
local LOCAL_PrintHandler = function(...)
DEFAULT_CHAT_FRAME:AddMessage(strjoin(" ", tostringall(unpack(arg))))
end
function setprinthandler(func)
if (type(func) ~= "function") then
error("Invalid print handler")
else
LOCAL_PrintHandler = func
end
end
function getprinthandler() return LOCAL_PrintHandler end
local function print_inner(...)
local ok, err = pcall(LOCAL_PrintHandler, unpack(arg))
if (not ok) then
local func = geterrorhandler()
func(err)
end
end
function print(...)
pcall(print_inner, unpack(arg))
end
SLASH_PRINT1 = "/print"
SlashCmdList["PRINT"] = print
@@ -1,10 +1,11 @@
--Cache global variables _G = getfenv()
-- Cache global variables
local strmatch = strmatch local strmatch = strmatch
--WoW API -- WoW API
local GetCVar = GetCVar local GetCVar = GetCVar
local IsAddOnLoaded = IsAddOnLoaded local IsAddOnLoaded = IsAddOnLoaded
local LoadAddOn = LoadAddOn local LoadAddOn = LoadAddOn
local UIParentLoadAddOn = UIParentLoadAddOn
local _ERROR_COUNT = 0 local _ERROR_COUNT = 0
local _ERROR_LIMIT = 1000 local _ERROR_LIMIT = 1000
@@ -15,7 +16,7 @@ function _ERRORMESSAGE_NEW(message)
LoadAddOn("!DebugTools") LoadAddOn("!DebugTools")
local loaded = IsAddOnLoaded("!DebugTools") local loaded = IsAddOnLoaded("!DebugTools")
-- if (GetCVar("scriptErrors") == 1) then if (GetCVar("ShowErrors") == "1") then
if (not loaded or DEBUG_DEBUGTOOLS) then if (not loaded or DEBUG_DEBUGTOOLS) then
ScriptErrors_Message:SetText(message) ScriptErrors_Message:SetText(message)
ScriptErrors:Show() ScriptErrors:Show()
@@ -25,9 +26,9 @@ function _ERRORMESSAGE_NEW(message)
else else
ScriptErrorsFrame_OnError(message) ScriptErrorsFrame_OnError(message)
end end
-- elseif (loaded) then elseif (loaded) then
-- ScriptErrorsFrame_OnError(message, true) ScriptErrorsFrame_OnError(message, true)
-- end end
_ERROR_COUNT = _ERROR_COUNT + 1 _ERROR_COUNT = _ERROR_COUNT + 1
if (_ERROR_COUNT == _ERROR_LIMIT) then if (_ERROR_COUNT == _ERROR_LIMIT) then
@@ -45,25 +46,3 @@ function message(text)
ScriptErrors:Show() ScriptErrors:Show()
end end
end end
SLASH_FRAMESTACK1 = "/framestack"
SLASH_FRAMESTACK2 = "/fstack"
SlashCmdList["FRAMESTACK"] = function(msg)
UIParentLoadAddOn("!DebugTools")
FrameStackTooltip_Toggle(showHidden)
end
SLASH_EVENTTRACE1 = "/eventtrace"
SLASH_EVENTTRACE2 = "/etrace"
SlashCmdList["EVENTTRACE"] = function(msg)
UIParentLoadAddOn("!DebugTools")
EventTraceFrame_HandleSlashCmd(msg)
end
SLASH_DUMP1 = "/dump"
SlashCmdList["DUMP"] = function(msg)
UIParentLoadAddOn("!DebugTools")
DevTools_DumpCommand(msg)
end
@@ -0,0 +1,292 @@
-- LibBabble-3.0 is hereby placed in the Public Domain
-- Credits: ckknight
local LIBBABBLE_MAJOR, LIBBABBLE_MINOR = "LibBabble-3.0", 2
local LibBabble = LibStub:NewLibrary(LIBBABBLE_MAJOR, LIBBABBLE_MINOR)
if not LibBabble then
return
end
local data = LibBabble.data or {}
for k,v in pairs(LibBabble) do
LibBabble[k] = nil
end
LibBabble.data = data
local tablesToDB = {}
for namespace, db in pairs(data) do
for k,v in pairs(db) do
tablesToDB[v] = db
end
end
local function warn(message)
local _, ret = pcall(error, message, 3)
geterrorhandler()(ret)
end
local lookup_mt = { __index = function(self, key)
local db = tablesToDB[self]
local current_key = db.current[key]
if current_key then
self[key] = current_key
return current_key
end
local base_key = db.base[key]
local real_MAJOR_VERSION
for k,v in pairs(data) do
if v == db then
real_MAJOR_VERSION = k
break
end
end
if not real_MAJOR_VERSION then
real_MAJOR_VERSION = LIBBABBLE_MAJOR
end
if base_key then
warn(string.format("%s: Translation %q not found for locale %q", real_MAJOR_VERSION, key, GetLocale()))
rawset(self, key, base_key)
return base_key
end
warn(string.format("%s: Translation %q not found.", real_MAJOR_VERSION, key))
rawset(self, key, key)
return key
end }
local function initLookup(module, lookup)
local db = tablesToDB[module]
for k in pairs(lookup) do
lookup[k] = nil
end
setmetatable(lookup, lookup_mt)
tablesToDB[lookup] = db
db.lookup = lookup
return lookup
end
local function initReverse(module, reverse)
local db = tablesToDB[module]
for k in pairs(reverse) do
reverse[k] = nil
end
for k,v in pairs(db.current) do
reverse[v] = k
end
tablesToDB[reverse] = db
db.reverse = reverse
db.reverseIterators = nil
return reverse
end
local prototype = {}
local prototype_mt = {__index = prototype}
--[[---------------------------------------------------------------------------
Notes:
* If you try to access a nonexistent key, it will warn but allow the code to pass through.
Returns:
A lookup table for english to localized words.
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
local BL = B:GetLookupTable()
assert(BL["Some english word"] == "Some localized word")
DoSomething(BL["Some english word that doesn't exist"]) -- warning!
-----------------------------------------------------------------------------]]
function prototype:GetLookupTable()
local db = tablesToDB[self]
local lookup = db.lookup
if lookup then
return lookup
end
return initLookup(self, {})
end
--[[---------------------------------------------------------------------------
Notes:
* If you try to access a nonexistent key, it will return nil.
Returns:
A lookup table for english to localized words.
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
local B_has = B:GetUnstrictLookupTable()
assert(B_has["Some english word"] == "Some localized word")
assert(B_has["Some english word that doesn't exist"] == nil)
-----------------------------------------------------------------------------]]
function prototype:GetUnstrictLookupTable()
local db = tablesToDB[self]
return db.current
end
--[[---------------------------------------------------------------------------
Notes:
* If you try to access a nonexistent key, it will return nil.
* This is useful for checking if the base (English) table has a key, even if the localized one does not have it registered.
Returns:
A lookup table for english to localized words.
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
local B_hasBase = B:GetBaseLookupTable()
assert(B_hasBase["Some english word"] == "Some english word")
assert(B_hasBase["Some english word that doesn't exist"] == nil)
-----------------------------------------------------------------------------]]
function prototype:GetBaseLookupTable()
local db = tablesToDB[self]
return db.base
end
--[[---------------------------------------------------------------------------
Notes:
* If you try to access a nonexistent key, it will return nil.
* This will return only one English word that it maps to, if there are more than one to check, see :GetReverseIterator("word")
Returns:
A lookup table for localized to english words.
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
local BR = B:GetReverseLookupTable()
assert(BR["Some localized word"] == "Some english word")
assert(BR["Some localized word that doesn't exist"] == nil)
-----------------------------------------------------------------------------]]
function prototype:GetReverseLookupTable()
local db = tablesToDB[self]
local reverse = db.reverse
if reverse then
return reverse
end
return initReverse(self, {})
end
local blank = {}
local weakVal = {__mode="v"}
--[[---------------------------------------------------------------------------
Arguments:
string - the localized word to chek for.
Returns:
An iterator to traverse all English words that map to the given key
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
for word in B:GetReverseIterator("Some localized word") do
DoSomething(word)
end
-----------------------------------------------------------------------------]]
function prototype:GetReverseIterator(key)
local db = tablesToDB[self]
local reverseIterators = db.reverseIterators
if not reverseIterators then
reverseIterators = setmetatable({}, weakVal)
db.reverseIterators = reverseIterators
elseif reverseIterators[key] then
return pairs(reverseIterators[key])
end
local t
for k,v in pairs(db.current) do
if v == key then
if not t then
t = {}
end
t[k] = true
end
end
reverseIterators[key] = t or blank
return pairs(reverseIterators[key])
end
--[[---------------------------------------------------------------------------
Returns:
An iterator to traverse all translations English to localized.
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
for english, localized in B:Iterate() do
DoSomething(english, localized)
end
-----------------------------------------------------------------------------]]
function prototype:Iterate()
local db = tablesToDB[self]
return pairs(db.current)
end
-- #NODOC
-- modules need to call this to set the base table
function prototype:SetBaseTranslations(base)
local db = tablesToDB[self]
local oldBase = db.base
if oldBase then
for k in pairs(oldBase) do
oldBase[k] = nil
end
for k, v in pairs(base) do
oldBase[k] = v
end
base = oldBase
else
db.base = base
end
for k,v in pairs(base) do
if v == true then
base[k] = k
end
end
end
local function init(module)
local db = tablesToDB[module]
if db.lookup then
initLookup(module, db.lookup)
end
if db.reverse then
initReverse(module, db.reverse)
end
db.reverseIterators = nil
end
-- #NODOC
-- modules need to call this to set the current table. if current is true, use the base table.
function prototype:SetCurrentTranslations(current)
local db = tablesToDB[self]
if current == true then
db.current = db.base
else
local oldCurrent = db.current
if oldCurrent then
for k in pairs(oldCurrent) do
oldCurrent[k] = nil
end
for k, v in pairs(current) do
oldCurrent[k] = v
end
current = oldCurrent
else
db.current = current
end
end
init(self)
end
for namespace, db in pairs(data) do
setmetatable(db.module, prototype_mt)
init(db.module)
end
-- #NODOC
-- modules need to call this to create a new namespace.
function LibBabble:New(namespace, minor)
local module, oldminor = LibStub:NewLibrary(namespace, minor)
if not module then
return
end
if not oldminor then
local db = {
module = module,
}
data[namespace] = db
tablesToDB[module] = db
else
for k,v in pairs(module) do
module[k] = nil
end
end
setmetatable(module, prototype_mt)
return module
end
@@ -0,0 +1,221 @@
--[[
Name: LibBabble-Class-3.0
Revision: $Rev: 50 $
Author(s): ckknight (ckknight@gmail.com)
Website: http://ckknight.wowinterface.com/
Dependencies: None
License: MIT
]]
local MAJOR_VERSION = "LibBabble-Class-3.0"
local MINOR_VERSION = 90000 + tonumber(string.match("$Revision: 50 $", "%d+"))
if not LibStub then error(MAJOR_VERSION .. " requires LibStub.") end
local lib = LibStub("LibBabble-3.0"):New(MAJOR_VERSION, MINOR_VERSION)
if not lib then return end
local GAME_LOCALE = GetLocale()
lib:SetBaseTranslations {
Warlock = true,
Warrior = true,
Hunter = true,
Mage = true,
Priest = true,
Druid = true,
Paladin = true,
Shaman = true,
Rogue = true,
WARLOCK = true,
WARRIOR = true,
HUNTER = true,
MAGE = true,
PRIEST = true,
DRUID = true,
PALADIN = true,
SHAMAN = true,
ROGUE = true,
}
if GAME_LOCALE == "enUS" then
lib:SetCurrentTranslations(true)
elseif GAME_LOCALE == "deDE" then
lib:SetCurrentTranslations {
["Warlock"] = "Hexenmeister",
["Warrior"] = "Krieger",
["Hunter"] = "Jäger",
["Mage"] = "Magier",
["Priest"] = "Priester",
["Druid"] = "Druide",
["Paladin"] = "Paladin",
["Shaman"] = "Schamane",
["Rogue"] = "Schurke",
["WARLOCK"] = "Hexenmeisterin",
["WARRIOR"] = "Kriegerin",
["HUNTER"] = "Jägerin",
["MAGE"] = "Magierin",
["PRIEST"] = "Priesterin",
["DRUID"] = "Druidin",
["PALADIN"] = "Paladin",
["SHAMAN"] = "Schamanin",
["ROGUE"] = "Schurkin",
}
elseif GAME_LOCALE == "frFR" then
lib:SetCurrentTranslations {
["Warlock"] = "Démoniste",
["Warrior"] = "Guerrier",
["Hunter"] = "Chasseur",
["Mage"] = "Mage",
["Priest"] = "Prêtre",
["Druid"] = "Druide",
["Paladin"] = "Paladin",
["Shaman"] = "Chaman",
["Rogue"] = "Voleur",
["WARLOCK"] = "Démoniste",
["WARRIOR"] = "Guerrière",
["HUNTER"] = "Chasseresse",
["MAGE"] = "Mage",
["PRIEST"] = "Prêtresse",
["DRUID"] = "Druidesse",
["PALADIN"] = "Paladin",
["SHAMAN"] = "Chamane",
["ROGUE"] = "Voleuse",
}
elseif GAME_LOCALE == "zhCN" then
lib:SetCurrentTranslations {
["Warlock"] = "术士",
["Warrior"] = "战士",
["Hunter"] = "猎人",
["Mage"] = "法师",
["Priest"] = "牧师",
["Druid"] = "德鲁伊",
["Paladin"] = "圣骑士",
["Shaman"] = "萨满祭司",
["Rogue"] = "潜行者",
["WARLOCK"] = "术士",
["WARRIOR"] = "战士",
["HUNTER"] = "猎人",
["MAGE"] = "法师",
["PRIEST"] = "牧师",
["DRUID"] = "德鲁伊",
["PALADIN"] = "圣骑士",
["SHAMAN"] = "萨满祭司",
["ROGUE"] = "潜行者",
}
elseif GAME_LOCALE == "zhTW" then
lib:SetCurrentTranslations {
["Warlock"] = "術士",
["Warrior"] = "戰士",
["Hunter"] = "獵人",
["Mage"] = "法師",
["Priest"] = "牧師",
["Druid"] = "德魯伊",
["Paladin"] = "聖騎士",
["Shaman"] = "薩滿",
["Rogue"] = "盜賊",
["WARLOCK"] = "術士",
["WARRIOR"] = "戰士",
["HUNTER"] = "獵人",
["MAGE"] = "法師",
["PRIEST"] = "牧師",
["DRUID"] = "德魯伊",
["PALADIN"] = "聖騎士",
["SHAMAN"] = "薩滿",
["ROGUE"] = "盜賊",
}
elseif GAME_LOCALE == "koKR" then
lib:SetCurrentTranslations {
["Warlock"] = "흑마법사",
["Warrior"] = "전사",
["Hunter"] = "사냥꾼",
["Mage"] = "마법사",
["Priest"] = "사제",
["Druid"] = "드루이드",
["Paladin"] = "성기사",
["Shaman"] = "주술사",
["Rogue"] = "도적",
["WARLOCK"] = "흑마법사",
["WARRIOR"] = "전사",
["HUNTER"] = "사냥꾼",
["MAGE"] = "마법사",
["PRIEST"] = "사제",
["DRUID"] = "드루이드",
["PALADIN"] = "성기사",
["SHAMAN"] = "주술사",
["ROGUE"] = "도적",
}
elseif GAME_LOCALE == "esES" then
lib:SetCurrentTranslations {
["Warlock"] = "Brujo",
["Warrior"] = "Guerrero",
["Hunter"] = "Cazador",
["Mage"] = "Mago",
["Priest"] = "Sacerdote",
["Druid"] = "Druida",
["Paladin"] = "Paladín",
["Shaman"] = "Chamán",
["Rogue"] = "Pícaro",
["WARLOCK"] = "Bruja",
["WARRIOR"] = "Guerrera",
["HUNTER"] = "Cazadora",
["MAGE"] = "Maga",
["PRIEST"] = "Sacerdotisa",
["DRUID"] = "Druida",
["PALADIN"] = "Paladín",
["SHAMAN"] = "Chamán",
["ROGUE"] = "Pícara",
}
elseif GAME_LOCALE == "esMX" then
lib:SetCurrentTranslations {
["Warlock"] = "Brujo",
["Warrior"] = "Guerrero",
["Hunter"] = "Cazador",
["Mage"] = "Mago",
["Priest"] = "Sacerdote",
["Druid"] = "Druida",
["Paladin"] = "Paladín",
["Shaman"] = "Chamán",
["Rogue"] = "Pícaro",
["WARLOCK"] = "Bruja",
["WARRIOR"] = "Guerrera",
["HUNTER"] = "Cazadora",
["MAGE"] = "Maga",
["PRIEST"] = "Sacerdotisa",
["DRUID"] = "Druida",
["PALADIN"] = "Paladín",
["SHAMAN"] = "Chamán",
["ROGUE"] = "Pícara",
}
elseif GAME_LOCALE == "ruRU" then
lib:SetCurrentTranslations {
["Warlock"] = "Чернокнижник",
["Warrior"] = "Воин",
["Hunter"] = "Охотник",
["Mage"] = "Маг",
["Priest"] = "Жрец",
["Druid"] = "Друид",
["Paladin"] = "Паладин",
["Shaman"] = "Шаман",
["Rogue"] = "Разбойник",
["WARLOCK"] = "Чернокнижница",
["WARRIOR"] = "Воин",
["HUNTER"] = "Охотница",
["MAGE"] = "Маг",
["PRIEST"] = "Жрица",
["DRUID"] = "Друид",
["PALADIN"] = "Паладин",
["SHAMAN"] = "Шаманка",
["ROGUE"] = "Разбойница",
}
else
error(string.format("%s: Locale %q not supported", MAJOR_VERSION, GAME_LOCALE))
end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,51 @@
-- $Id: LibStub.lua 103 2014-10-16 03:02:50Z mikk $
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/addons/libstub/ for more info
-- LibStub is hereby placed in the Public Domain
-- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
local LibStub = _G[LIBSTUB_MAJOR]
-- Check to see is this version of the stub is obsolete
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
LibStub = LibStub or {libs = {}, minors = {} }
_G[LIBSTUB_MAJOR] = LibStub
LibStub.minor = LIBSTUB_MINOR
-- LibStub:NewLibrary(major, minor)
-- major (string) - the major version of the library
-- minor (string or number ) - the minor version of the library
--
-- returns nil if a newer or same version of the lib is already present
-- returns empty library object or old library object if upgrade is needed
function LibStub:NewLibrary(major, minor)
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
local oldminor = self.minors[major]
if oldminor and oldminor >= minor then return nil end
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
return self.libs[major], oldminor
end
-- LibStub:GetLibrary(major, [silent])
-- major (string) - the major version of the library
-- silent (boolean) - if true, library is optional, silently return nil if its not found
--
-- throws an error if the library can not be found (except silent is set)
-- returns the library object if found
function LibStub:GetLibrary(major, silent)
if not self.libs[major] and not silent then
error(string.format("Cannot find a library instance of %q.", tostring(major)), 2)
end
return self.libs[major], self.minors[major]
end
-- LibStub:IterateLibraries()
--
-- Returns an iterator for the currently registered libraries
function LibStub:IterateLibraries()
return pairs(self.libs)
end
setmetatable(LibStub, { __call = LibStub.GetLibrary })
end
+6
View File
@@ -0,0 +1,6 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="LibStub.lua"/>
<Script file="LibBabble-3.0.lua"/>
<Script file="LibBabble-Class-3.0.lua"/>
<Script file="LibBabble-Zone-3.0.lua"/>
</Ui>
@@ -0,0 +1,51 @@
-- Cache global variables
local strmatch = strmatch
local checked
local function LoadDebugTools()
if checked then return end
local _, _, _, lod, _, reason = GetAddOnInfo("!DebugTools")
checked = true
if reason == "MISSING" then return end
if lod then
LoadAddOn("!DebugTools")
else
EnableAddOn("!DebugTools")
LoadAddOn("!DebugTools")
DisableAddOn("!DebugTools")
end
end
SLASH_FRAMESTACK1 = "/framestack"
SLASH_FRAMESTACK2 = "/fstack"
SlashCmdList["FRAMESTACK"] = function(msg)
LoadDebugTools()
if IsAddOnLoaded("!DebugTools") then
local showHiddenArg, showRegionsArg = strmatch(msg, "^%s*(%S+)%s+(%S+)%s*$")
if (not showHiddenArg or not showRegionsArg) then
showHiddenArg = strmatch(msg, "^%s*(%S+)%s*$")
showRegionsArg = "1"
end
local showHidden = showHiddenArg == "true" or showHiddenArg == "1"
local showRegions = showRegions == "true" or showRegionsArg == "1"
FrameStackTooltip_Toggle(showHidden, showRegions)
end
end
SLASH_EVENTTRACE1 = "/eventtrace"
SLASH_EVENTTRACE2 = "/etrace"
SlashCmdList["EVENTTRACE"] = function(msg)
LoadDebugTools()
EventTraceFrame_HandleSlashCmd(msg)
end
SLASH_DUMP1 = "/dump"
SlashCmdList["DUMP"] = function(msg)
LoadDebugTools()
DevTools_DumpCommand(msg)
end
+2 -1
View File
@@ -1,10 +1,11 @@
## Interface: 20400 ## Interface: 11200
## Title: !DebugTools ## Title: !DebugTools
## Notes: Tools for developing addons (Blizzard UI Debug Tools) ## Notes: Tools for developing addons (Blizzard UI Debug Tools)
## Author: Blizzard Entertainment ## Author: Blizzard Entertainment
## Special Thanks: Iriel, Kirov, Esamynn ## Special Thanks: Iriel, Kirov, Esamynn
## Version: 1.0 ## Version: 1.0
## Dependencies: !Compatibility ## Dependencies: !Compatibility
## LoadOnDemand: 1
Compatibility.lua Compatibility.lua
Dump.lua Dump.lua
+20 -14
View File
@@ -1,4 +1,5 @@
local _G = getfenv() local mod = math.mod
local getn = table.getn
EVENT_TRACE_EVENT_HEIGHT = 16; EVENT_TRACE_EVENT_HEIGHT = 16;
EVENT_TRACE_MAX_ENTRIES = 1000; EVENT_TRACE_MAX_ENTRIES = 1000;
@@ -44,7 +45,7 @@ function EventTraceFrame_OnLoad(self)
self.lastIndex = 0; self.lastIndex = 0;
self.visibleButtons = 0; self.visibleButtons = 0;
_EventTraceFrame = self; _EventTraceFrame = self;
self:SetScript("OnSizeChanged", function() EventTraceFrame_OnSizeChanged(this, arg1, arg2) end); self:SetScript("OnSizeChanged", function() EventTraceFrame_OnSizeChanged(this, this:GetWidth(), this:GetHeight()) end);
EventTraceFrame_OnSizeChanged(self, self:GetWidth(), self:GetHeight()); EventTraceFrame_OnSizeChanged(self, self:GetWidth(), self:GetHeight());
self:EnableMouse(true); self:EnableMouse(true);
self:EnableMouseWheel(true); self:EnableMouseWheel(true);
@@ -99,18 +100,18 @@ function EventTraceFrame_OnEvent (self, event, ...)
local hours = math.floor(minutes / 60); local hours = math.floor(minutes / 60);
seconds = seconds - 60 * minutes; seconds = seconds - 60 * minutes;
minutes = minutes - 60 * hours; minutes = minutes - 60 * hours;
hours = math.mod(hours, 1000); hours = mod(hours, 1000)
self.times[nextIndex] = string.format("%.2d:%.2d:%06.3f", hours, minutes, seconds); self.times[nextIndex] = string.format("%.2d:%.2d:%06.3f", hours, minutes, seconds);
self.timeSinceLast[nextIndex] = 0; self.timeSinceLast[nextIndex] = 0;
self.framesSinceLast[nextIndex] = 0; self.framesSinceLast[nextIndex] = 0;
self.eventids[nextIndex] = GetCurrentEventID(); self.eventids[nextIndex] = GetCurrentEventID();
local numArgs = select("#", unpack(arg)); local numArgs = select("#", arg);
for i=1, numArgs do for i=1, numArgs do
if (not self.args[i]) then if (not self.args[i]) then
self.args[i] = {}; self.args[i] = {};
end end
self.args[i][nextIndex] = select(i, unpack(arg)); self.args[i][nextIndex] = select(i, arg);
end end
if (self.eventsToCapture) then if (self.eventsToCapture) then
@@ -127,8 +128,8 @@ function EventTraceFrame_OnEvent (self, event, ...)
end end
end end
function EventTraceFrame_OnShow() function EventTraceFrame_OnShow(self)
wipe(this.ignoredEvents); wipe(self.ignoredEvents);
local scrollBar = _G["EventTraceFrameScroll"]; local scrollBar = _G["EventTraceFrameScroll"];
local minValue, maxValue = scrollBar:GetMinMaxValues(); local minValue, maxValue = scrollBar:GetMinMaxValues();
scrollBar:SetValue(maxValue); scrollBar:SetValue(maxValue);
@@ -140,7 +141,7 @@ end
function EventTraceFrame_OnSizeChanged (self, width, height) function EventTraceFrame_OnSizeChanged (self, width, height)
local numButtonsToDisplay = math.floor((height - 36)/EVENT_TRACE_EVENT_HEIGHT); local numButtonsToDisplay = math.floor((height - 36)/EVENT_TRACE_EVENT_HEIGHT);
local numButtonsCreated = getn(self.buttons) local numButtonsCreated = getn(self.buttons);
if (numButtonsCreated < numButtonsToDisplay) then if (numButtonsCreated < numButtonsToDisplay) then
for i = numButtonsCreated + 1, numButtonsToDisplay do for i = numButtonsCreated + 1, numButtonsToDisplay do
@@ -162,7 +163,7 @@ function EventTraceFrame_OnSizeChanged (self, width, height)
EventTraceFrame_Update(); EventTraceFrame_Update();
elseif (numButtonsToDisplay < self.visibleButtons) then elseif (numButtonsToDisplay < self.visibleButtons) then
for i = numButtonsToDisplay + 1, self.visibleButtons do for i = numButtonsToDisplay + 1, self.visibleButtons do
-- self.buttons[i]:Hide(); self.buttons[i]:Hide();
end end
self.visibleButtons = numButtonsToDisplay; self.visibleButtons = numButtonsToDisplay;
end end
@@ -493,9 +494,14 @@ function EventTraceFrameEventHideButton_OnClick (button)
EventTraceFrame_Update(); EventTraceFrame_Update();
end end
local ERROR_FORMAT = "|cffffd200Message:|r|cffffffff %s|r\n|cffffd200Time:|r|cffffffff %s|r\n|cffffd200Count:|r|cffffffff %s|r\n|cffffd200Stack:|r|cffffffff %s|r"; local ERROR_FORMAT = [[|cffffd200Message:|r|cffffffff %s|r
|cffffd200Time:|r|cffffffff %s|r
|cffffd200Count:|r|cffffffff %s|r
|cffffd200Stack:|r|cffffffff %s|r]];
local WARNING_AS_ERROR_FORMAT = "|cffffd200Message:|r|cffffffff %s|r\n|cffffd200Time:|r|cffffffff %s|r\n|cffffd200Count:|r|cffffffff %s|r"; local WARNING_AS_ERROR_FORMAT = [[|cffffd200Message:|r|cffffffff %s|r
|cffffd200Time:|r|cffffffff %s|r
|cffffd200Count:|r|cffffffff %s|r]];
local WARNING_FORMAT = "Lua Warning:\n"..WARNING_AS_ERROR_FORMAT; local WARNING_FORMAT = "Lua Warning:\n"..WARNING_AS_ERROR_FORMAT;
@@ -522,7 +528,7 @@ function ScriptErrorsFrame_OnLoad (self)
_ScriptErrorsFrame = self; _ScriptErrorsFrame = self;
end end
function ScriptErrorsFrame_OnShow (self) function ScriptErrorsFrame_OnShow ()
ScriptErrorsFrame_Update(); ScriptErrorsFrame_Update();
end end
@@ -583,7 +589,7 @@ function ScriptErrorsFrame_Update ()
if (prevText ~= text) then if (prevText ~= text) then
editBox:SetText(text); editBox:SetText(text);
editBox:HighlightText(0); editBox:HighlightText(0);
--editBox:SetCursorPosition(0); -- editBox:SetCursorPosition(0);
else else
ScriptErrorsFrameScrollFrame:UpdateScrollChildRect(); ScriptErrorsFrameScrollFrame:UpdateScrollChildRect();
end end
@@ -663,7 +669,7 @@ function FrameStackTooltip_OnLoad(self)
self:RegisterEvent("DISPLAY_SIZE_CHANGED") self:RegisterEvent("DISPLAY_SIZE_CHANGED")
end end
function FrameStackTooltip_OnEvent(self, event, ...) function FrameStackTooltip_OnEvent(self, event)
if (event == "DISPLAY_SIZE_CHANGED") then if (event == "DISPLAY_SIZE_CHANGED") then
FrameStackTooltip_OnDisplaySizeChanged(self) FrameStackTooltip_OnDisplaySizeChanged(self)
end end
+10 -10
View File
@@ -57,9 +57,9 @@
<Scripts> <Scripts>
<OnLoad> <OnLoad>
local frameName = this:GetName(); local frameName = this:GetName();
this.time = getglobal(frameName.."Time"); this.time = _G[frameName.."Time"];
this.event = getglobal(frameName.."Event"); this.event = _G[frameName.."Event"];
this.HideButton = getglobal(frameName.."HideButton"); this.HideButton = _G[frameName.."HideButton"];
this:GetHighlightTexture():SetAlpha(.15); this:GetHighlightTexture():SetAlpha(.15);
</OnLoad> </OnLoad>
<OnEnter> <OnEnter>
@@ -326,12 +326,12 @@
this:RegisterForDrag("LeftButton"); this:RegisterForDrag("LeftButton");
</OnLoad> </OnLoad>
<OnDragStart> <OnDragStart>
local eventTraceFrame = getglobal("EventTraceFrame"); local eventTraceFrame = _G["EventTraceFrame"];
eventTraceFrame.moving = true; eventTraceFrame.moving = true;
eventTraceFrame:StartMoving(); eventTraceFrame:StartMoving();
</OnDragStart> </OnDragStart>
<OnDragStop> <OnDragStop>
local eventTraceFrame = getglobal("EventTraceFrame"); local eventTraceFrame = _G["EventTraceFrame"];
eventTraceFrame.moving = nil; eventTraceFrame.moving = nil;
eventTraceFrame:StopMovingOrSizing(); eventTraceFrame:StopMovingOrSizing();
</OnDragStop> </OnDragStop>
@@ -356,7 +356,7 @@
</Layers> </Layers>
<Scripts> <Scripts>
<OnLoad> <OnLoad>
this:SetFrameLevel(this:GetFrameLevel() + 1); this:SetFrameLevel(self:GetFrameLevel() + 1);
this:SetValue(0); this:SetValue(0);
this:SetValueStep(1); this:SetValueStep(1);
</OnLoad> </OnLoad>
@@ -375,7 +375,7 @@
EventTraceFrame_OnShow(this); EventTraceFrame_OnShow(this);
</OnShow> </OnShow>
<OnEvent> <OnEvent>
EventTraceFrame_OnEvent(this, unpack(arg)); EventTraceFrame_OnEvent(this, event, arg);
</OnEvent> </OnEvent>
<OnUpdate> <OnUpdate>
EventTraceFrame_OnUpdate(this, arg1); EventTraceFrame_OnUpdate(this, arg1);
@@ -414,12 +414,12 @@
this:RegisterForDrag("LeftButton"); this:RegisterForDrag("LeftButton");
</OnLoad> </OnLoad>
<OnDragStart> <OnDragStart>
local frame = getglobal("ScriptErrorsFrame"); local frame = _G["ScriptErrorsFrame"];
frame.moving = true; frame.moving = true;
frame:StartMoving(); frame:StartMoving();
</OnDragStart> </OnDragStart>
<OnDragStop> <OnDragStop>
local frame = getglobal("ScriptErrorsFrame"); local frame = _G["ScriptErrorsFrame"];
frame.moving = nil; frame.moving = nil;
frame:StopMovingOrSizing(); frame:StopMovingOrSizing();
</OnDragStop> </OnDragStop>
@@ -543,7 +543,7 @@
FrameStackTooltip_OnUpdate(this, arg1); FrameStackTooltip_OnUpdate(this, arg1);
</OnUpdate> </OnUpdate>
<OnEvent> <OnEvent>
FrameStackTooltip_OnEvent(this, unpack(arg)); FrameStackTooltip_OnEvent(this, arg);
</OnEvent> </OnEvent>
</Scripts> </Scripts>
</GameTooltip> </GameTooltip>
+12 -9
View File
@@ -1,11 +1,10 @@
--Cache global variables -- Cache global variables
local _G = getfenv()
local format, match = string.format, string.match
local tinsert, tsort, twipe = table.insert, table.sort, table.wipe
local mod = math.mod local mod = math.mod
local pairs = pairs local pairs = pairs
local tostring = tostring local tostring = tostring
--WoW API local format, match = string.format, string.match
local getn, tinsert, tsort, twipe = table.getn, table.insert, table.sort, table.wipe
-- WoW API
local GetTime = GetTime local GetTime = GetTime
DEBUG_FRAMESTACK = "Frame Stack" DEBUG_FRAMESTACK = "Frame Stack"
@@ -87,7 +86,11 @@ local function FrameStackSort(b, a)
return return
end end
return a < b if a and b then
return a < b
else
return
end
end end
function UpdateFrameStack(tooltip, showHidden) function UpdateFrameStack(tooltip, showHidden)
@@ -154,7 +157,7 @@ function UpdateFrameStack(tooltip, showHidden)
frameStackList[getn(frameStackList) + 1] = nil frameStackList[getn(frameStackList) + 1] = nil
--tsort(frameStackList, FrameStackSort) tsort(frameStackList, FrameStackSort)
tooltip:ClearLines() tooltip:ClearLines()
tooltip:AddDoubleLine(DEBUG_FRAMESTACK, format("(%.2f,%.2f)", x, y), 1, 1, 1, 1, .82, 0) tooltip:AddDoubleLine(DEBUG_FRAMESTACK, format("(%.2f,%.2f)", x, y), 1, 1, 1, 1, .82, 0)
@@ -174,12 +177,12 @@ function UpdateFrameStack(tooltip, showHidden)
end end
if l ~= ol then if l ~= ol then
cs = mod(cs, cn) + 1 or 0 cs = mod(cs, cn) + 1
ol = l ol = l
end end
if not highlighted then if not highlighted then
local frameName = _G[n] --[[or match(n, "%((.+)%)$")]] or n local frameName = _G[n] or match(n, "%((.+)%)$") or n
if frameName and frameName == highlightFrame then if frameName and frameName == highlightFrame then
tooltip:AddLine("-->" .. (a[cs] or "|cff444444") .. "<" .. l .. "> " .. n .. "|r") tooltip:AddLine("-->" .. (a[cs] or "|cff444444") .. "<" .. l .. "> " .. n .. "|r")
highlighted = true highlighted = true
@@ -35,6 +35,10 @@ local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceAddon then return end -- No Upgrade needed. if not AceAddon then return end -- No Upgrade needed.
local AceCore = LibStub("AceCore-3.0")
local new, del = AceCore.new, AceCore.del
local wipe, truncate = AceCore.wipe, AceCore.truncate
AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame
AceAddon.addons = AceAddon.addons or {} -- addons in general AceAddon.addons = AceAddon.addons or {} -- addons in general
AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon. AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon.
@@ -43,9 +47,9 @@ AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized
AceAddon.embeds = AceAddon.embeds or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end }) -- contains a list of libraries embedded in an addon AceAddon.embeds = AceAddon.embeds or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end }) -- contains a list of libraries embedded in an addon
-- Lua APIs -- Lua APIs
local getn, tinsert, tconcat, tremove = table.getn, table.insert, table.concat, table.remove local tinsert, tconcat, tremove, tgetn = table.insert, table.concat, table.remove, table.getn
local fmt, tostring = string.format, tostring local strfmt, tostring = string.format, tostring
local select, pairs, next, type, unpack = select, pairs, next, type, unpack local pairs, next, type, unpack = pairs, next, type, unpack
local loadstring, assert, error = loadstring, assert, error local loadstring, assert, error = loadstring, assert, error
local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
@@ -56,54 +60,7 @@ local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, r
--[[ --[[
xpcall safecall implementation xpcall safecall implementation
]] ]]
local xpcall = xpcall local safecall = AceCore.safecall
local function errorhandler(err)
return geterrorhandler()(err)
end
local function CreateDispatcher(argCount)
local code = [[
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = unpack(arg)
return xpcall(call, function(err) return geterrorhandler()(err) end)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do
ARGS[i] = "arg"..i
end
code = string.gsub(code, "ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
end
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
Dispatchers[0] = function(func)
return xpcall(func, errorhandler)
end
local function safecall(func, ...)
-- we check to see if the func is passed is actually a function here and don't error when it isn't
-- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
-- present execution should continue without hinderance
if type(func) == "function" then
--print(Dispatchers[getn(arg)](func, unpack(arg)))
return func(unpack(arg))
end
end
-- local functions that will be implemented further down -- local functions that will be implemented further down
local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype
@@ -113,7 +70,7 @@ local function addontostring( self ) return self.name end
-- Check if the addon is queued for initialization -- Check if the addon is queued for initialization
local function queuedForInitialization(addon) local function queuedForInitialization(addon)
for i = 1, getn(AceAddon.initializequeue) do for i = 1, tgetn(AceAddon.initializequeue) do
if AceAddon.initializequeue[i] == addon then if AceAddon.initializequeue[i] == addon then
return true return true
end end
@@ -136,24 +93,34 @@ end
-- -- Create a Addon object based on the table of a frame -- -- Create a Addon object based on the table of a frame
-- local MyFrame = CreateFrame("Frame") -- local MyFrame = CreateFrame("Frame")
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon(MyFrame, "MyAddon", "AceEvent-3.0") -- MyAddon = LibStub("AceAddon-3.0"):NewAddon(MyFrame, "MyAddon", "AceEvent-3.0")
function AceAddon:NewAddon(objectorname, ...) function AceAddon:NewAddon(objectorname,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
local object,name local object,name
local i=1
if type(objectorname)=="table" then if type(objectorname)=="table" then
object=objectorname object=objectorname
name=unpack(arg) name=a0
i=2
else else
name=objectorname name=objectorname
end end
if type(name)~="string" then if type(name)~="string" then
error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) error(strfmt("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'.", type(name)), 2)
end end
if self.addons[name] then if self.addons[name] then
error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2) error(strfmt("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists.", name), 2)
end end
local args = new()
args[1] = a1
args[2] = a2
args[3] = a3
args[4] = a4
args[5] = a5
args[6] = a6
args[7] = a7
args[8] = a8
args[9] = a9
args[10] = a10
object = object or {} object = object or {}
object.name = name object.name = name
@@ -170,14 +137,18 @@ function AceAddon:NewAddon(objectorname, ...)
object.orderedModules = {} object.orderedModules = {}
object.defaultModuleLibraries = {} object.defaultModuleLibraries = {}
Embed( object ) -- embed NewModule, GetModule methods Embed( object ) -- embed NewModule, GetModule methods
self:EmbedLibraries(object, unpack(arg)) if type(objectorname)=="table" then
self:EmbedLibraries(object,nil,args)
elseif a0 then
self:EmbedLibraries(object,a0,args)
end
del(args)
-- add to queue of addons to be initialized upon ADDON_LOADED -- add to queue of addons to be initialized upon ADDON_LOADED
tinsert(self.initializequeue, object) tinsert(self.initializequeue, object)
return object return object
end end
--- Get the addon object by its name from the internal AceAddon registry. --- Get the addon object by its name from the internal AceAddon registry.
-- Throws an error if the addon object cannot be found (except if silent is set). -- Throws an error if the addon object cannot be found (except if silent is set).
-- @param name unique name of the addon object -- @param name unique name of the addon object
@@ -187,7 +158,7 @@ end
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") -- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
function AceAddon:GetAddon(name, silent) function AceAddon:GetAddon(name, silent)
if not silent and not self.addons[name] then if not silent and not self.addons[name] then
error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2) error(strfmt("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'.", tostring(name)), 2)
end end
return self.addons[name] return self.addons[name]
end end
@@ -200,10 +171,12 @@ end
-- @paramsig addon, [lib, ...] -- @paramsig addon, [lib, ...]
-- @param addon addon object to embed the libs in -- @param addon addon object to embed the libs in
-- @param lib List of libraries to embed into the addon -- @param lib List of libraries to embed into the addon
function AceAddon:EmbedLibraries(addon, ...) function AceAddon:EmbedLibraries(addon,a1,arg)
for i=1, getn(arg) do if a1 then self:EmbedLibrary(addon, a1, false, 4) end
local libname = arg[i] -- 10 is the max number of variable arguments in the function NewAddon and NewModule
self:EmbedLibrary(addon, libname, false, 4) for i=1,10 do
if not arg[i] then return end
self:EmbedLibrary(addon, arg[i], false, 4)
end end
end end
@@ -221,13 +194,13 @@ end
function AceAddon:EmbedLibrary(addon, libname, silent, offset) function AceAddon:EmbedLibrary(addon, libname, silent, offset)
local lib = LibStub:GetLibrary(libname, true) local lib = LibStub:GetLibrary(libname, true)
if not lib and not silent then if not lib and not silent then
error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2) error(strfmt("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q.", tostring(libname)), offset or 2)
elseif lib and type(lib.Embed) == "function" then elseif lib and type(lib.Embed) == "function" then
lib:Embed(addon) lib:Embed(addon)
tinsert(self.embeds[addon], libname) tinsert(self.embeds[addon], libname)
return true return true
elseif lib then elseif lib then
error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2) error(strfmt("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable", libname), offset or 2)
end end
end end
@@ -244,7 +217,7 @@ end
-- MyModule = MyAddon:GetModule("MyModule") -- MyModule = MyAddon:GetModule("MyModule")
function GetModule(self, name, silent) function GetModule(self, name, silent)
if not self.modules[name] and not silent then if not self.modules[name] and not silent then
error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2) error(strfmt("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'.", tostring(name)), 2)
end end
return self.modules[name] return self.modules[name]
end end
@@ -267,26 +240,39 @@ local function IsModuleTrue(self) return true end
-- -- Create a module with a prototype -- -- Create a module with a prototype
-- local prototype = { OnEnable = function(self) print("OnEnable called!") end } -- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
-- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0") -- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0")
function NewModule(self, name, prototype, ...) function NewModule(self, name, prototype, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end if type(name) ~= "string" then error(strfmt("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'.", type(name)), 2) end
if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(strfmt("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'.", type(prototype)), 2) end
if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end if self.modules[name] then error(strfmt("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists.", name), 2) end
-- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well. -- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well.
-- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is. -- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is.
local module = AceAddon:NewAddon(fmt("%s_%s", self.name or tostring(self), name)) local module = AceAddon:NewAddon(strfmt("%s_%s", self.name or tostring(self), name))
module.IsModule = IsModuleTrue module.IsModule = IsModuleTrue
module:SetEnabledState(self.defaultModuleState) module:SetEnabledState(self.defaultModuleState)
module.moduleName = name module.moduleName = name
local args = new()
args[1] = a1
args[2] = a2
args[3] = a3
args[4] = a4
args[5] = a5
args[6] = a6
args[7] = a7
args[8] = a8
args[9] = a9
args[10] = a10
if type(prototype) == "string" then if type(prototype) == "string" then
AceAddon:EmbedLibraries(module, prototype, unpack(arg)) AceAddon:EmbedLibraries(module, prototype, args)
else else
AceAddon:EmbedLibraries(module, unpack(arg)) AceAddon:EmbedLibraries(module, nil, args)
end end
AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries)) del(args)
AceAddon:EmbedLibraries(module, nil, self.defaultModuleLibraries)
if not prototype or type(prototype) == "string" then if not prototype or type(prototype) == "string" then
prototype = self.defaultModulePrototype or nil prototype = self.defaultModulePrototype or nil
@@ -298,7 +284,7 @@ function NewModule(self, name, prototype, ...)
setmetatable(module, mt) -- More of a Base class type feel. setmetatable(module, mt) -- More of a Base class type feel.
end end
safecall(self.OnModuleCreated, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy. safecall(self.OnModuleCreated, 2, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy.
self.modules[name] = module self.modules[name] = module
tinsert(self.orderedModules, module) tinsert(self.orderedModules, module)
@@ -399,11 +385,25 @@ end
-- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0") -- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0")
-- -- Create a module -- -- Create a module
-- MyModule = MyAddon:NewModule("MyModule") -- MyModule = MyAddon:NewModule("MyModule")
function SetDefaultModuleLibraries(self, ...) function SetDefaultModuleLibraries(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
if next(self.modules) then if next(self.modules) then
error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2) error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2)
end end
self.defaultModuleLibraries = {unpack(arg)} local args = self.defaultModuleLibraries or {}
args[1] = a1
args[2] = a2
args[3] = a3
args[4] = a4
args[5] = a5
args[6] = a6
args[7] = a7
args[8] = a8
args[9] = a9
args[10] = a10
truncate(tmp,10)
self.defaultModuleLibraries = args
end end
--- Set the default state in which new modules are being created. --- Set the default state in which new modules are being created.
@@ -446,7 +446,7 @@ function SetDefaultModulePrototype(self, prototype)
error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2) error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2)
end end
if type(prototype) ~= "table" then if type(prototype) ~= "table" then
error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2) error(strfmt("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'.", type(prototype)), 2)
end end
self.defaultModulePrototype = prototype self.defaultModulePrototype = prototype
end end
@@ -530,12 +530,12 @@ end
-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing. -- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
-- @param addon addon object to intialize -- @param addon addon object to intialize
function AceAddon:InitializeAddon(addon) function AceAddon:InitializeAddon(addon)
safecall(addon.OnInitialize, addon) safecall(addon.OnInitialize, 1, addon)
local embeds = self.embeds[addon] local embeds = self.embeds[addon]
for i = 1, getn(embeds) do for i = 1, tgetn(embeds) do
local lib = LibStub:GetLibrary(embeds[i], true) local lib = LibStub:GetLibrary(embeds[i], true)
if lib then safecall(lib.OnEmbedInitialize, lib, addon) end if lib then safecall(lib.OnEmbedInitialize, 2, lib, addon) end
end end
-- we don't call InitializeAddon on modules specifically, this is handled -- we don't call InitializeAddon on modules specifically, this is handled
@@ -559,19 +559,19 @@ function AceAddon:EnableAddon(addon)
-- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable. -- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable.
self.statuses[addon.name] = true self.statuses[addon.name] = true
safecall(addon.OnEnable, addon) safecall(addon.OnEnable, 1, addon)
-- make sure we're still enabled before continueing -- make sure we're still enabled before continueing
if self.statuses[addon.name] then if self.statuses[addon.name] then
local embeds = self.embeds[addon] local embeds = self.embeds[addon]
for i = 1, getn(embeds) do for i = 1, tgetn(embeds) do
local lib = LibStub:GetLibrary(embeds[i], true) local lib = LibStub:GetLibrary(embeds[i], true)
if lib then safecall(lib.OnEmbedEnable, lib, addon) end if lib then safecall(lib.OnEmbedEnable, 2, lib, addon) end
end end
-- enable possible modules. -- enable possible modules.
local modules = addon.orderedModules local modules = addon.orderedModules
for i = 1, getn(modules) do for i = 1, tgetn(modules) do
self:EnableAddon(modules[i]) self:EnableAddon(modules[i])
end end
end end
@@ -594,18 +594,18 @@ function AceAddon:DisableAddon(addon)
-- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable. -- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable.
self.statuses[addon.name] = false self.statuses[addon.name] = false
safecall( addon.OnDisable, addon ) safecall(addon.OnDisable, 1, addon)
-- make sure we're still disabling... -- make sure we're still disabling...
if not self.statuses[addon.name] then if not self.statuses[addon.name] then
local embeds = self.embeds[addon] local embeds = self.embeds[addon]
for i = 1, getn(embeds) do for i = 1, tgetn(embeds) do
local lib = LibStub:GetLibrary(embeds[i], true) local lib = LibStub:GetLibrary(embeds[i], true)
if lib then safecall(lib.OnEmbedDisable, lib, addon) end if lib then safecall(lib.OnEmbedDisable, 2, lib, addon) end
end end
-- disable possible modules. -- disable possible modules.
local modules = addon.orderedModules local modules = addon.orderedModules
for i = 1, getn(modules) do for i = 1, tgetn(modules) do
self:DisableAddon(modules[i]) self:DisableAddon(modules[i])
end end
end end
@@ -636,13 +636,22 @@ function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
local IsLoggedIn
local onEvent
do
local IsLoggedIn = false
-- Event Handling -- Event Handling
local function onEvent() function onEvent()
-- 2011-08-17 nevcairiel - ignore the load event of Blizzard_DebugTools, so a potential startup error isn't swallowed up -- 2011-08-17 nevcairiel - ignore the load event of Blizzard_DebugTools, so a potential startup error isn't swallowed up
-- Ace3v: When the ADDON_LOADED event is triggerd, global arg1 is the loaded addon name
-- so onEvent(event, arg1) won't work because it will cover the global variables
if (event == "ADDON_LOADED" and arg1 ~= "Blizzard_DebugTools") or event == "PLAYER_LOGIN" then if (event == "ADDON_LOADED" and arg1 ~= "Blizzard_DebugTools") or event == "PLAYER_LOGIN" then
-- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration -- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration
while(getn(AceAddon.initializequeue) > 0) do -- Ace3v: When an Ace3 addons is loaded, then he initializeque should not be empty unless
-- the addon does not use the library. If an addon that does not use Ace3 library
-- is loaded, we will also receive the ADDON_LOADED event but in this case the
-- queue will be empty so we have nothing to do.
while(tgetn(AceAddon.initializequeue) > 0) do
local addon = tremove(AceAddon.initializequeue, 1) local addon = tremove(AceAddon.initializequeue, 1)
-- this might be an issue with recursion - TODO: validate -- this might be an issue with recursion - TODO: validate
if event == "ADDON_LOADED" then addon.baseName = arg1 end if event == "ADDON_LOADED" then addon.baseName = arg1 end
@@ -655,13 +664,14 @@ local function onEvent()
end end
if IsLoggedIn then if IsLoggedIn then
while(getn(AceAddon.enablequeue) > 0) do while(tgetn(AceAddon.enablequeue) > 0) do
local addon = tremove(AceAddon.enablequeue, 1) local addon = tremove(AceAddon.enablequeue, 1)
AceAddon:EnableAddon(addon) AceAddon:EnableAddon(addon)
end end
end end
end end
end end
end -- onEvent
AceAddon.frame:RegisterEvent("ADDON_LOADED") AceAddon.frame:RegisterEvent("ADDON_LOADED")
AceAddon.frame:RegisterEvent("PLAYER_LOGIN") AceAddon.frame:RegisterEvent("PLAYER_LOGIN")
@@ -16,87 +16,110 @@ local AceConsole, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConsole then return end -- No upgrade needed if not AceConsole then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0")
AceConsole.embeds = AceConsole.embeds or {} -- table containing objects AceConsole is embedded in. AceConsole.embeds = AceConsole.embeds or {} -- table containing objects AceConsole is embedded in.
AceConsole.commands = AceConsole.commands or {} -- table containing commands registered AceConsole.commands = AceConsole.commands or {} -- table containing commands registered
AceConsole.weakcommands = AceConsole.weakcommands or {} -- table containing self, command => func references for weak commands that don't persist through enable/disable AceConsole.weakcommands = AceConsole.weakcommands or {} -- table containing self, command => func references for weak commands that don't persist through enable/disable
-- Lua APIs -- Lua APIs
local tconcat, tostring, select = table.concat, tostring, select local tinsert, tconcat, tgetn, tsetn = table.insert, table.concat, table.getn, table.setn
local tostring = tostring
local type, pairs, error = type, pairs, error local type, pairs, error = type, pairs, error
local format, strfind, strsub = string.format, string.find, string.sub local format, strfind, strsub = string.format, string.find, string.sub
local max = math.max local max = math.max
local strupper, strlower = string.upper, string.lower
-- WoW APIs -- WoW APIs
local _G = getfenv() local _G = AceCore._G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
-- GLOBALS: DEFAULT_CHAT_FRAME, SlashCmdList, hash_SlashCmdList -- GLOBALS: DEFAULT_CHAT_FRAME, SlashCmdList, hash_SlashCmdList
local Print
local tmp={} do
local function Print(self,frame,...) local tmp = {}
local n=0 function Print(self, frame, arg)
if self ~= AceConsole then if self ~= AceConsole then
n=n+1 tmp[1] = "|cff33ff99"..tostring(self).."|r:"
tmp[n] = "|cff33ff99"..tostring( self ).."|r:" else
tmp[1] = ''
end end
for i=1, getn(arg) do if type(arg) == "string" then
n=n+1 frame:AddMessage(tmp[1]..arg)
tmp[n] = tostring(arg[i]) else -- arg is table and may contain frame as first element if argument frame is nil
local b, e = frame and 1 or 2, tgetn(arg)
if e >= b then
frame = frame or arg[1]
for i=0,e-b do
tmp[2+i] = tostring(arg[b+i])
end
frame:AddMessage(tconcat(tmp," ",1,e-b+2)) -- explicitly, because the length is not affected by assignment
end
end end
frame:AddMessage( tconcat(tmp," ",1,n) )
end end
end -- Print
--- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function) --- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
-- @paramsig [chatframe ,] ... -- @paramsig [chatframe ,] ...
-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function) -- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
-- @param ... List of any values to be printed -- @param ... List of any values to be printed
function AceConsole:Print(...) function AceConsole:Print(...)
local frame = arg local frame = arg[1]
if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member? if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
return Print(self, frame, arg[2]) return Print(self, nil, arg)
else else
return Print(self, DEFAULT_CHAT_FRAME, arg) return Print(self, DEFAULT_CHAT_FRAME, arg)
end end
end end
--- Formatted (using format()) print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function) --- Formatted (using format()) print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
-- @paramsig [chatframe ,] "format"[, ...] -- @paramsig [chatframe ,] "format"[, ...]
-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function) -- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
-- @param format Format string - same syntax as standard Lua format() -- @param format Format string - same syntax as standard Lua format()
-- @param ... Arguments to the format string -- @param ... Arguments to the format string
function AceConsole:Printf(...) function AceConsole:Printf(a1, ...)
local frame = arg local frame, succ, s
if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member? if type(a1) == "table" and a1.AddMessage then -- Is first argument something with an .AddMessage member?
return Print(self, frame, format(arg[2])) frame, succ, s = a1, pcall(format, unpack(arg))
else else
return Print(self, DEFAULT_CHAT_FRAME, format(arg)) frame, succ, s = DEFAULT_CHAT_FRAME, pcall(format, a1, unpack(arg))
end end
if not succ then error(s,2) end
return Print(self, frame, s)
end end
--- Register a simple chat command --- Register a simple chat command
-- @param command Chat command to be registered WITHOUT leading "/" -- @param command Chat command to be registered WITHOUT leading "/"
-- @param func Function to call when the slash command is being used (funcref or methodname) -- @param func Function to call when the slash command is being used (funcref or methodname)
-- @param persist if false, the command will be soft disabled/enabled when aceconsole is used as a mixin (default: true) -- @param persist if false, the command will be soft disabled/enabled when aceconsole is used as a mixin (default: true)
function AceConsole:RegisterChatCommand( command, func, persist ) function AceConsole:RegisterChatCommand( command, func, persist )
if type(command)~="string" then error([[Usage: AceConsole:RegisterChatCommand( "command", func[, persist ]): 'command' - expected a string]], 2) end if type(command)~="string" then error([[Usage: AceConsole:RegisterChatCommand(command, func[, persist ]): 'command' - expected a string]], 2) end
if persist==nil then persist=true end -- I'd rather have my addon's "/addon enable" around if the author screws up. Having some extra slash regged when it shouldnt be isn't as destructive. True is a better default. /Mikk if persist==nil then persist=true end -- I'd rather have my addon's "/addon enable" around if the author screws up. Having some extra slash regged when it shouldnt be isn't as destructive. True is a better default. /Mikk
local name = "ACECONSOLE_"..string.upper(command) local name = "ACECONSOLE_"..strupper(command)
if type( func ) == "string" then local t = type(func)
if t == "string" then
-- Ace3v: prevent user from using AceConSole as self
if self == AceConsole then
error([[Usage: RegisterChatCommand(command, func[, persist]): 'self' - use your own 'self']], 2)
end
SlashCmdList[name] = function(input, editBox) SlashCmdList[name] = function(input, editBox)
self[func](self, input, editBox) self[func](self, input, editBox)
end end
else elseif t == "function" then
SlashCmdList[name] = func SlashCmdList[name] = func
else
error([[Usage: AceConsole:RegisterChatCommand(command, func[, persist ]): 'func' - expected a string or a function]], 2)
end end
_G["SLASH_"..name.."1"] = "/"..string.lower(command) _G["SLASH_"..name.."1"] = "/"..strlower(command)
AceConsole.commands[command] = name AceConsole.commands[command] = name
-- non-persisting commands are registered for enabling disabling -- non-persisting commands are registered for enabling disabling
if not persist then if not persist then
@@ -113,7 +136,6 @@ function AceConsole:UnregisterChatCommand( command )
if name then if name then
SlashCmdList[name] = nil SlashCmdList[name] = nil
_G["SLASH_" .. name .. "1"] = nil _G["SLASH_" .. name .. "1"] = nil
hash_SlashCmdList["/" .. command:upper()] = nil
AceConsole.commands[command] = nil AceConsole.commands[command] = nil
end end
end end
@@ -122,18 +144,16 @@ end
-- @return Iterator (pairs) over all commands -- @return Iterator (pairs) over all commands
function AceConsole:IterateChatCommands() return pairs(AceConsole.commands) end function AceConsole:IterateChatCommands() return pairs(AceConsole.commands) end
local function nils(n,argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
local function nils(n, ...) if n >= 1 then
if n>1 then return nil, nils(n-1,argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
return nil, nils(n-1, arg) elseif not argc or argc == 0 then
elseif n==1 then return
return nil, arg
else else
return arg return a1, nils(0,argc-1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
end end
end end
--- Retreive one or more space-separated arguments from a string. --- Retreive one or more space-separated arguments from a string.
-- Treats quoted strings and itemlinks as non-spaced. -- Treats quoted strings and itemlinks as non-spaced.
-- @param str The raw argument string -- @param str The raw argument string
@@ -150,7 +170,7 @@ function AceConsole:GetArgs(str, numargs, startpos)
-- find start of new arg -- find start of new arg
pos = strfind(str, "[^ ]", pos) pos = strfind(str, "[^ ]", pos)
if not pos then -- whoops, end of string if not pos then -- whoops, end of string
return nils(numargs, 1e9) return nils(numargs, 1, 1e9)
end end
if numargs<1 then if numargs<1 then
@@ -205,7 +225,7 @@ function AceConsole:GetArgs(str, numargs, startpos)
end end
-- search aborted, we hit end of string. return it all as one argument. (yes, even if it's an unterminated quote or hyperlink) -- search aborted, we hit end of string. return it all as one argument. (yes, even if it's an unterminated quote or hyperlink)
return strsub(str, startpos), nils(numargs-1, 1e9) return strsub(str, startpos), nils(numargs-1, 1, 1e9)
end end
@@ -18,7 +18,7 @@ if not AceEvent then return end
-- Lua APIs -- Lua APIs
local pairs = pairs local pairs = pairs
local CallbackHandler = LibStub("CallbackHandler-1.0") local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame
AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib
@@ -1,12 +1,12 @@
--- **AceTimer-3.0** provides a central facility for registering timers. --- **AceTimer-3.0** provides a central facility for registering timers.
-- AceTimer supports one-shot timers and repeating timers. All timers are stored in an efficient -- AceTimer supports one-shot timers and repeating timers. All timers are stored in an efficient
-- data structure that allows easy dispatching and fast rescheduling. Timers can be registered, rescheduled -- data structure that allows easy dispatching and fast rescheduling. Timers can be registered
-- or canceled at any time, even from within a running timer, without conflict or large overhead.\\ -- or canceled at any time, even from within a running timer, without conflict or large overhead.\\
-- AceTimer is currently limited to firing timers at a frequency of 0.1s. This constant may change -- AceTimer is currently limited to firing timers at a frequency of 0.01s as this is what the WoW timer API
-- in the future, but for now it seemed like a good compromise in efficiency and accuracy. -- restricts us to.
-- --
-- All `:Schedule` functions will return a handle to the current timer, which you will need to store if you -- All `:Schedule` functions will return a handle to the current timer, which you will need to store if you
-- need to cancel or reschedule the timer you just registered. -- need to cancel the timer you just registered.
-- --
-- **AceTimer-3.0** can be embeded into your addon, either explicitly by calling AceTimer:Embed(MyAddon) or by -- **AceTimer-3.0** can be embeded into your addon, either explicitly by calling AceTimer:Embed(MyAddon) or by
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object -- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
@@ -15,54 +15,33 @@
-- make into AceTimer. -- make into AceTimer.
-- @class file -- @class file
-- @name AceTimer-3.0 -- @name AceTimer-3.0
-- @release $Id: AceTimer-3.0.lua 895 2009-12-06 16:28:55Z nevcairiel $ -- @release $Id: AceTimer-3.0.lua 1119 2014-10-14 17:23:29Z nevcairiel $
--[[ local MAJOR, MINOR = "AceTimer-3.0", 17 -- Bump minor on changes
Basic assumptions:
* In a typical system, we do more re-scheduling per second than there are timer pulses per second
* Regardless of timer implementation, we cannot guarantee timely delivery due to FPS restriction (may be as low as 10)
This implementation:
CON: The smallest timer interval is constrained by HZ (currently 1/10s).
PRO: It will still correctly fire any timer slower than HZ over a length of time, e.g. 0.11s interval -> 90 times over 10 seconds
PRO: In lag bursts, the system simly skips missed timer intervals to decrease load
CON: Algorithms depending on a timer firing "N times per minute" will fail
PRO: (Re-)scheduling is O(1) with a VERY small constant. It's a simple linked list insertion in a hash bucket.
CAUTION: The BUCKETS constant constrains how many timers can be efficiently handled. With too many hash collisions, performance will decrease.
Major assumptions upheld:
- ALLOWS scheduling multiple timers with the same funcref/method
- ALLOWS scheduling more timers during OnUpdate processing
- ALLOWS unscheduling ANY timer (including the current running one) at any time, including during OnUpdate processing
]]
local MAJOR, MINOR = "AceTimer-3.0", 6
local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR) local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceTimer then return end -- No upgrade needed if not AceTimer then return end -- No upgrade needed
AceTimer.hash = AceTimer.hash or {} -- Array of [0..BUCKET-1] = linked list of timers (using .next member) local AceCore = LibStub("AceCore-3.0")
-- Linked list gets around ACE-88 and ACE-90. local safecall = AceCore.safecall
AceTimer.selfs = AceTimer.selfs or {} -- Array of [self]={[handle]=timerobj, [handle2]=timerobj2, ...}
AceTimer.counter = AceTimer.counter or {}
AceTimer.hash = AceTimer.hash or {} -- Array of [1..BUCKETS] = linked list of timers (using .next member)
AceTimer.activeTimers = AceTimer.activeTimers or {} -- Active timer list
AceTimer.frame = AceTimer.frame or CreateFrame("Frame", "AceTimer30Frame") AceTimer.frame = AceTimer.frame or CreateFrame("Frame", "AceTimer30Frame")
local counter = AceTimer.counter
local activeTimers = AceTimer.activeTimers -- Upvalue our private data
local timerFrame = AceTimer.frame
-- Lua APIs -- Lua APIs
local assert, error, loadstring = assert, error, loadstring local type, unpack, next, error = type, unpack, next, error
local setmetatable, rawset, rawget = setmetatable, rawset, rawget local floor, max, min, mod = math.floor, math.max, math.min, math.mod
local select, pairs, type, next, tostring = select, pairs, type, next, tostring local tostring = tostring
local floor, max, min = math.floor, math.max, math.min
local tconcat = table.concat
-- WoW APIs -- WoW APIs
local GetTime = GetTime local GetTime = GetTime
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
-- GLOBALS: DEFAULT_CHAT_FRAME, geterrorhandler
-- Simple ONE-SHOT timer cache. Much more efficient than a full compost for our purposes.
local timerCache = nil
--[[ --[[
Timers will not be fired more often than HZ-1 times per second. Timers will not be fired more often than HZ-1 times per second.
Keep at intended speed PLUS ONE or we get bitten by floating point rounding errors (n.5 + 0.1 can be n.599999) Keep at intended speed PLUS ONE or we get bitten by floating point rounding errors (n.5 + 0.1 can be n.599999)
@@ -70,6 +49,7 @@ local timerCache = nil
If this number is ever changed, all entries need to be rehashed on lib upgrade. If this number is ever changed, all entries need to be rehashed on lib upgrade.
]] ]]
local HZ = 11 local HZ = 11
local minDelay = 1/(HZ-1)
--[[ --[[
Prime for good distribution Prime for good distribution
@@ -82,214 +62,122 @@ for i=1,BUCKETS do
hash[i] = hash[i] or false -- make it an integer-indexed array; it's faster than hashes hash[i] = hash[i] or false -- make it an integer-indexed array; it's faster than hashes
end end
--[[ local new, del
xpcall safecall implementation do
]] local list = setmetatable({}, {__mode = "k"})
local xpcall = xpcall function new(self, loop, func, delay, argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
local name = loop and "ScheduleRepeatingTimer" or "ScheduleTimer"
local function errorhandler(err) if self == AceTimer then
return geterrorhandler()(err) error(MAJOR..": " .. name .. "(callback, delay, argc, args...): use your own 'self'", 3)
end
local function CreateDispatcher(argCount)
local code = [[
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = unpack(arg)
return xpcall(call, function(err) return geterrorhandler()(err) end)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = gsub(code, "ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
end
local Dispatchers = setmetatable({}, {
__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end end
}) if not func or not delay then
Dispatchers[0] = function(func) error(MAJOR..": " .. name .. "(callback, delay, argc, args...): 'callback' and 'delay' must have set values.", 3)
return xpcall(func, errorhandler)
end
local function safecall(func, ...)
return Dispatchers[getn(arg)](func, unpack(arg))
end
local lastint = floor(GetTime() * HZ)
-- --------------------------------------------------------------------
-- OnUpdate handler
--
-- traverse buckets, always chasing "now", and fire timers that have expired
local function OnUpdate()
local now = GetTime()
local nowint = floor(now * HZ)
-- Have we passed into a new hash bucket?
if nowint == lastint then return end
local soon = now + 1 -- +1 is safe as long as 1 < HZ < BUCKETS/2
-- Pass through each bucket at most once
-- Happens on e.g. instance loads, but COULD happen on high local load situations also
for curint = (max(lastint, nowint - BUCKETS) + 1), nowint do -- loop until we catch up with "now", usually only 1 iteration
local curbucket = (math.mod(curint, BUCKETS))+1
-- Yank the list of timers out of the bucket and empty it. This allows reinsertion in the currently-processed bucket from callbacks.
local nexttimer = hash[curbucket]
hash[curbucket] = false -- false rather than nil to prevent the array from becoming a hash
while nexttimer do
local timer = nexttimer
nexttimer = timer.next
local when = timer.when
if when < soon then
-- Call the timer func, either as a method on given object, or a straight function ref
local callback = timer.callback
if type(callback) == "string" then
safecall(timer.object[callback], timer.object, timer.arg)
elseif callback then
safecall(callback, timer.arg)
else
-- probably nilled out by CancelTimer
timer.delay = nil -- don't reschedule it
end
local delay = timer.delay -- NOW make a local copy, can't do it earlier in case the timer cancelled itself in the callback
if not delay then
-- single-shot timer (or cancelled)
AceTimer.selfs[timer.object][tostring(timer)] = nil
timerCache = timer
else
-- repeating timer
local newtime = when + delay
if newtime < now then -- Keep lag from making us firing a timer unnecessarily. (Note that this still won't catch too-short-delay timers though.)
newtime = now + delay
end
timer.when = newtime
-- add next timer execution to the correct bucket
local bucket = (math.mod(floor(newtime * HZ), BUCKETS)) + 1
timer.next = hash[bucket]
hash[bucket] = timer
end
else -- if when>=soon
-- reinsert (yeah, somewhat expensive, but shouldn't be happening too often either due to hash distribution)
timer.next = hash[curbucket]
hash[curbucket] = timer
end -- if when<soon ... else
end -- while nexttimer do
end -- for curint=lastint,nowint
lastint = nowint
end
-- ---------------------------------------------------------------------
-- Reg( callback, delay, arg, repeating )
--
-- callback( function or string ) - direct function ref or method name in our object for the callback
-- delay(int) - delay for the timer
-- arg(variant) - any argument to be passed to the callback function
-- repeating(boolean) - repeating timer, or oneshot
--
-- returns the handle of the timer for later processing (canceling etc)
local function Reg(self, callback, delay, arg, repeating)
if type(callback) ~= "string" and type(callback) ~= "function" then
local error_origin = repeating and "ScheduleRepeatingTimer" or "ScheduleTimer"
error(MAJOR..": " .. error_origin .. "(callback, delay, arg): 'callback' - function or method name expected.", 3)
end end
if type(callback) == "string" then if argc and (type(argc) ~= "number" or floor(argc) ~= argc) then
if type(self)~="table" then error(MAJOR..": " .. name .. "(callback, delay, argc, args...): 'argc' must be an integer.", 3)
local error_origin = repeating and "ScheduleRepeatingTimer" or "ScheduleTimer" end
error(MAJOR..": " .. error_origin .. "(\"methodName\", delay, arg): 'self' - must be a table.", 3) if type(func) == "string" then
end if type(self) ~= "table" then
if type(self[callback]) ~= "function" then error(MAJOR..": " .. name .. "(callback, delay, argc, args...): 'self' - must be a table.", 3)
local error_origin = repeating and "ScheduleRepeatingTimer" or "ScheduleTimer" elseif type(self[func]) ~= "function" then
error(MAJOR..": " .. error_origin .. "(\"methodName\", delay, arg): 'methodName' - method not found on target object.", 3) error(MAJOR..": " .. name .. "(callback, delay, argc, args...): Tried to register '"..func.."' as the callback, but it is not a method.", 3)
end end
elseif type(func) ~= "function" then
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): Tried to register '"..tostring(func).."' as the callback, but it is not a function.", 3)
end end
if delay < (1 / (HZ - 1)) then if delay < minDelay then
delay = 1 / (HZ - 1) delay = minDelay
end end
-- Create and stuff timer in the correct hash bucket -- Create and stuff timer in the correct hash bucket
local now = GetTime() local now = GetTime()
local timer = timerCache or {} -- Get new timer object (from cache if available) local timer = next(list) or {}
timerCache = nil list[timer] = nil
timer.object = self timer.object = self
timer.callback = callback timer.func = func
timer.delay = (repeating and delay) timer.delay = delay
timer.arg = arg timer.status = loop and "loop" or "once"
timer.when = now + delay timer.ends = now + delay
timer.argsCount = argc or 0
timer[1] = a1
timer[2] = a2
timer[3] = a3
timer[4] = a4
timer[5] = a5
timer[6] = a6
timer[7] = a7
timer[8] = a8
timer[9] = a9
timer[10] = a10
local bucket = (math.mod(floor((now+delay)*HZ), BUCKETS)) + 1 local bucket = floor(mod((now+delay)*HZ,BUCKETS)) + 1
timer.next = hash[bucket] timer.next = hash[bucket]
hash[bucket] = timer hash[bucket] = timer
-- Insert timer in our self->handle->timer registry local id = tostring(timer) -- user has only access to the id but not the table itself
local handle = tostring(timer) activeTimers[id] = timer
local selftimers = AceTimer.selfs[self] counter[self] = (counter[self] or 0) + 1
if not selftimers then
selftimers = {}
AceTimer.selfs[self] = selftimers
end
selftimers[handle] = timer
selftimers.__ops = (selftimers.__ops or 0) + 1
return handle timerFrame:Show()
return id
end end
function del(t)
local id = tostring(t)
activeTimers[id] = nil
if not next(activeTimers) then
timerFrame:Hide()
end
local self = t.object
for k in pairs(t) do t[k] = nil end
list[t] = true
if counter[self] then
counter[self] = counter[self] - 1
else
counter[self] = nil
end
end
end -- new, del
--- Schedule a new one-shot timer. --- Schedule a new one-shot timer.
-- The timer will fire once in `delay` seconds, unless canceled before. -- The timer will fire once in `delay` seconds, unless canceled before.
-- @param callback Callback function for the timer pulse (funcref or method name). -- @param callback Callback function for the timer pulse (funcref or method name).
-- @param delay Delay for the timer, in seconds. -- @param delay Delay for the timer, in seconds.
-- @param arg An optional argument to be passed to the callback function. -- @param argc The numbers of arguments to be passed to the callback function
-- @param a1,...,a10 The arguments
-- @usage -- @usage
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("TimerTest", "AceTimer-3.0") -- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
-- --
-- function MyAddon:OnEnable() -- function MyAddOn:OnEnable()
-- self:ScheduleTimer("TimerFeedback", 5) -- self:ScheduleTimer("TimerFeedback", 5)
-- end -- end
-- --
-- function MyAddon:TimerFeedback() -- function MyAddOn:TimerFeedback()
-- print("5 seconds passed") -- print("5 seconds passed")
-- end -- end
function AceTimer:ScheduleTimer(callback, delay, arg) function AceTimer:ScheduleTimer(func, delay, argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
return Reg(self, callback, delay, arg) return new(self, nil, func, delay, argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
end end
--- Schedule a repeating timer. --- Schedule a repeating timer.
-- The timer will fire every `delay` seconds, until canceled. -- The timer will fire every `delay` seconds, until canceled.
-- @param callback Callback function for the timer pulse (funcref or method name). -- @param callback Callback function for the timer pulse (funcref or method name).
-- @param delay Delay for the timer, in seconds. -- @param delay Delay for the timer, in seconds.
-- @param arg An optional argument to be passed to the callback function. -- @param argc The numbers of arguments to be passed to the callback function
-- @param a1,...,a10 The arguments
-- @usage -- @usage
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("TimerTest", "AceTimer-3.0") -- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
-- --
-- function MyAddon:OnEnable() -- function MyAddOn:OnEnable()
-- self.timerCount = 0 -- self.timerCount = 0
-- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5) -- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5)
-- end -- end
-- --
-- function MyAddon:TimerFeedback() -- function MyAddOn:TimerFeedback()
-- self.timerCount = self.timerCount + 1 -- self.timerCount = self.timerCount + 1
-- print(("%d seconds passed"):format(5 * self.timerCount)) -- print(("%d seconds passed"):format(5 * self.timerCount))
-- -- run 30 seconds in total -- -- run 30 seconds in total
@@ -297,131 +185,65 @@ end
-- self:CancelTimer(self.testTimer) -- self:CancelTimer(self.testTimer)
-- end -- end
-- end -- end
function AceTimer:ScheduleRepeatingTimer(callback, delay, arg) function AceTimer:ScheduleRepeatingTimer(func, delay, argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
return Reg(self, callback, delay, arg, true) return new(self, true, func, delay, argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
end end
--- Cancels a timer with the given handle, registered by the same addon object as used for `:ScheduleTimer` --- Cancels a timer with the given id, registered by the same addon object as used for `:ScheduleTimer`
-- Both one-shot and repeating timers can be canceled with this function, as long as the `handle` is valid -- Both one-shot and repeating timers can be canceled with this function, as long as the `id` is valid
-- and the timer has not fired yet or was canceled before. -- and the timer has not fired yet or was canceled before.
-- @param handle The handle of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer` -- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
-- @param silent If true, no error is raised if the timer handle is invalid (expired or already canceled) function AceTimer:CancelTimer(id)
-- @return True if the timer was successfully cancelled. local timer = activeTimers[id]
function AceTimer:CancelTimer(handle, silent)
if not handle then return end -- nil handle -> bail out without erroring if not timer then
if type(handle) ~= "string" then return false
error(MAJOR..": CancelTimer(handle): 'handle' - expected a string", 2) -- for now, anyway
end
local selftimers = AceTimer.selfs[self]
local timer = selftimers and selftimers[handle]
if silent then
if timer then
timer.callback = nil -- don't run it again
timer.delay = nil -- if this is the currently-executing one: don't even reschedule
-- The timer object is removed in the OnUpdate loop
end
return not not timer -- might return "true" even if we double-cancel. we'll live.
else else
if not timer then -- Ace3v: the timer will always be collected in the next update but not here
geterrorhandler()(MAJOR..": CancelTimer(handle[, silent]): '"..tostring(handle).."' - no such timer registered") -- this is necessary for AceBucket to determinate if the bucket has been unregistered
return false -- in the callback
end timer.status = nil
if not timer.callback then activeTimers[id] = nil
geterrorhandler()(MAJOR..": CancelTimer(handle[, silent]): '"..tostring(handle).."' - timer already cancelled or expired")
return false
end
timer.callback = nil -- don't run it again
timer.delay = nil -- if this is the currently-executing one: don't even reschedule
return true return true
end end
end end
--- Cancels all timers registered to the current addon object ('self') --- Cancels all timers registered to the current addon object ('self')
function AceTimer:CancelAllTimers() function AceTimer:CancelAllTimers()
if not(type(self) == "string" or type(self) == "table") then if type(self) ~= "table" then
error(MAJOR..": CancelAllTimers(): 'self' - must be a string or a table",2) error(MAJOR..": CancelAllTimers(): 'self' - must be a table",2)
end end
if self == AceTimer then if self == AceTimer then
error(MAJOR..": CancelAllTimers(): supply a meaningful 'self'", 2) error(MAJOR..": CancelAllTimers(): supply a meaningful 'self'", 2)
end end
local selftimers = AceTimer.selfs[self] for k,v in pairs(activeTimers) do
if selftimers then if v.object == self then
for handle,v in pairs(selftimers) do AceTimer.CancelTimer(self, k)
if type(v) == "table" then -- avoid __ops, etc
AceTimer.CancelTimer(self, handle, true)
end
end end
end end
end end
--- Returns the time left for a timer with the given handle, registered by the current addon object ('self'). --- Returns the time left for a timer with the given id, registered by the current addon object ('self').
-- This function will raise a warning when the handle is invalid, but not stop execution. -- This function will return 0 when the id is invalid.
-- @param handle The handle of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer` -- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
-- @return The time left on the timer, or false if the handle is invalid. -- @return The time left on the timer.
function AceTimer:TimeLeft(handle) function AceTimer:TimeLeft(id)
if not handle then return end local timer = activeTimers[id]
if type(handle) ~= "string" then
error(MAJOR..": TimeLeft(handle): 'handle' - expected a string", 2) -- for now, anyway
end
local selftimers = AceTimer.selfs[self]
local timer = selftimers and selftimers[handle]
if not timer then if not timer then
geterrorhandler()(MAJOR..": TimeLeft(handle): '"..tostring(handle).."' - no such timer registered") return 0
return false else
return timer.ends - GetTime()
end end
return timer.when - GetTime()
end end
function AceTimer:TimerStatus(id)
-- --------------------------------------------------------------------- local timer = activeTimers[id]
-- PLAYER_REGEN_ENABLED: Run through our .selfs[] array step by step if not timer then
-- and clean it out - otherwise the table indices can grow indefinitely return nil
-- if an addon starts and stops a lot of timers. AceBucket does this! else
-- return timer.status
-- See ACE-94 and tests/AceTimer-3.0-ACE-94.lua
local lastCleaned = nil
local function OnEvent()
if event~="PLAYER_REGEN_ENABLED" then
return
end end
-- Get the next 'self' to process
local selfs = AceTimer.selfs
local self = next(selfs, lastCleaned)
if not self then
self = next(selfs)
end
lastCleaned = self
if not self then -- should only happen if .selfs[] is empty
return
end
-- Time to clean it out?
local list = selfs[self]
if (list.__ops or 0) < 250 then -- 250 slosh indices = ~10KB wasted (worst case!). For one 'self'.
return
end
-- Create a new table and copy all members over
local newlist = {}
local n=0
for k,v in pairs(list) do
newlist[k] = v
if type(v)=="table" and v.callback then -- if the timer is actually live: count it
n=n+1
end
end
newlist.__ops = 0 -- Reset operation count
-- And since we now have a count of the number of live timers, check that it's reasonable. Emit a warning if not.
if n>BUCKETS then
DEFAULT_CHAT_FRAME:AddMessage(MAJOR..": Warning: The addon/module '"..tostring(self).."' has "..n.." live timers. Surely that's not intended?")
end
selfs[self] = newlist
end end
-- --------------------------------------------------------------------- -- ---------------------------------------------------------------------
@@ -443,32 +265,115 @@ function AceTimer:Embed(target)
return target return target
end end
-- AceTimer:OnEmbedDisable( target ) -- AceTimer:OnEmbedDisable(target)
-- target (object) - target object that AceTimer is embedded in. -- target (object) - target object that AceTimer is embedded in.
-- --
-- cancel all timers registered for the object -- cancel all timers registered for the object
function AceTimer:OnEmbedDisable( target ) function AceTimer:OnEmbedDisable(target)
target:CancelAllTimers() target:CancelAllTimers()
end end
for addon in pairs(AceTimer.embeds) do for addon in pairs(AceTimer.embeds) do
AceTimer:Embed(addon) AceTimer:Embed(addon)
end end
-- --------------------------------------------------------------------- -- --------------------------------------------------------------------
-- Debug tools (expose copies of internals to test suites) -- OnUpdate handler
AceTimer.debug = AceTimer.debug or {} --
AceTimer.debug.HZ = HZ -- traverse buckets, always chasing "now", and fire timers that have expired
AceTimer.debug.BUCKETS = BUCKETS local lastint = floor(GetTime() * HZ)
local function OnUpdate()
local now = GetTime()
local nowint = floor(now * HZ)
-- --------------------------------------------------------------------- -- Have we passed into a new hash bucket?
-- Finishing touchups if nowint == lastint then return end
AceTimer.frame:SetScript("OnUpdate", OnUpdate) local soon = now + 1 -- +1 is safe as long as 1 < HZ < BUCKETS/2
AceTimer.frame:SetScript("OnEvent", OnEvent)
AceTimer.frame:RegisterEvent("PLAYER_REGEN_ENABLED")
-- In theory, we could hide&show the frame based on there being timers or not. -- Pass through each bucket at most once
-- However, this job is fairly expensive, and the chance that there will -- Happens on e.g. instance loads, but COULD happen on high local load situations also
-- actually be zero timers running is diminuitive to say the least. for curint = (max(lastint, nowint-BUCKETS) + 1), nowint do -- loop until we catch up with "now", usually only 1 iteratio
local curbucket = mod(curint,BUCKETS) + 1 -- Ace3v: both int so no floor here
-- Yank the list of timers out of the bucket and empty it. This allows reinsertion in the currently-processed bucket from callbacks.
local nexttimer = hash[curbucket]
hash[curbucket] = false -- false rather than nil to prevent the array from becoming a hash
while nexttimer do
local timer = nexttimer
nexttimer = timer.next
local status = timer.status
if not status then
del(timer)
else
local ends = timer.ends
if (status == "loop" or status == "once") and ends < soon then
local object = timer.object
local callback = timer.func
if type(callback) == "string" then
callback = (type(object) == "table") and object[callback]
if type(callback) == "function" then
safecall(callback, timer.argsCount+1, object,
timer[1], timer[2], timer[3], timer[4], timer[5],
timer[6], timer[7], timer[8], timer[9], timer[10])
else
status = "once"
end
elseif type(callback) == "function" then
safecall(callback, timer.argsCount,
timer[1], timer[2], timer[3], timer[4], timer[5],
timer[6], timer[7], timer[8], timer[9], timer[10])
else
-- probably nilled out by CancelTimer
status = "once" -- don't reschedule it
end
if status == "once" then
del(timer)
else
local delay = timer.delay
local newends = ends + delay
if newends < now then -- Keep lag from making us firing a timer unnecessarily. (Note that this still won't catch too-short-delay timers though.)
newends = now + delay
end
timer.ends = newends
-- add next timer execution to the correct bucket
local bucket = floor(mod(newends*HZ,BUCKETS)) + 1
timer.next = hash[bucket]
hash[bucket] = timer
end
else
-- reinsert (yeah, somewhat expensive, but shouldn't be happening too often either due to hash distribution)
timer.next = hash[curbucket]
hash[curbucket] = timer
end
end
end
end
lastint = nowint
end
local lastchecked = nil
local function OnEvent()
if event ~= "PLAYER_REGEN_ENABLED" then return end
local addon = next(counter, lastchecked)
if not addon then
addon = next(counter)
end
lastchecked = addon
if not addon then -- should only happen if counter is empty
return
end
local n = counter[addon]
if n > BUCKETS then
DEFAULT_CHAT_FRAME:AddMessage(MAJOR..": Warning: The addon/module '"..tostring(addon).."' has "..tostring(n).." live timers. Surely that's not intended?")
end
end
timerFrame:SetScript("OnUpdate", OnUpdate)
timerFrame:SetScript("OnEvent", OnEvent)
timerFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
timerFrame:Hide()
@@ -15,6 +15,7 @@
<Include file="LibSimpleSticky\LibSimpleSticky.xml"/> <Include file="LibSimpleSticky\LibSimpleSticky.xml"/>
<Include file="LibDataBroker\LibDataBroker-1.1.xml"/> <Include file="LibDataBroker\LibDataBroker-1.1.xml"/>
<Include file="LibElvUIPlugin-1.0\LibElvUIPlugin-1.0.xml"/> <Include file="LibElvUIPlugin-1.0\LibElvUIPlugin-1.0.xml"/>
<Include file="oUF\oUF.xml"/>
<!-- <!--
<Include file="UTF8\UTF8.xml"/> <Include file="UTF8\UTF8.xml"/>
<Include file="LibCompress\LibCompress.xml"/> <Include file="LibCompress\LibCompress.xml"/>
+25
View File
@@ -0,0 +1,25 @@
Copyright (c) 2006-2017 Trond A Ekseth <troeks@gmail.com>
Copyright (c) 2016-2017 Val Voronov <i.lightspark@gmail.com>
Copyright (c) 2016-2017 Adrian L Lange <contact@p3lim.net>
Copyright (c) 2016-2017 Rainrider <rainrider.wow@gmail.com>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,72 @@
local ns = oUF
local oUF = ns.oUF
local hiddenParent = CreateFrame("Frame")
-- sourced from FrameXML/PartyMemberFrame.lua
local MAX_PARTY_MEMBERS = MAX_PARTY_MEMBERS or 4
local hiddenParent = CreateFrame('Frame', nil, UIParent)
hiddenParent:SetAllPoints()
hiddenParent:Hide()
local function handleFrame(baseName)
local frame
if(type(baseName) == 'string') then
frame = _G[baseName]
else
frame = baseName
end
if(frame) then
frame:UnregisterAllEvents()
frame:Hide()
-- Keep frame hidden without causing taint
frame:SetParent(hiddenParent)
local health = frame.healthBar or frame.healthbar
if(health) then
health:UnregisterAllEvents()
end
local power = frame.manabar
if(power) then
power:UnregisterAllEvents()
end
local spell = frame.castBar or frame.spellbar
if(spell) then
spell:UnregisterAllEvents()
end
local buffFrame = frame.BuffFrame
if(buffFrame) then
buffFrame:UnregisterAllEvents()
end
end
end
function oUF:DisableBlizzard(unit)
if(not unit) then return end
if(unit == 'player') then
handleFrame(PlayerFrame)
elseif(unit == 'pet') then
handleFrame(PetFrame)
elseif(unit == 'target') then
handleFrame(TargetFrame)
handleFrame(ComboFrame)
elseif(unit == 'targettarget') then
handleFrame(TargetofTargetFrame)
elseif(unit:match('party%d?$')) then
local id = unit:match('party(%d)')
if(id) then
handleFrame('PartyMemberFrame' .. id)
else
for i = 1, MAX_PARTY_MEMBERS do
handleFrame(string.format('PartyMemberFrame%d', i))
end
end
end
end
+234
View File
@@ -0,0 +1,234 @@
local ns = oUF
local oUF = ns.oUF
local Private = oUF.Private
local frame_metatable = Private.frame_metatable
local colors = {
smooth = {
1, 0, 0,
1, 1, 0,
0, 1, 0
},
health = {49 / 255, 207 / 255, 37 / 255},
disconnected = {.6, .6, .6},
tapped = {.6, .6, .6},
class = {},
reaction = {},
power = {},
}
-- We do this because people edit the vars directly, and changing the default
-- globals makes SPICE FLOW!
local function customClassColors()
if(CUSTOM_CLASS_COLORS) then
local function updateColors()
for classToken, color in next, CUSTOM_CLASS_COLORS do
colors.class[classToken] = {color.r, color.g, color.b}
end
for _, obj in next, oUF.objects do
obj:UpdateAllElements('CUSTOM_CLASS_COLORS')
end
end
updateColors()
CUSTOM_CLASS_COLORS:RegisterCallback(updateColors)
return true
end
end
if(not customClassColors()) then
for classToken, color in next, RAID_CLASS_COLORS do
colors.class[classToken] = {color.r, color.g, color.b}
end
local eventHandler = CreateFrame('Frame')
eventHandler:RegisterEvent('ADDON_LOADED')
eventHandler:SetScript('OnEvent', function(self)
if(customClassColors()) then
self:UnregisterEvent('ADDON_LOADED')
self:SetScript('OnEvent', nil)
end
end)
end
for eclass, color in next, FACTION_BAR_COLORS do
colors.reaction[eclass] = {color.r, color.g, color.b}
end
colors.power = {}
colors.power[0] = {0.00, 0.00, 1.00}
colors.power[1] = {1.00, 0.00, 0.00}
colors.power[2] = {1.00, 0.50, 0.25}
colors.power[3] = {1.00, 1.00, 0.00}
colors.power[4] = {0.00, 1.00, 1.00}
local function colorsAndPercent(a, b, ...)
if(a <= 0 or b == 0) then
return nil, unpack(arg)
elseif(a >= b) then
return nil, select(select('#', unpack(arg)) - 2, unpack(arg))
end
local num = select('#', unpack(arg)) / 3
local segment, relperc = math.modf((a / b) * (num - 1))
return relperc, select((segment * 3) + 1, unpack(arg))
end
-- http://www.wowwiki.com/ColorGradient
--[[ Colors: oUF:RGBColorGradient(a, b, ...)
Used to convert a percent value (the quotient of `a` and `b`) into a gradient from 2 or more RGB colors. If more than 2
colors are passed, the gradient will be between the two colors which perc lies in an evenly divided range. A RGB color
is a sequence of 3 consecutive RGB percent values (in the range [0-1]). If `a` is negative or `b` is zero then the first
RGB color (the first 3 RGB values passed to the function) is returned. If `a` is bigger than or equal to `b`, then the
last 3 RGB values are returned.
* self - the global oUF object
* a - value used as numerator to calculate the percentage (number)
* b - value used as denominator to calculate the percentage (number)
* ... - a list of RGB percent values. At least 6 values should be passed (number [0-1])
--]]
local function RGBColorGradient(...)
local relperc, r1, g1, b1, r2, g2, b2 = colorsAndPercent(unpack(arg))
if(relperc) then
return r1 + (r2 - r1) * relperc, g1 + (g2 - g1) * relperc, b1 + (b2 - b1) * relperc
else
return r1, g1, b1
end
end
-- HCY functions are based on http://www.chilliant.com/rgb2hsv.html
local function getY(r, g, b)
return 0.299 * r + 0.587 * g + 0.114 * b
end
--[[ Colors: oUF:RGBToHCY(r, g, b)
Used to convert a color from RGB to HCY color space.
* self - the global oUF object
* r - red color component (number [0-1])
* g - green color component (number [0-1])
* b - blue color component (number [0-1])
--]]
function oUF:RGBToHCY(r, g, b)
local min, max = min(r, g, b), max(r, g, b)
local chroma = max - min
local hue
if(chroma > 0) then
if(r == max) then
hue = math.mod((g - b) / chroma, 6)
elseif(g == max) then
hue = (b - r) / chroma + 2
elseif(b == max) then
hue = (r - g) / chroma + 4
end
hue = hue / 6
end
return hue, chroma, getY(r, g, b)
end
local math_abs = math.abs
--[[ Colors: oUF:HCYtoRGB(hue, chroma, luma)
Used to convert a color from HCY to RGB color space.
* self - the global oUF object
* hue - hue color component (number [0-1])
* chroma - chroma color component (number [0-1])
* luma - luminance color component (number [0-1])
--]]
function oUF:HCYtoRGB(hue, chroma, luma)
local r, g, b = 0, 0, 0
if(hue and luma > 0) then
local h2 = hue * 6
local x = chroma * (1 - math_abs(math.mod(h2, 2 - 1)))
if(h2 < 1) then
r, g, b = chroma, x, 0
elseif(h2 < 2) then
r, g, b = x, chroma, 0
elseif(h2 < 3) then
r, g, b = 0, chroma, x
elseif(h2 < 4) then
r, g, b = 0, x, chroma
elseif(h2 < 5) then
r, g, b = x, 0, chroma
else
r, g, b = chroma, 0, x
end
local y = getY(r, g, b)
if(luma < y) then
chroma = chroma * (luma / y)
elseif(y < 1) then
chroma = chroma * (1 - luma) / (1 - y)
end
r = (r - y) * chroma + luma
g = (g - y) * chroma + luma
b = (b - y) * chroma + luma
end
return r, g, b
end
--[[ Colors: oUF:HCYColorGradient(a, b, ...)
Used to convert a percent value (the quotient of `a` and `b`) into a gradient from 2 or more HCY colors. If more than 2
colors are passed, the gradient will be between the two colors which perc lies in an evenly divided range. A HCY color
is a sequence of 3 consecutive values in the range [0-1]. If `a` is negative or `b` is zero then the first
HCY color (the first 3 HCY values passed to the function) is returned. If `a` is bigger than or equal to `b`, then the
last 3 HCY values are returned.
* self - the global oUF object
* a - value used as numerator to calculate the percentage (number)
* b - value used as denominator to calculate the percentage (number)
* ... - a list of HCY color values. At least 6 values should be passed (number [0-1])
--]]
local function HCYColorGradient(...)
local relperc, r1, g1, b1, r2, g2, b2 = colorsAndPercent(unpack(arg))
if(not relperc) then
return r1, g1, b1
end
local h1, c1, y1 = self:RGBToHCY(r1, g1, b1)
local h2, c2, y2 = self:RGBToHCY(r2, g2, b2)
local c = c1 + (c2 - c1) * relperc
local y = y1 + (y2 - y1) * relperc
if(h1 and h2) then
local dh = h2 - h1
if(dh < -0.5) then
dh = dh + 1
elseif(dh > 0.5) then
dh = dh - 1
end
return self:HCYtoRGB(math.mod(h1 + dh * relperc, 1), c, y)
else
return self:HCYtoRGB(h1 or h2, c, y)
end
end
--[[ Colors: oUF:ColorGradient(a, b, ...) or frame:ColorGradient(a, b, ...)
Used as a proxy to call the proper gradient function depending on the user's preference. If `oUF.useHCYColorGradient` is
set to true, `:HCYColorGradient` will be called, else `:RGBColorGradient`.
* self - the global oUF object or a unit frame
* a - value used as numerator to calculate the percentage (number)
* b - value used as denominator to calculate the percentage (number)
* ... - a list of color values. At least 6 values should be passed (number [0-1])
--]]
local function ColorGradient(...)
return (oUF.useHCYColorGradient and HCYColorGradient or RGBColorGradient)(unpack(arg))
end
Private.colors = colors
oUF.colors = colors
oUF.ColorGradient = ColorGradient
oUF.RGBColorGradient = RGBColorGradient
oUF.HCYColorGradient = HCYColorGradient
oUF.useHCYColorGradient = false
frame_metatable.__index.colors = colors
frame_metatable.__index.ColorGradient = ColorGradient
@@ -0,0 +1,103 @@
--[[
# Element: Assistant Indicator
Toggles the visibility of an indicator based on the unit's raid assistant status.
## Widget
AssistantIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local AssistantIndicator = self:CreateTexture(nil, 'OVERLAY')
AssistantIndicator:SetSize(16, 16)
AssistantIndicator:SetPoint('TOP', self)
-- Register it with oUF
self.AssistantIndicator = AssistantIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local UnitInRaid = UnitInRaid
local UnitIsPartyLeader = UnitIsPartyLeader
local UnitIsRaidOfficer = UnitIsRaidOfficer
local function Update(self, event)
local element = self.AssistantIndicator
--[[ Callback: AssistantIndicator:PreUpdate()
Called before the element has been updated.
* self - the AssistantIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local unit = self.unit
local isAssistant = UnitInRaid(unit) and UnitIsRaidOfficer(unit) and not UnitIsPartyLeader(unit)
if(isAssistant) then
element:Show()
else
element:Hide()
end
--[[ Callback: AssistantIndicator:PostUpdate(isAssistant)
Called after the element has been updated.
* self - the AssistantIndicator element
* isAssistant - indicates whether the unit is a raid assistant (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isAssistant)
end
end
local function Path(self, ...)
--[[ Override: AssistantIndicator.Override(self, event, ...)
Used to completely override the element's update process.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event (string)
--]]
return (self.AssistantIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.AssistantIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\GroupFrame\UI-Group-AssistantIcon]])
end
return true
end
end
local function Disable(self)
local element = self.AssistantIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
end
end
oUF:AddElement('AssistantIndicator', Path, Enable, Disable)
@@ -0,0 +1,516 @@
--[[
# Element: Auras
Handles creation and updating of aura icons.
## Widget
Auras - A Frame to hold `Button`s representing both buffs and debuffs.
Buffs - A Frame to hold `Button`s representing buffs.
Debuffs - A Frame to hold `Button`s representing debuffs.
## Notes
At least one of the above widgets must be present for the element to work.
## Options
.disableMouse - Disables mouse events (boolean)
.disableCooldown - Disables the cooldown spiral (boolean)
.size - Aura icon size. Defaults to 16 (number)
.spacing - Spacing between each icon. Defaults to 0 (number)
.['spacing-x'] - Horizontal spacing between each icon. Takes priority over `spacing` (number)
.['spacing-y'] - Vertical spacing between each icon. Takes priority over `spacing` (number)
.['growth-x'] - Horizontal growth direction. Defaults to 'RIGHT' (string)
.['growth-y'] - Vertical growth direction. Defaults to 'UP' (string)
.initialAnchor - Anchor point for the icons. Defaults to 'BOTTOMLEFT' (string)
.filter - Custom filter list for auras to display. Defaults to 'HELPFUL' for buffs and 'HARMFUL' for
debuffs (string)
## Options Auras
.numBuffs - The maximum number of buffs to display. Defaults to 32 (number)
.numDebuffs - The maximum number of debuffs to display. Defaults to 40 (number)
.numTotal - The maximum number of auras to display. Prioritizes buffs over debuffs. Defaults to the sum of
.numBuffs and .numDebuffs (number)
.gap - Controls the creation of an invisible icon between buffs and debuffs. Defaults to false (boolean)
.buffFilter - Custom filter list for buffs to display. Takes priority over `filter` (string)
.debuffFilter - Custom filter list for debuffs to display. Takes priority over `filter` (string)
## Options Buffs
.num - Number of buffs to display. Defaults to 32 (number)
## Options Debuffs
.num - Number of debuffs to display. Defaults to 40 (number)
## Attributes
button.filter - the filter list used to determine the visibility of the aura (string)
button.isDebuff - indicates if the button holds a debuff (boolean)
## Examples
-- Position and size
local Buffs = CreateFrame('Frame', nil, self)
Buffs:SetPoint('RIGHT', self, 'LEFT')
Buffs:SetSize(16 * 2, 16 * 16)
-- Register with oUF
self.Buffs = Buffs
--]]
local ns = oUF
local oUF = ns.oUF
local tinsert = table.insert
local floor = math.floor
local CreateFrame = CreateFrame
local GetTime = GetTime
local UnitAura = UnitAura
local VISIBLE = 1
local HIDDEN = 0
local function UpdateTooltip(self)
if self.filter == 'HELPFUL' then
GameTooltip:SetUnitBuff(self:GetParent().__owner.unit, self:GetID(), self.filter)
else
GameTooltip:SetUnitDebuff(self:GetParent().__owner.unit, self:GetID(), self.filter)
end
end
local function onEnter(self)
if(not self:IsVisible()) then return end
GameTooltip:SetOwner(self, 'ANCHOR_BOTTOMRIGHT')
self:UpdateTooltip()
end
local function onLeave()
GameTooltip:Hide()
end
local function createAuraIcon(element, index)
local button = CreateFrame('Button', '$parentButton' .. index, element)
button:RegisterForClicks('RightButtonUp')
local cd = CreateFrame('Cooldown', '$parentCooldown', button, 'oUF_CooldownFrameTemplate')
cd:SetAllPoints()
local icon = button:CreateTexture(nil, 'BORDER')
icon:SetAllPoints()
local count = button:CreateFontString(nil, 'OVERLAY', 'NumberFontNormal')
count:SetPoint('BOTTOMRIGHT', button, 'BOTTOMRIGHT', -1, 0)
local overlay = button:CreateTexture(nil, 'OVERLAY')
overlay:SetTexture([[Interface\Buttons\UI-Debuff-Overlays]])
overlay:SetAllPoints()
overlay:SetTexCoord(.296875, .5703125, 0, .515625)
button.overlay = overlay
button.UpdateTooltip = UpdateTooltip
button:SetScript('OnEnter', onEnter)
button:SetScript('OnLeave', onLeave)
button.icon = icon
button.count = count
button.cd = cd
--[[ Callback: Auras:PostCreateIcon(button)
Called after a new aura button has been created.
* self - the widget holding the aura buttons
* button - the newly created aura button (Button)
--]]
if(element.PostCreateIcon) then element:PostCreateIcon(button) end
return button
end
local function customFilter(element, unit, button, name)
if(name) then
return true
end
end
local function updateIcon(element, unit, index, offset, filter, isDebuff, visible)
local name, rank, texture, count, dispelType, duration, expiration = UnitAura(unit, index, filter)
if element.forceShow then
name, rank, texture = GetSpellInfo(26993)
count, dispelType, duration, expiration = 5, 'Magic', 0, 60
end
if(name) then
local position = visible + offset + 1
local button = element[position]
if(not button) then
--[[ Override: Auras:CreateIcon(position)
Used to create the aura button at a given position.
* self - the widget holding the aura buttons
* position - the position at which the aura button is to be created (number)
## Returns
* button - the button used to represent the aura (Button)
--]]
button = (element.CreateIcon or createAuraIcon) (element, position)
tinsert(element, button)
element.createdIcons = element.createdIcons + 1
end
button.filter = filter
button.isDebuff = isDebuff
--[[ Override: Auras:CustomFilter(unit, button, ...)
Defines a custom filter that controls if the aura button should be shown.
* self - the widget holding the aura buttons
* unit - the unit on which the aura is cast (string)
* button - the button displaying the aura (Button)
* ... - the return values from [UnitAura](http://wowprogramming.com/docs/api/UnitAura)
## Returns
* show - indicates whether the aura button should be shown (boolean)
--]]
local show = true
if not element.forceShow then
show = (element.CustomFilter or customFilter) (element, unit, button, name, rank, texture, count, dispelType, duration, expiration)
end
if(show) then
-- We might want to consider delaying the creation of an actual cooldown
-- object to this point, but I think that will just make things needlessly
-- complicated.
if(button.cd and not element.disableCooldown) then
if(duration and duration > 0) then
button.cd:SetCooldown(GetTime() - (duration - expiration), duration)
button.cd:Show()
else
button.cd:Hide()
end
end
if(button.overlay) then
if((isDebuff and element.showDebuffType) or (not isDebuff and element.showBuffType) or element.showType) then
local color = DebuffTypeColor[dispelType] or DebuffTypeColor.none
button.overlay:SetVertexColor(color.r, color.g, color.b)
button.overlay:Show()
else
button.overlay:Hide()
end
end
if(button.icon) then button.icon:SetTexture(texture) end
if(button.count) then button.count:SetText(count > 1 and count) end
local size = element.size or 16
button:SetSize(size, size)
button:EnableMouse(not element.disableMouse)
button:SetID(index)
button:Show()
--[[ Callback: Auras:PostUpdateIcon(unit, button, index, position)
Called after the aura button has been updated.
* self - the widget holding the aura buttons
* unit - the unit on which the aura is cast (string)
* button - the updated aura button (Button)
* index - the index of the aura (number)
* position - the actual position of the aura button (number)
--]]
if(element.PostUpdateIcon) then
element:PostUpdateIcon(unit, button, index, position)
end
return VISIBLE
else
return HIDDEN
end
end
end
local function SetPosition(element, from, to)
local sizex = (element.size or 16) + (element['spacing-x'] or element.spacing or 0)
local sizey = (element.size or 16) + (element['spacing-y'] or element.spacing or 0)
local anchor = element.initialAnchor or 'BOTTOMLEFT'
local growthx = (element['growth-x'] == 'LEFT' and -1) or 1
local growthy = (element['growth-y'] == 'DOWN' and -1) or 1
local cols = floor(element:GetWidth() / sizex + 0.5)
for i = from, to do
local button = element[i]
-- Bail out if the to range is out of scope.
if(not button) then break end
local col = (i - 1) % cols
local row = floor((i - 1) / cols)
button:ClearAllPoints()
button:SetPoint(anchor, element, anchor, col * sizex * growthx, row * sizey * growthy)
end
end
local function filterIcons(element, unit, filter, limit, isDebuff, offset, dontHide)
if(not offset) then offset = 0 end
local index = 1
local visible = 0
local hidden = 0
while(visible < limit) do
local result = updateIcon(element, unit, index, offset, filter, isDebuff, visible)
if(not result) then
break
elseif(result == VISIBLE) then
visible = visible + 1
elseif(result == HIDDEN) then
hidden = hidden + 1
end
index = index + 1
end
if(not dontHide) then
for i = visible + offset + 1, #element do
element[i]:Hide()
end
end
return visible, hidden
end
local function UpdateAuras(self, event, unit)
if(self.unit ~= unit) then return end
local auras = self.Auras
if(auras) then
--[[ Callback: Auras:PreUpdate(unit)
Called before the element has been updated.
* self - the widget holding the aura buttons
* unit - the unit for which the update has been triggered (string)
--]]
if(auras.PreUpdate) then auras:PreUpdate(unit) end
local numBuffs = auras.numBuffs or 32
local numDebuffs = auras.numDebuffs or 40
local max = auras.numTotal or numBuffs + numDebuffs
local visibleBuffs, hiddenBuffs = filterIcons(auras, unit, auras.buffFilter or auras.filter or 'HELPFUL', math.min(numBuffs, max), nil, 0, true)
local hasGap
if(visibleBuffs ~= 0 and auras.gap) then
hasGap = true
visibleBuffs = visibleBuffs + 1
local button = auras[visibleBuffs]
if(not button) then
button = (auras.CreateIcon or createAuraIcon) (auras, visibleBuffs)
tinsert(auras, button)
auras.createdIcons = auras.createdIcons + 1
end
-- Prevent the button from displaying anything.
if(button.cd) then button.cd:Hide() end
if(button.icon) then button.icon:SetTexture() end
if(button.overlay) then button.overlay:Hide() end
if(button.stealable) then button.stealable:Hide() end
if(button.count) then button.count:SetText() end
button:EnableMouse(false)
button:Show()
--[[ Callback: Auras:PostUpdateGapIcon(unit, gapButton, visibleBuffs)
Called after an invisible aura button has been created. Only used by Auras when the `gap` option is enabled.
* self - the widget holding the aura buttons
* unit - the unit that has the invisible aura button (string)
* gapButton - the invisible aura button (Button)
* visibleBuffs - the number of currently visible aura buttons (number)
--]]
if(auras.PostUpdateGapIcon) then
auras:PostUpdateGapIcon(unit, button, visibleBuffs)
end
end
local visibleDebuffs, hiddenDebuffs = filterIcons(auras, unit, auras.debuffFilter or auras.filter or 'HARMFUL', math.min(numDebuffs, max - visibleBuffs), true, visibleBuffs)
auras.visibleDebuffs = visibleDebuffs
if(hasGap and visibleDebuffs == 0) then
auras[visibleBuffs]:Hide()
visibleBuffs = visibleBuffs - 1
end
auras.visibleBuffs = visibleBuffs
auras.visibleAuras = auras.visibleBuffs + auras.visibleDebuffs
local fromRange, toRange
--[[ Callback: Auras:PreSetPosition(max)
Called before the aura buttons have been (re-)anchored.
* self - the widget holding the aura buttons
* max - the maximum possible number of aura buttons (number)
## Returns
* from - the offset of the first aura button to be (re-)anchored (number)
* to - the offset of the last aura button to be (re-)anchored (number)
--]]
if(auras.PreSetPosition) then
fromRange, toRange = auras:PreSetPosition(max)
end
if(fromRange or auras.createdIcons > auras.anchoredIcons) then
--[[ Override: Auras:SetPosition(from, to)
Used to (re-)anchor the aura buttons.
Called when new aura buttons have been created or if :PreSetPosition is defined.
* self - the widget that holds the aura buttons
* from - the offset of the first aura button to be (re-)anchored (number)
* to - the offset of the last aura button to be (re-)anchored (number)
--]]
(auras.SetPosition or SetPosition) (auras, fromRange or auras.anchoredIcons + 1, toRange or auras.createdIcons)
auras.anchoredIcons = auras.createdIcons
end
--[[ Callback: Auras:PostUpdate(unit)
Called after the element has been updated.
* self - the widget holding the aura buttons
* unit - the unit for which the update has been triggered (string)
--]]
if(auras.PostUpdate) then auras:PostUpdate(unit) end
end
local buffs = self.Buffs
if(buffs) then
if(buffs.PreUpdate) then buffs:PreUpdate(unit) end
local numBuffs = buffs.num or 32
local visibleBuffs, hiddenBuffs = filterIcons(buffs, unit, buffs.filter or 'HELPFUL', numBuffs)
buffs.visibleBuffs = visibleBuffs
local fromRange, toRange
if(buffs.PreSetPosition) then
fromRange, toRange = buffs:PreSetPosition(numBuffs)
end
if(fromRange or buffs.createdIcons > buffs.anchoredIcons) then
(buffs.SetPosition or SetPosition) (buffs, fromRange or buffs.anchoredIcons + 1, toRange or buffs.createdIcons)
buffs.anchoredIcons = buffs.createdIcons
end
if(buffs.PostUpdate) then buffs:PostUpdate(unit) end
end
local debuffs = self.Debuffs
if(debuffs) then
if(debuffs.PreUpdate) then debuffs:PreUpdate(unit) end
local numDebuffs = debuffs.num or 40
local visibleDebuffs, hiddenDebuffs = filterIcons(debuffs, unit, debuffs.filter or 'HARMFUL', numDebuffs, true)
debuffs.visibleDebuffs = visibleDebuffs
local fromRange, toRange
if(debuffs.PreSetPosition) then
fromRange, toRange = debuffs:PreSetPosition(numDebuffs)
end
if(fromRange or debuffs.createdIcons > debuffs.anchoredIcons) then
(debuffs.SetPosition or SetPosition) (debuffs, fromRange or debuffs.anchoredIcons + 1, toRange or debuffs.createdIcons)
debuffs.anchoredIcons = debuffs.createdIcons
end
if(debuffs.PostUpdate) then debuffs:PostUpdate(unit) end
end
end
local function Update(self, event, unit)
if(self.unit ~= unit) then return end
UpdateAuras(self, event, unit)
-- Assume no event means someone wants to re-anchor things. This is usually
-- done by UpdateAllElements and :ForceUpdate.
if(event == 'ForceUpdate' or not event) then
local buffs = self.Buffs
if(buffs) then
(buffs.SetPosition or SetPosition) (buffs, 1, buffs.createdIcons)
end
local debuffs = self.Debuffs
if(debuffs) then
(debuffs.SetPosition or SetPosition) (debuffs, 1, debuffs.createdIcons)
end
local auras = self.Auras
if(auras) then
(auras.SetPosition or SetPosition) (auras, 1, auras.createdIcons)
end
end
end
local function ForceUpdate(element)
return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
if(self.Buffs or self.Debuffs or self.Auras) then
self:RegisterEvent('UNIT_AURA', UpdateAuras)
local buffs = self.Buffs
if(buffs) then
buffs.__owner = self
buffs.ForceUpdate = ForceUpdate
buffs.createdIcons = buffs.createdIcons or 0
buffs.anchoredIcons = 0
--buffs:Show()
end
local debuffs = self.Debuffs
if(debuffs) then
debuffs.__owner = self
debuffs.ForceUpdate = ForceUpdate
debuffs.createdIcons = debuffs.createdIcons or 0
debuffs.anchoredIcons = 0
--debuffs:Show()
end
local auras = self.Auras
if(auras) then
auras.__owner = self
auras.ForceUpdate = ForceUpdate
auras.createdIcons = auras.createdIcons or 0
auras.anchoredIcons = 0
--auras:Show()
end
return true
end
end
local function Disable(self)
if(self.Buffs or self.Debuffs or self.Auras) then
self:UnregisterEvent('UNIT_AURA', UpdateAuras)
if(self.Buffs) then self.Buffs:Hide() end
if(self.Debuffs) then self.Debuffs:Hide() end
if(self.Auras) then self.Auras:Hide() end
end
end
oUF:AddElement('Auras', Update, Enable, Disable)
@@ -0,0 +1,585 @@
--[[
# Element: Castbar
Handles the visibility and updating of spell castbars.
Based upon oUF_Castbar by starlon.
## Widget
Castbar - A `StatusBar` to represent spell cast/channel progress.
## Sub-Widgets
.Text - A `FontString` to represent spell name.
.Icon - A `Texture` to represent spell icon.
.Time - A `FontString` to represent spell duration.
.SafeZone - A `Texture` to represent latency.
## Notes
A default texture will be applied to the StatusBar and Texture widgets if they don't have a texture or a color set.
## Options
.timeToHold - indicates for how many seconds the castbar should be visible after a _FAILED or _INTERRUPTED
event. Defaults to 0 (number)
## Examples
-- Position and size
local Castbar = CreateFrame('StatusBar', nil, self)
Castbar:SetSize(20, 20)
Castbar:SetPoint('TOP')
Castbar:SetPoint('LEFT')
Castbar:SetPoint('RIGHT')
-- Add a background
local Background = Castbar:CreateTexture(nil, 'BACKGROUND')
Background:SetAllPoints(Castbar)
Background:SetTexture(1, 1, 1, .5)
-- Add a spark
local Spark = Castbar:CreateTexture(nil, 'OVERLAY')
Spark:SetSize(20, 20)
Spark:SetBlendMode('ADD')
-- Add a timer
local Time = Castbar:CreateFontString(nil, 'OVERLAY', 'GameFontNormalSmall')
Time:SetPoint('RIGHT', Castbar)
-- Add spell text
local Text = Castbar:CreateFontString(nil, 'OVERLAY', 'GameFontNormalSmall')
Text:SetPoint('LEFT', Castbar)
-- Add spell icon
local Icon = Castbar:CreateTexture(nil, 'OVERLAY')
Icon:SetSize(20, 20)
Icon:SetPoint('TOPLEFT', Castbar, 'TOPLEFT')
-- Add safezone
local SafeZone = Castbar:CreateTexture(nil, 'OVERLAY')
-- Register it with oUF
Castbar.bg = Background
Castbar.Spark = Spark
Castbar.Time = Time
Castbar.Text = Text
Castbar.Icon = Icon
Castbar.SafeZone = SafeZone
self.Castbar = Castbar
--]]
local ns = oUF
local oUF = ns.oUF
local GetNetStats = GetNetStats
local GetTime = GetTime
local UnitCastingInfo = UnitCastingInfo
local UnitChannelInfo = UnitChannelInfo
local UnitIsUnit = UnitIsUnit
local tradeskillCastTime, tradeskillCastDuration, tradeskillCurrent, tradeskillTotal, mergeTradeskill = 0, 0, 0, 0, false
local function updateSafeZone(self)
local safeZone = self.SafeZone
local width = self:GetWidth()
local _, _, ms = GetNetStats()
-- Guard against GetNetStats returning latencies of 0.
if(ms ~= 0) then
local safeZoneRatio = (ms / 1e3) / self.max
if(safeZoneRatio > 1) then
safeZoneRatio = 1
end
safeZone:SetWidth(width * safeZoneRatio)
safeZone:Show()
else
safeZone:Hide()
end
end
local function UNIT_SPELLCAST_SENT(self, event, unit, spell, rank, target)
local element = self.Castbar
element.curTarget = (target and target ~= '') and target or nil
if element.isTradeSkill then
element.tradeSkillCastName = spell
end
end
local function UNIT_SPELLCAST_START(self, event, unit)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
local name, _, text, texture, startTime, endTime, isTradeSkill = UnitCastingInfo(unit)
if(not name) then
return element:Hide()
end
endTime = endTime / 1e3
startTime = startTime / 1e3
local max = endTime - startTime
element.castName = name
element.duration = GetTime() - startTime
element.max = max
element.delay = 0
element.casting = true
element.holdTime = 0
element.isTradeSkill = isTradeSkill
if(mergeTradeskill and isTradeSkill and UnitIsUnit(unit, 'player')) then
element.duration = element.duration + (element.max * tradeskillCurrent)
element.max = max * tradeskillTotal
if(unit == 'player') then
tradeskillCurrent = tradeskillCurrent + 1
tradeskillCastDuration = element.duration
tradeskillCastTime = max
end
element:SetValue(element.duration)
else
element:SetValue(0)
end
element:SetMinMaxValues(0, element.max)
if(element.Text) then element.Text:SetText(text) end
if(element.Icon) then element.Icon:SetTexture(texture) end
if(element.Time) then element.Time:SetText() end
local sf = element.SafeZone
if(sf) then
sf:ClearAllPoints()
sf:SetPoint('RIGHT')
sf:SetPoint('TOP')
sf:SetPoint('BOTTOM')
updateSafeZone(element)
end
--[[ Callback: Castbar:PostCastStart(unit, name)
Called after the element has been updated upon a spell cast start.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the spell being cast (string)
--]]
if(element.PostCastStart) then
element:PostCastStart(unit, name)
end
element:Show()
end
local function UNIT_SPELLCAST_FAILED(self, event, unit, spellname)
if(not self.casting) then return end
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
if(spellname and (element.castName ~= spellname and element.tradeSkillCastName ~= spellname)) then
return
end
if(mergeTradeskill and UnitIsUnit(unit, 'player')) then
mergeTradeskill = false
element.tradeSkillCastName = nil
end
local text = element.Text
if(text) then
text:SetText(FAILED)
end
element.casting = nil
element.holdTime = element.timeToHold or 0
--[[ Callback: Castbar:PostCastFailed(unit, name)
Called after the element has been updated upon a failed spell cast.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the failed spell (string)
--]]
if(element.PostCastFailed) then
return element:PostCastFailed(unit, spellname)
end
end
local function UNIT_SPELLCAST_FAILED_QUIET(self, event, unit, spellname)
if(not self.casting) then return end
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
if(spellname and (element.castName ~= spellname and element.tradeSkillCastName ~= spellname)) then
return
end
if(mergeTradeskill and UnitIsUnit(unit, 'player')) then
mergeTradeskill = false
element.tradeSkillCastName = nil
end
element.casting = nil
element:SetValue(0)
element:Hide()
end
local function UNIT_SPELLCAST_INTERRUPTED(self, event, unit, spellname)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
if(spellname and element.castName ~= spellname) then
return
end
local text = element.Text
if(text) then
text:SetText(INTERRUPTED)
end
element.casting = nil
element.channeling = nil
element.holdTime = element.timeToHold or 0
--[[ Callback: Castbar:PostCastInterrupted(unit, name)
Called after the element has been updated upon an interrupted spell cast.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the interrupted spell (string)
--]]
if(element.PostCastInterrupted) then
return element:PostCastInterrupted(unit, spellname)
end
end
local function UNIT_SPELLCAST_DELAYED(self, event, unit)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
local name, _, _, _, startTime = UnitCastingInfo(unit)
if(not startTime or not element:IsShown()) then return end
local duration = GetTime() - (startTime / 1000)
if(duration < 0) then duration = 0 end
element.delay = element.delay + element.duration - duration
element.duration = duration
element:SetValue(duration)
--[[ Callback: Castbar:PostCastDelayed(unit, name)
Called after the element has been updated when a spell cast has been delayed.
* self - the Castbar widget
* unit - unit that the update has been triggered (string)
* name - name of the delayed spell (string)
--]]
if(element.PostCastDelayed) then
return element:PostCastDelayed(unit, name)
end
end
local function UNIT_SPELLCAST_STOP(self, event, unit, spellname)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
if(spellname and (element.castName ~= spellname)) then
return
end
if(mergeTradeskill and UnitIsUnit(unit, 'player')) then
if(tradeskillCurrent == tradeskillTotal) then
mergeTradeskill = false
end
else
element.casting = nil
end
--[[ Callback: Castbar:PostCastStop(unit, name)
Called after the element has been updated when a spell cast has finished.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the spell (string)
--]]
if(element.PostCastStop) then
return element:PostCastStop(unit, spellname)
end
end
local function UNIT_SPELLCAST_CHANNEL_START(self, event, unit)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
local name, _, _, texture, startTime, endTime = UnitChannelInfo(unit)
if(not name) then
return
end
endTime = endTime / 1e3
startTime = startTime / 1e3
local max = (endTime - startTime)
local duration = endTime - GetTime()
element.duration = duration
element.max = max
element.delay = 0
element.startTime = startTime
element.endTime = endTime
element.extraTickRatio = 0
element.channeling = true
element.holdTime = 0
-- We have to do this, as it's possible for spell casts to never have _STOP
-- executed or be fully completed by the OnUpdate handler before CHANNEL_START
-- is called.
element.casting = nil
element.castName = nil
element:SetMinMaxValues(0, max)
element:SetValue(duration)
if(element.Text) then element.Text:SetText(name) end
if(element.Icon) then element.Icon:SetTexture(texture) end
if(element.Time) then element.Time:SetText() end
local sf = element.SafeZone
if(sf) then
sf:ClearAllPoints()
sf:SetPoint('LEFT')
sf:SetPoint('TOP')
sf:SetPoint('BOTTOM')
updateSafeZone(element)
end
--[[ Callback: Castbar:PostChannelStart(unit, name)
Called after the element has been updated upon a spell channel start.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the channeled spell (string)
--]]
if(element.PostChannelStart) then
element:PostChannelStart(unit, name)
end
element:Show()
end
local function UNIT_SPELLCAST_CHANNEL_UPDATE(self, event, unit)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
local name, _, _, _, startTime, endTime = UnitChannelInfo(unit)
if(not name or not element:IsShown()) then
return
end
local duration = (endTime / 1000) - GetTime()
element.delay = element.delay + element.duration - duration
element.duration = duration
element.max = (endTime - startTime) / 1000
element.startTime = startTime / 1000
element.endTime = endTime / 1000
element:SetMinMaxValues(0, element.max)
element:SetValue(duration)
--[[ Callback: Castbar:PostChannelUpdate(unit, name)
Called after the element has been updated after a channeled spell has been delayed or interrupted.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the channeled spell (string)
--]]
if(element.PostChannelUpdate) then
return element:PostChannelUpdate(unit, name)
end
end
local function UNIT_SPELLCAST_CHANNEL_STOP(self, event, unit, spellname)
if(self.unit ~= unit and self.realUnit ~= unit) then return end
local element = self.Castbar
if(element:IsShown()) then
element.channeling = nil
--[[ Callback: Castbar:PostChannelUpdate(unit, name)
Called after the element has been updated after a channeled spell has been completed.
* self - the Castbar widget
* unit - unit for which the update has been triggered (string)
* name - name of the channeled spell (string)
--]]
if(element.PostChannelStop) then
return element:PostChannelStop(unit, spellname)
end
end
end
local function onUpdate(self, elapsed)
if(self.casting) then
local duration = self.duration + elapsed
if(duration >= self.max or (tradeskillTotal > 1 and duration >= (tradeskillCastDuration + tradeskillCastTime * 1.25))) then
self.casting = nil
self:Hide()
tradeskillTotal = 0
if(self.PostCastStop) then self:PostCastStop(self.__owner.unit) end
return
end
if(self.Time) then
if(self.delay ~= 0) then
if(self.CustomDelayText) then
self:CustomDelayText(duration)
else
self.Time:SetFormattedText('%.1f|cffff0000-%.1f|r', duration, self.delay)
end
else
if(self.CustomTimeText) then
self:CustomTimeText(duration)
else
self.Time:SetFormattedText('%.1f', duration)
end
end
end
self.duration = duration
self:SetValue(duration)
if(self.Spark) then
self.Spark:SetPoint('CENTER', self, 'LEFT', (duration / self.max) * self:GetWidth(), 0)
end
elseif(self.channeling) then
local duration = self.duration - elapsed
if(duration <= 0) then
self.channeling = nil
self:Hide()
if(self.PostChannelStop) then self:PostChannelStop(self.__owner.unit) end
return
end
if(self.Time) then
if(self.delay ~= 0) then
if(self.CustomDelayText) then
self:CustomDelayText(duration)
else
self.Time:SetFormattedText('%.1f|cffff0000-%.1f|r', duration, self.delay)
end
else
if(self.CustomTimeText) then
self:CustomTimeText(duration)
else
self.Time:SetFormattedText('%.1f', duration)
end
end
end
self.duration = duration
self:SetValue(duration)
if(self.Spark) then
self.Spark:SetPoint('CENTER', self, 'LEFT', (duration / self.max) * self:GetWidth(), 0)
end
elseif(self.holdTime > 0) then
self.holdTime = self.holdTime - elapsed
else
self.casting = nil
self.castName = nil
self.channeling = nil
tradeskillTotal = 0
self:Hide()
end
end
local function Update(self, ...)
UNIT_SPELLCAST_START(self, ...)
return UNIT_SPELLCAST_CHANNEL_START(self, ...)
end
local function ForceUpdate(element)
return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self, unit)
local element = self.Castbar
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
if(not (unit and unit:match('%wtarget$'))) then
self:RegisterEvent('UNIT_SPELLCAST_START', UNIT_SPELLCAST_START)
self:RegisterEvent('UNIT_SPELLCAST_FAILED', UNIT_SPELLCAST_FAILED)
self:RegisterEvent('UNIT_SPELLCAST_STOP', UNIT_SPELLCAST_STOP)
self:RegisterEvent('UNIT_SPELLCAST_INTERRUPTED', UNIT_SPELLCAST_INTERRUPTED)
self:RegisterEvent('UNIT_SPELLCAST_DELAYED', UNIT_SPELLCAST_DELAYED)
self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_START', UNIT_SPELLCAST_CHANNEL_START)
self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_UPDATE', UNIT_SPELLCAST_CHANNEL_UPDATE)
self:RegisterEvent('UNIT_SPELLCAST_CHANNEL_STOP', UNIT_SPELLCAST_CHANNEL_STOP)
self:RegisterEvent('UNIT_SPELLCAST_SENT', UNIT_SPELLCAST_SENT, true)
self:RegisterEvent('UNIT_SPELLCAST_FAILED_QUIET', UNIT_SPELLCAST_FAILED_QUIET)
end
element.holdTime = 0
element:SetScript('OnUpdate', element.OnUpdate or onUpdate)
if(self.unit == 'player') then
CastingBarFrame:UnregisterAllEvents()
CastingBarFrame.Show = CastingBarFrame.Hide
CastingBarFrame:Hide()
PetCastingBarFrame:UnregisterAllEvents()
PetCastingBarFrame.Show = PetCastingBarFrame.Hide
PetCastingBarFrame:Hide()
end
if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then
element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
local spark = element.Spark
if(spark and spark:IsObjectType('Texture') and not spark:GetTexture()) then
spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
end
local safeZone = element.SafeZone
if(safeZone and safeZone:IsObjectType('Texture') and not safeZone:GetTexture()) then
safeZone:SetTexture(1, 0, 0)
end
element:Hide()
return true
end
end
local function Disable(self)
local element = self.Castbar
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_SPELLCAST_START', UNIT_SPELLCAST_START)
self:UnregisterEvent('UNIT_SPELLCAST_FAILED', UNIT_SPELLCAST_FAILED)
self:UnregisterEvent('UNIT_SPELLCAST_STOP', UNIT_SPELLCAST_STOP)
self:UnregisterEvent('UNIT_SPELLCAST_INTERRUPTED', UNIT_SPELLCAST_INTERRUPTED)
self:UnregisterEvent('UNIT_SPELLCAST_DELAYED', UNIT_SPELLCAST_DELAYED)
self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_START', UNIT_SPELLCAST_CHANNEL_START)
self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_UPDATE', UNIT_SPELLCAST_CHANNEL_UPDATE)
self:UnregisterEvent('UNIT_SPELLCAST_CHANNEL_STOP', UNIT_SPELLCAST_CHANNEL_STOP)
self:UnregisterEvent('UNIT_SPELLCAST_SENT', UNIT_SPELLCAST_SENT)
self:UnregisterEvent('UNIT_SPELLCAST_FAILED_QUIET', UNIT_SPELLCAST_FAILED_QUIET)
element:SetScript('OnUpdate', nil)
end
end
hooksecurefunc('DoTradeSkill', function(_, num)
tradeskillCastTime = 0
tradeskillCastDuration = 0
tradeskillCurrent = 0
tradeskillTotal = num or 1
mergeTradeskill = true
end)
oUF:AddElement('Castbar', Update, Enable, Disable)
@@ -0,0 +1,102 @@
--[[
# Element: Combat Indicator
Toggles the visibility of an indicator based on the player's combat status.
## Widget
CombatIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local CombatIndicator = self:CreateTexture(nil, 'OVERLAY')
CombatIndicator:SetSize(16, 16)
CombatIndicator:SetPoint('TOP', self)
-- Register it with oUF
self.CombatIndicator = CombatIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local UnitAffectingCombat = UnitAffectingCombat
local function Update(self, event)
local element = self.CombatIndicator
--[[ Callback: CombatIndicator:PreUpdate()
Called before the element has been updated.
* self - the CombatIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local inCombat = UnitAffectingCombat('player')
if(inCombat) then
element:Show()
else
element:Hide()
end
--[[ Callback: CombatIndicator:PostUpdate(inCombat)
Called after the element has been updated.
* self - the CombatIndicator element
* inCombat - indicates if the player is affecting combat (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(inCombat)
end
end
local function Path(self, ...)
--[[ Override: CombatIndicator.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.CombatIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.CombatIndicator
if(element and unit == 'player') then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PLAYER_REGEN_DISABLED', Path)
self:RegisterEvent('PLAYER_REGEN_ENABLED', Path)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\CharacterFrame\UI-StateIcon]])
element:SetTexCoord(.5, 1, 0, .49)
end
return true
end
end
local function Disable(self)
local element = self.CombatIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PLAYER_REGEN_DISABLED', Path)
self:UnregisterEvent('PLAYER_REGEN_ENABLED', Path)
end
end
oUF:AddElement('CombatIndicator', Path, Enable, Disable)
@@ -0,0 +1,118 @@
--[[
# Element: ComboPoints
Handles the visibility and updating of the player's combo points.
## Widget
ComboPoints - An `table` consisting of as many Textures as the theoretical maximum return of [GetComboPoints](http://wowprogramming.com/docs/api/GetComboPoints).
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
local ComboPoints = {}
for index = 1, 10 do
local Bar = CreateFrame('StatusBar', nil, self)
-- Position and size.
Bar:SetSize(16, 16)
Bar:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', (index - 1) * Bar:GetWidth(), 0)
ComboPoints[index] = Bar
end
-- Register with oUF
self.ComboPoints = ComboPoints
--]]
local ns = oUF
local oUF = ns.oUF
local GetComboPoints = GetComboPoints
local MAX_COMBO_POINTS = MAX_COMBO_POINTS
local function Update(self, event)
local element = self.ComboPoints
--[[ Callback: ComboPoints:PreUpdate()
Called before the element has been updated.
* self - the ComboPoints element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local cp = GetComboPoints('player', 'target')
for i = 1, MAX_COMBO_POINTS do
if(i <= cp) then
element[i]:Show()
else
element[i]:Hide()
end
end
--[[ Callback: ComboPoints:PostUpdate(role)
Called after the element has been updated.
* self - the ComboPoints element
* cpoint - the current amount of combo points (number)
--]]
if(element.PostUpdate) then
return element:PostUpdate(cp)
end
end
local function Path(self, ...)
--[[ Override: ComboPoints.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.ComboPoints.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.ComboPoints
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PLAYER_COMBO_POINTS', Path, true)
self:RegisterEvent('PLAYER_TARGET_CHANGED', Path, true)
for index = 1, MAX_COMBO_POINTS do
local cp = element[index]
if(cp:IsObjectType('Texture') and not cp:GetTexture()) then
cp:SetTexture([[Interface\ComboFrame\ComboPoint]])
cp:SetTexCoord(0, 0.375, 0, 1)
end
end
return true
end
end
local function Disable(self)
local element = self.ComboPoints
if(element) then
for index = 1, MAX_COMBO_POINTS do
element[index]:Hide()
end
self:UnregisterEvent('PLAYER_COMBO_POINTS', Path)
self:UnregisterEvent('PLAYER_TARGET_CHANGED', Path)
end
end
oUF:AddElement('ComboPoints', Path, Enable, Disable)
@@ -0,0 +1,22 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="power.lua"/>
<!--<Script file="auras.lua"/>-->
<Script file="health.lua"/>
<!--<Script file="raidtargetindicator.lua"/>
<Script file="leaderindicator.lua"/>
<Script file="combatindicator.lua"/>
<Script file="restingindicator.lua"/>
<Script file="pvpindicator.lua"/>-->
<Script file="portrait.lua"/>
<!--
<Script file="range.lua"/>
<Script file="castbar.lua"/>-->
<Script file="tags.lua"/>
<!-- <Script file="masterlooterindicator.lua"/>
<Script file="assistantindicator.lua"/>
<Script file="readycheckindicator.lua"/>
<Script file="combopoints.lua"/>
<Script file="raidroleindicator.lua"/>
<Script file="happinessindicator.lua"/>
-->
</Ui>
@@ -0,0 +1,116 @@
--[[
# Element: HappinessIndicator
Handles the visibility and updating of player pet happiness.
## Widget
HappinessIndicator - A `Texture` used to display the current happiness level.
The element works by changing the texture's vertex color.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local HappinessIndicator = self:CreateTexture(nil, 'OVERLAY')
HappinessIndicator:SetSize(16, 16)
HappinessIndicator:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.HappinessIndicator = HappinessIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local GetPetHappiness = GetPetHappiness
local HasPetUI = HasPetUI
local function Update(self, event, unit)
if(not unit or self.unit ~= unit) then return end
local element = self.HappinessIndicator
--[[ Callback: HappinessIndicator:PreUpdate()
Called before the element has been updated.
* self - the ComboPoints element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local _, hunterPet = HasPetUI()
local happiness, damagePercentage = GetPetHappiness()
if(hunterPet and happiness) then
if(happiness == 1) then
element:SetTexCoord(0.375, 0.5625, 0, 0.359375)
elseif(happiness == 2) then
element:SetTexCoord(0.1875, 0.375, 0, 0.359375)
elseif(happiness == 3) then
element:SetTexCoord(0, 0.1875, 0, 0.359375)
end
element:Show()
else
return element:Hide()
end
--[[ Callback: HappinessIndicator:PostUpdate(role)
Called after the element has been updated.
* self - the ComboPoints element
* unit - the unit for which the update has been triggered (string)
* happiness - the numerical happiness value of the pet (1 = unhappy, 2 = content, 3 = happy) (number)
* damagePercentage - damage modifier, happiness affects this (unhappy = 75%, content = 100%, happy = 125%) (number)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, happiness, damagePercentage)
end
end
local function Path(self, ...)
--[[ Override: HappinessIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.HappinessIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.HappinessIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_HAPPINESS', Path)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\PetPaperDollFrame\UI-PetHappiness]])
end
return true
end
end
local function Disable(self)
local element = self.HappinessIndicator
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_HAPPINESS', Path)
end
end
oUF:AddElement('HappinessIndicator', Path, Enable, Disable)
@@ -0,0 +1,292 @@
--[[
# Element: Health Bar
Handles the updating of a status bar that displays the unit's health.
## Widget
Health - A `StatusBar` used to represent the unit's health.
## Sub-Widgets
.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
## Notes
A default texture will be applied if the widget is a StatusBar and doesn't have a texture set.
## Options
.frequentUpdates - Indicates whether to use OnUpdate script instead of UNIT_HEALTH to update the bar (boolean)
.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
The following options are listed by priority. The first check that returns true decides the color of the bar.
.colorTapping - Use `self.colors.tapping` to color the bar if the unit isn't tapped by the player (boolean)
.colorDisconnected - Use `self.colors.disconnected` to color the bar if the unit is offline (boolean)
.colorHappiness - Use `self.colors.happiness` to color the bar if the unit is pet based on pet happiness (boolean)
.colorClass - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass) (boolean)
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the unit is a NPC (boolean)
.colorClassPet - Use `self.colors.class[class]` to color the bar if the unit is player controlled, but not a player
(boolean)
.colorReaction - Use `self.colors.reaction[reaction]` to color the bar based on the player's reaction towards the
unit. `reaction` is defined by the return value of
[UnitReaction](http://wowprogramming.com/docs/api/UnitReaction) (boolean)
.colorSmooth - Use `smoothGradient` if present or `self.colors.smooth` to color the bar with a smooth gradient
based on the player's current health percentage (boolean)
.colorHealth - Use `self.colors.health` to color the bar. This flag is used to reset the bar color back to default
if none of the above conditions are met (boolean)
## Sub-Widgets Options
.multiplier - Used to tint the background based on the main widgets R, G and B values. Defaults to 1 (number)[0-1]
## Attributes
.disconnected - Indicates whether the unit is disconnected (boolean)
## Examples
-- Position and size
local Health = CreateFrame('StatusBar', nil, self)
Health:SetHeight(20)
Health:SetPoint('TOP')
Health:SetPoint('LEFT')
Health:SetPoint('RIGHT')
-- Add a background
local Background = Health:CreateTexture(nil, 'BACKGROUND')
Background:SetAllPoints(Health)
Background:SetTexture(1, 1, 1, .5)
-- Options
Health.frequentUpdates = true
Health.colorTapping = true
Health.colorDisconnected = true
Health.colorClass = true
Health.colorReaction = true
Health.colorHealth = true
-- Make the background darker.
Background.multiplier = .5
-- Register it with oUF
Health.bg = Background
self.Health = Health
--]]
local ns = oUF
local oUF = ns.oUF
local unpack = unpack
local GetPetHappiness = GetPetHappiness
local UnitClass = UnitClass
local UnitHealth = UnitHealth
local UnitHealthMax = UnitHealthMax
local UnitIsConnected = UnitIsConnected
local UnitIsPlayer = UnitIsPlayer
local UnitIsTapped = UnitIsTapped
local UnitIsTappedByPlayer = UnitIsTappedByPlayer
local UnitIsUnit = UnitIsUnit
local UnitPlayerControlled = UnitPlayerControlled
local UnitReaction = UnitReaction
local updateFrequentUpdates
local function UpdateColor(element, unit, cur, max)
local parent = element.__owner
if element.frequentUpdates ~= element.__frequentUpdates then
element.__frequentUpdates = element.frequentUpdates
updateFrequentUpdates(parent, unit)
end
local r, g, b, t
if(element.colorTapping and not UnitPlayerControlled(unit) and (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit))) then
t = parent.colors.tapped
elseif(element.colorDisconnected and element.disconnected) then
t = parent.colors.disconnected
elseif(element.colorHappiness and UnitIsUnit(unit, 'pet') and GetPetHappiness()) then
t = parent.colors.happiness[GetPetHappiness()]
elseif(element.colorClass and UnitIsPlayer(unit)) or
(element.colorClassNPC and not UnitIsPlayer(unit)) or
(element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
local _, class = UnitClass(unit)
t = parent.colors.class[class]
elseif(element.colorReaction and UnitReaction(unit, 'player')) then
t = parent.colors.reaction[UnitReaction(unit, 'player')]
elseif(element.colorSmooth) then
r, g, b = parent.ColorGradient(cur, max, unpack(element.smoothGradient or parent.colors.smooth))
elseif(element.colorHealth) then
t = parent.colors.health
end
if(t) then
r, g, b = t[1], t[2], t[3]
end
if(r or g or b) then
element:SetStatusBarColor(r, g, b)
local bg = element.bg
if(bg) then
local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
end
end
local function Update(self, event, unit)
if(not unit or self.unit ~= unit) then return end
local element = self.Health
--[[ Callback: Health:PreUpdate(unit)
Called before the element has been updated.
* self - the Health element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local cur, max = UnitHealth(unit), UnitHealthMax(unit)
local disconnected = not UnitIsConnected(unit)
element:SetMinMaxValues(0, max)
if(disconnected) then
element:SetValue(max)
else
element:SetValue(cur)
end
element.disconnected = disconnected
--[[ Override: Health:UpdateColor(unit, cur, max)
Used to completely override the internal function for updating the widgets' colors.
* self - the Health element
* unit - the unit for which the update has been triggered (string)
* cur - the unit's current health value (number)
* max - the unit's maximum possible health value (number)
--]]
element:UpdateColor(unit, cur, max)
--[[ Callback: Health:PostUpdate(unit, cur, max)
Called after the element has been updated.
* self - the Health element
* unit - the unit for which the update has been triggered (string)
* cur - the unit's current health value (number)
* max - the unit's maximum possible health value (number)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, cur, max)
end
end
local function Path(self, ...)
--[[ Override: Health.Override(self, event, unit)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
return (self.Health.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function onHealthUpdate()
if(this.disconnected) then return end
local unit = this.__owner.unit
local health = UnitHealth(unit)
if(health ~= this.min) then
this.min = health
return Path(this.__owner, 'OnHealthUpdate', unit)
end
end
function updateFrequentUpdates(self, unit)
if(not unit or string.match(unit, '%w+target$')) then return end
local element = self.Health
if(element.frequentUpdates and not element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', onHealthUpdate)
if((unit == 'party' or string.match(unit, 'party%d?$'))) then
self:RegisterEvent('UNIT_HEALTH', Path)
elseif(self:IsEventRegistered("UNIT_HEALTH")) then
self:UnregisterEvent('UNIT_HEALTH', Path)
end
elseif(not element.frequentUpdates and element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', nil)
self:RegisterEvent('UNIT_HEALTH', Path)
end
end
local function Enable(self, unit)
local element = self.Health
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element.__frequentUpdates = element.frequentUpdates
updateFrequentUpdates(self, unit)
if(element.frequentUpdates and (unit and not string.match(unit, '%w+target$'))) then
element:SetScript('OnUpdate', onHealthUpdate)
-- The party frames need this to handle disconnect states correctly.
if(unit == 'party') then
self:RegisterEvent('UNIT_HEALTH', Path)
end
else
self:RegisterEvent('UNIT_HEALTH', Path)
end
self:RegisterEvent('UNIT_MAXHEALTH', Path)
self:RegisterEvent('UNIT_CONNECTION', Path)
self:RegisterEvent('UNIT_FACTION', Path) -- For tapping
self:RegisterEvent('UNIT_HAPPINESS', Path)
if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then
element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
end
if(not element.UpdateColor) then
element.UpdateColor = UpdateColor
end
element:Show()
return true
end
end
local function Disable(self)
local element = self.Health
if(element) then
if(element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', nil)
end
element:Hide()
self:UnregisterEvent('UNIT_HEALTH', Path)
self:UnregisterEvent('UNIT_MAXHEALTH', Path)
self:UnregisterEvent('UNIT_CONNECTION', Path)
self:UnregisterEvent('UNIT_FACTION', Path)
self:UnregisterEvent('UNIT_HAPPINESS', Path)
end
end
oUF:AddElement('Health', Path, Enable, Disable)
@@ -0,0 +1,107 @@
--[[
# Element: Leader Indicator
Toggles the visibility of an indicator based on the unit's leader status.
## Widget
LeaderIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local LeaderIndicator = self:CreateTexture(nil, 'OVERLAY')
LeaderIndicator:SetSize(16, 16)
LeaderIndicator:SetPoint('BOTTOM', self, 'TOP')
-- Register it with oUF
self.LeaderIndicator = LeaderIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local UnitInParty = UnitInParty
local UnitInRaid = UnitInRaid
local UnitIsPartyLeader = UnitIsPartyLeader
local function Update(self, event)
local element = self.LeaderIndicator
--[[ Callback: LeaderIndicator:PreUpdate()
Called before the element has been updated.
* self - the LeaderIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local unit = self.unit
local isLeader = (UnitInParty(unit) or UnitInRaid(unit)) and UnitIsPartyLeader(unit)
if(isLeader) then
element:Show()
else
element:Hide()
end
--[[ Callback: LeaderIndicator:PostUpdate(isLeader)
Called after the element has been updated.
* self - the LeaderIndicator element
* isLeader - indicates whether the element is shown (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isLeader)
end
end
local function Path(self, ...)
--[[ Override: LeaderIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.LeaderIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.LeaderIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PARTY_LEADER_CHANGED', Path)
self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path)
self:RegisterEvent('RAID_ROSTER_UPDATE', Path)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\GroupFrame\UI-Group-LeaderIcon]])
end
return true
end
end
local function Disable(self)
local element = self.LeaderIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PARTY_LEADER_CHANGED', Path)
self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
self:UnregisterEvent('RAID_ROSTER_UPDATE', Path)
end
end
oUF:AddElement('LeaderIndicator', Path, Enable, Disable)
@@ -0,0 +1,126 @@
--[[
# Element: Master Looter Indicator
Toggles the visibility of an indicator based on the unit's master looter status.
## Widget
MasterLooterIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local MasterLooterIndicator = self:CreateTexture(nil, 'OVERLAY')
MasterLooterIndicator:SetSize(16, 16)
MasterLooterIndicator:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.MasterLooterIndicator = MasterLooterIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local GetLootMethod = GetLootMethod
local UnitInParty = UnitInParty
local UnitInRaid = UnitInRaid
local UnitIsUnit = UnitIsUnit
local function Update(self, event)
local unit = self.unit
local element = self.MasterLooterIndicator
--[[ Callback: MasterLooterIndicator:PreUpdate()
Called before the element has been updated.
* self - the MasterLooterIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local isShown = false
if(UnitInParty(unit) or UnitInRaid(unit)) then
local method, partyIndex, raidIndex = GetLootMethod()
if(method == 'master') then
local mlUnit
if(partyIndex) then
if(partyIndex == 0) then
mlUnit = 'player'
else
mlUnit = 'party' .. partyIndex
end
elseif(raidIndex) then
mlUnit = 'raid' .. raidIndex
end
if(mlUnit and UnitIsUnit(unit, mlUnit)) then
isShown = true
end
end
end
if isShown then
element:Show()
else
element:Hide()
end
--[[ Callback: MasterLooterIndicator:PostUpdate(isShown)
Called after the element has been updated.
* self - the MasterLooterIndicator element
* isShown - indicates whether the element is shown (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isShown)
end
end
local function Path(self, ...)
--[[ Override: MasterLooterIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.MasterLooterIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.MasterLooterIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PARTY_LOOT_METHOD_CHANGED', Path, true)
self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path, true)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\GroupFrame\UI-Group-MasterLooter]])
end
return true
end
end
local function Disable(self)
local element = self.MasterLooterIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PARTY_LOOT_METHOD_CHANGED', Path)
self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
end
end
oUF:AddElement('MasterLooterIndicator', Path, Enable, Disable)
@@ -0,0 +1,148 @@
--[[
# Element: Portraits
Handles the updating of the unit's portrait.
## Widget
Portrait - A `PlayerModel` or a `Texture` used to represent the unit's portrait.
## Notes
A question mark model will be used if the widget is a PlayerModel and the client doesn't have the model information for
the unit.
## Examples
-- 3D Portrait
-- Position and size
local Portrait = CreateFrame('PlayerModel', nil, self)
Portrait:SetSize(32, 32)
Portrait:SetPoint('RIGHT', self, 'LEFT')
-- Register it with oUF
self.Portrait = Portrait
-- 2D Portrait
local Portrait = self:CreateTexture(nil, 'OVERLAY')
Portrait:SetSize(32, 32)
Portrait:SetPoint('RIGHT', self, 'LEFT')
-- Register it with oUF
self.Portrait = Portrait
--]]
local ns = oUF
local oUF = ns.oUF
local SetPortraitTexture = SetPortraitTexture
local UnitExists = UnitExists
local UnitName = UnitName
local UnitIsConnected = UnitIsConnected
local UnitIsUnit = UnitIsUnit
local UnitIsVisible = UnitIsVisible
local function Update(self, event, unit)
if(not unit or not UnitIsUnit(self.unit, unit)) then return end
local element = self.Portrait
--[[ Callback: Portrait:PreUpdate(unit)
Called before the element has been updated.
* self - the Portrait element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then element:PreUpdate(unit) end
local name = UnitName(unit)
local isAvailable = UnitIsConnected(unit) and UnitIsVisible(unit)
if(event ~= 'OnUpdate' or element.name ~= name or element.state ~= isAvailable) then
if(element:IsObjectType('PlayerModel')) then
if(not isAvailable) then
element:SetModelScale(4.25)
element:SetCamera(0)
element:SetPosition(0, 0, -1.5)
element:SetModel([[Interface\Buttons\TalkToMeQuestionMark.m2]])
elseif(element.name ~= name or event == 'UNIT_MODEL_CHANGED') then
element:ClearModel()
element:SetUnit(unit)
element:SetModelScale(1)
element:SetCamera(0)
element:SetPosition(0, 0, 0)
else
element:SetCamera(0)
end
else
SetPortraitTexture(element, unit)
end
element.name = name
element.state = isAvailable
end
--[[ Callback: Portrait:PostUpdate(unit)
Called after the element has been updated.
* self - the Portrait element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit)
end
end
local function Path(self, ...)
--[[ Override: Portrait.Override(self, event, unit)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
--]]
return (self.Portrait.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self, unit)
local element = self.Portrait
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_PORTRAIT_UPDATE', Path)
self:RegisterEvent('UNIT_MODEL_CHANGED', Path)
self:RegisterEvent('UNIT_CONNECTION', Path)
-- The quest log uses PARTY_MEMBER_{ENABLE,DISABLE} to handle updating of
-- party members overlapping quests. This will probably be enough to handle
-- model updating.
--
-- DISABLE isn't used as it fires when we most likely don't have the
-- information we want.
if(unit == 'party') then
self:RegisterEvent('PARTY_MEMBER_ENABLE', Path)
end
element:Show()
return true
end
end
local function Disable(self)
local element = self.Portrait
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_PORTRAIT_UPDATE', Path)
self:UnregisterEvent('UNIT_MODEL_CHANGED', Path)
self:UnregisterEvent('PARTY_MEMBER_ENABLE', Path)
self:UnregisterEvent('UNIT_CONNECTION', Path)
end
end
oUF:AddElement('Portrait', Path, Enable, Disable)
@@ -0,0 +1,326 @@
--[[
# Element: Power Bar
Handles the updating of a status bar that displays the unit's power.
## Widget
Power - A `StatusBar` used to represent the unit's power.
## Sub-Widgets
.bg - A `Texture` used as a background. It will inherit the color of the main StatusBar.
## Notes
A default texture will be applied if the widget is a StatusBar and doesn't have a texture or a color set.
## Options
.frequentUpdates - Indicates whether to use OnUpdate script instead of UNIT_POWER to update the bar. Only valid for the
player and pet units (boolean)
.smoothGradient - 9 color values to be used with the .colorSmooth option (table)
The following options are listed by priority. The first check that returns true decides the color of the bar.
.colorTapping - Use `self.colors.tapping` to color the bar if the unit isn't tapped by the player (boolean)
.colorDisconnected - Use `self.colors.disconnected` to color the bar if the unit is offline (boolean)
.colorHappiness - Use `self.colors.happiness` to color the bar if the unit is pet based on pet happiness (boolean)
.colorPower - Use `self.colors.power[token]` to color the bar based on the unit's power type. This method will
fall-back to `:GetAlternativeColor()` if it can't find a color matching the token. If this function
isn't defined, then it will attempt to color based upon the alternative power colors returned by
[UnitPowerType](http://wowprogramming.com/docs/api/UnitPowerType). Finally, if these aren't
defined, then it will attempt to color the bar based upon `self.colors.power[type]` (boolean)
.colorClass - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass) (boolean)
.colorClassNPC - Use `self.colors.class[class]` to color the bar if the unit is a NPC (boolean)
.colorClassPet - Use `self.colors.class[class]` to color the bar if the unit is player controlled, but not a player
(boolean)
.colorReaction - Use `self.colors.reaction[reaction]` to color the bar based on the player's reaction towards the
unit. `reaction` is defined by the return value of
[UnitReaction](http://wowprogramming.com/docs/api/UnitReaction) (boolean)
.colorSmooth - Use `smoothGradient` if present or `self.colors.smooth` to color the bar with a smooth gradient
based on the player's current power percentage (boolean)
## Sub-Widget Options
.multiplier - A multiplier used to tint the background based on the main widgets R, G and B values. Defaults to 1
(number)[0-1]
## Attributes
.disconnected - Indicates whether the unit is disconnected (boolean)
.tapped - Indicates whether the unit is tapped by the player (boolean)
## Examples
-- Position and size
local Power = CreateFrame('StatusBar', nil, self)
Power:SetHeight(20)
Power:SetPoint('BOTTOM')
Power:SetPoint('LEFT')
Power:SetPoint('RIGHT')
-- Add a background
local Background = Power:CreateTexture(nil, 'BACKGROUND')
Background:SetAllPoints(Power)
Background:SetTexture(1, 1, 1, .5)
-- Options
Power.frequentUpdates = true
Power.colorTapping = true
Power.colorDisconnected = true
Power.colorPower = true
Power.colorClass = true
Power.colorReaction = true
-- Make the background darker.
Background.multiplier = .5
-- Register it with oUF
Power.bg = Background
self.Power = Power
--]]
local ns = oUF
local oUF = ns.oUF
local unpack = unpack
local GetPetHappiness = GetPetHappiness
local UnitClass = UnitClass
local UnitIsConnected = UnitIsConnected
local UnitIsPlayer = UnitIsPlayer
local UnitIsTapped = UnitIsTapped
local UnitIsTappedByPlayer = UnitIsTappedByPlayer
local UnitIsUnit = UnitIsUnit
local UnitMana = UnitMana
local UnitManaMax = UnitManaMax
local UnitPlayerControlled = UnitPlayerControlled
local UnitPowerType = UnitPowerType
local UnitReaction = UnitReaction
local updateFrequentUpdates
local function UpdateColor(element, unit, cur, min, max)
local parent = element.__owner
if element.frequentUpdates ~= element.__frequentUpdates then
element.__frequentUpdates = element.frequentUpdates
updateFrequentUpdates(element, unit)
end
local ptype = UnitPowerType(unit)
local r, g, b, t
if(element.colorTapping and element.tapped) then
t = parent.colors.tapped
elseif(element.colorDisconnected and element.disconnected) then
t = parent.colors.disconnected
elseif(element.colorHappiness and UnitIsUnit(unit, 'pet') and GetPetHappiness()) then
t = parent.colors.happiness[GetPetHappiness()]
elseif(element.colorPower) then
t = parent.colors.power[ptype]
elseif(element.colorClass and UnitIsPlayer(unit)) or
(element.colorClassNPC and not UnitIsPlayer(unit)) or
(element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
local _, class = UnitClass(unit)
t = parent.colors.class[class]
elseif(element.colorReaction and UnitReaction(unit, 'player')) then
t = parent.colors.reaction[UnitReaction(unit, 'player')]
elseif(element.colorSmooth) then
local adjust = 0 - (min or 0)
r, g, b = parent.ColorGradient(cur + adjust, max + adjust, unpack(element.smoothGradient or parent.colors.smooth))
end
if(t) then
r, g, b = t[1], t[2], t[3]
end
t = parent.colors.power[ptype]
element:SetStatusBarTexture(element.texture)
if(r or g or b) then
element:SetStatusBarColor(r, g, b)
end
local bg = element.bg
if(bg and b) then
local mu = bg.multiplier or 1
bg:SetVertexColor(r * mu, g * mu, b * mu)
end
end
local function Update(self, event, unit)
if(self.unit ~= unit) then return end
local element = self.Power
--[[ Callback: Power:PreUpdate(unit)
Called before the element has been updated.
* self - the Power element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local cur, max = UnitMana(unit), UnitManaMax(unit)
local disconnected = not UnitIsConnected(unit)
local tapped = not UnitPlayerControlled(unit) and (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit))
element:SetMinMaxValues(0, max)
if(disconnected) then
element:SetValue(max)
else
element:SetValue(cur)
end
element.disconnected = disconnected
element.tapped = tapped
--[[ Override: Power:UpdateColor(unit, cur, max)
Used to completely override the internal function for updating the widget's colors.
* self - the Power element
* unit - the unit for which the update has been triggered (string)
* cur - the unit's current power value (number)
* max - the unit's maximum possible power value (number)
--]]
element:UpdateColor(unit, cur, max)
--[[ Callback: Power:PostUpdate(unit, cur, max)
Called after the element has been updated.
* self - the Power element
* unit - the unit for which the update has been triggered (string)
* cur - the unit's current power value (number)
* max - the unit's maximum possible power value (number)
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, cur, max)
end
end
local function Path(self, ...)
--[[ Override: Power.Override(self, event, unit, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* unit - the unit accompanying the event (string)
* ... - the arguments accompanying the event
--]]
return (self.Power.Override or Update) (self, unpack(arg))
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function onPowerUpdate()
if(this.disconnected) then return end
local unit = this.__owner.unit
local power = UnitMana(unit)
if(power ~= this.min) then
this.min = power
return Path(this.__owner, 'OnPowerUpdate', unit)
end
end
function updateFrequentUpdates(self, unit)
if(not unit or (unit ~= 'player' and unit ~= 'pet')) then return end
local element = self.Power
if(element.frequentUpdates and not element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', onPowerUpdate)
self:UnregisterEvent('UNIT_MANA', Path)
self:UnregisterEvent('UNIT_RAGE', Path)
self:UnregisterEvent('UNIT_FOCUS', Path)
self:UnregisterEvent('UNIT_ENERGY', Path)
elseif(not element.frequentUpdates and element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', nil)
self:RegisterEvent('UNIT_MANA', Path)
self:RegisterEvent('UNIT_RAGE', Path)
self:RegisterEvent('UNIT_FOCUS', Path)
self:RegisterEvent('UNIT_ENERGY', Path)
end
end
local function Enable(self, unit)
local element = self.Power
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element.__frequentUpdates = element.frequentUpdates
updateFrequentUpdates(self, unit)
if(element.frequentUpdates and (unit == 'player' or unit == 'pet')) then
element:SetScript('OnUpdate', onPowerUpdate)
else
self:RegisterEvent('UNIT_MANA', Path)
self:RegisterEvent('UNIT_RAGE', Path)
self:RegisterEvent('UNIT_FOCUS', Path)
self:RegisterEvent('UNIT_ENERGY', Path)
end
self:RegisterEvent('UNIT_MAXMANA', Path)
self:RegisterEvent('UNIT_MAXRAGE', Path)
self:RegisterEvent('UNIT_MAXFOCUS', Path)
self:RegisterEvent('UNIT_MAXENERGY', Path)
self:RegisterEvent('UNIT_MAXRUNIC_POWER', Path)
self:RegisterEvent('UNIT_DISPLAYPOWER', Path)
self:RegisterEvent('UNIT_CONNECTION', Path)
self:RegisterEvent('UNIT_HAPPINESS', Path)
self:RegisterEvent('UNIT_FACTION', Path) -- For tapping
if(element:IsObjectType('StatusBar')) then
element.texture = element:GetStatusBarTexture() and element:GetStatusBarTexture():GetTexture() or [[Interface\TargetingFrame\UI-StatusBar]]
element:SetStatusBarTexture(element.texture)
end
if(not element.UpdateColor) then
element.UpdateColor = UpdateColor
end
element:Show()
return true
end
end
local function Disable(self)
local element = self.Power
if(element) then
element:Hide()
if(element:GetScript('OnUpdate')) then
element:SetScript('OnUpdate', nil)
else
self:UnregisterEvent('UNIT_MANA', Path)
self:UnregisterEvent('UNIT_RAGE', Path)
self:UnregisterEvent('UNIT_FOCUS', Path)
self:UnregisterEvent('UNIT_ENERGY', Path)
self:UnregisterEvent('UNIT_RUNIC_POWER', Path)
end
self:UnregisterEvent('UNIT_MAXMANA', Path)
self:UnregisterEvent('UNIT_MAXRAGE', Path)
self:UnregisterEvent('UNIT_MAXFOCUS', Path)
self:UnregisterEvent('UNIT_MAXENERGY', Path)
self:UnregisterEvent('UNIT_MAXRUNIC_POWER', Path)
self:UnregisterEvent('UNIT_DISPLAYPOWER', Path)
self:UnregisterEvent('UNIT_CONNECTION', Path)
self:UnregisterEvent('UNIT_HAPPINESS', Path)
self:UnregisterEvent('UNIT_FACTION', Path)
end
end
oUF:AddElement('Power', Path, Enable, Disable)
@@ -0,0 +1,118 @@
--[[
# Element: PvP Icon
Handles the visibility and updating of an indicator based on the unit's PvP status.
## Widget
PvPIndicator - A `Texture` used to display faction, FFA PvP status icon.
## Notes
This element updates by changing the texture.
## Examples
-- Position and size
local PvPIndicator = self:CreateTexture(nil, 'ARTWORK', nil, 1)
PvPIndicator:SetSize(30, 30)
PvPIndicator:SetPoint('RIGHT', self, 'LEFT')
-- Register it with oUF
self.PvPIndicator = PvPIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local UnitFactionGroup = UnitFactionGroup
local UnitIsPVP = UnitIsPVP
local UnitIsPVPFreeForAll = UnitIsPVPFreeForAll
local FFA_ICON = [[Interface\TargetingFrame\UI-PVP-FFA]]
local FACTION_ICON = [[Interface\TargetingFrame\UI-PVP-]]
local function Update(self, event, unit)
if(unit ~= self.unit) then return end
local element = self.PvPIndicator
--[[ Callback: PvPIndicator:PreUpdate(unit)
Called before the element has been updated.
* self - the PvPIndicator element
* unit - the unit for which the update has been triggered (string)
--]]
if(element.PreUpdate) then
element:PreUpdate(unit)
end
local status
local factionGroup = UnitFactionGroup(unit)
if(UnitIsPVPFreeForAll(unit)) then
element:SetTexture(FFA_ICON)
element:SetTexCoord(0, 0.65625, 0, 0.65625)
status = 'ffa'
elseif(factionGroup and factionGroup ~= 'Neutral' and UnitIsPVP(unit)) then
element:SetTexture(FACTION_ICON .. factionGroup)
element:SetTexCoord(0, 0.65625, 0, 0.65625)
status = factionGroup
end
if(status) then
element:Show()
else
element:Hide()
end
--[[ Callback: PvPIndicator:PostUpdate(unit, status)
Called after the element has been updated.
* self - the PvPIndicator element
* unit - the unit for which the update has been triggered (string)
* status - the unit's current PvP status or faction accounting for mercenary mode (string)['ffa', 'Alliance',
'Horde']
--]]
if(element.PostUpdate) then
return element:PostUpdate(unit, status)
end
end
local function Path(self, ...)
--[[Override: PvPIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.PvPIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.PvPIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('UNIT_FACTION', Path)
return true
end
end
local function Disable(self)
local element = self.PvPIndicator
if(element) then
element:Hide()
self:UnregisterEvent('UNIT_FACTION', Path)
end
end
oUF:AddElement('PvPIndicator', Path, Enable, Disable)
@@ -0,0 +1,114 @@
--[[
# Element: Raid Role Indicator
Handles the visibility and updating of an indicator based on the unit's raid assignment (main tank or main assist).
## Widget
RaidRoleIndicator - A `Texture` representing the unit's raid assignment.
## Notes
This element updates by changing the texture.
## Examples
-- Position and size
local RaidRoleIndicator = self:CreateTexture(nil, 'OVERLAY')
RaidRoleIndicator:SetSize(16, 16)
RaidRoleIndicator:SetPoint('TOPLEFT')
-- Register it with oUF
self.RaidRoleIndicator = RaidRoleIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local GetPartyAssignment = GetPartyAssignment
local UnitInRaid = UnitInRaid
local MAINTANK_ICON = [[Interface\GROUPFRAME\UI-GROUP-MAINTANKICON]]
local MAINASSIST_ICON = [[Interface\GROUPFRAME\UI-GROUP-MAINASSISTICON]]
local function Update(self, event)
local unit = self.unit
local element = self.RaidRoleIndicator
--[[ Callback: RaidRoleIndicator:PreUpdate()
Called before the element has been updated.
* self - the RaidRoleIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local role, isShown
if(UnitInRaid(unit)) then
if(GetPartyAssignment('MAINTANK', unit)) then
isShown = true
element:SetTexture(MAINTANK_ICON)
role = 'MAINTANK'
elseif(GetPartyAssignment('MAINASSIST', unit)) then
isShown = true
element:SetTexture(MAINASSIST_ICON)
role = 'MAINASSIST'
end
end
if isShown then
element:Show()
else
element:Hide()
end
--[[ Callback: RaidRoleIndicator:PostUpdate(role)
Called after the element has been updated.
* self - the RaidRoleIndicator element
* role - the unit's raid assignment (string?)['MAINTANK', 'MAINASSIST']
--]]
if(element.PostUpdate) then
return element:PostUpdate(role)
end
end
local function Path(self, ...)
--[[ Override: RaidRoleIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.RaidRoleIndicator.Override or Update)(self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.RaidRoleIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PARTY_MEMBERS_CHANGED', Path, true)
return true
end
end
local function Disable(self)
local element = self.RaidRoleIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Path)
end
end
oUF:AddElement('RaidRoleIndicator', Path, Enable, Disable)
@@ -0,0 +1,102 @@
--[[
# Element: Raid Target Indicator
Handles the visibility and updating of an indicator based on the unit's raid target assignment.
## Widget
RaidTargetIndicator - A `Texture` used to display the raid target icon.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture set.
## Examples
-- Position and size
local RaidTargetIndicator = self:CreateTexture(nil, 'OVERLAY')
RaidTargetIndicator:SetSize(16, 16)
RaidTargetIndicator:SetPoint('TOPRIGHT', self)
-- Register it with oUF
self.RaidTargetIndicator = RaidTargetIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local GetRaidTargetIndex = GetRaidTargetIndex
local SetRaidTargetIconTexture = SetRaidTargetIconTexture
local function Update(self, event)
local element = self.RaidTargetIndicator
--[[ Callback: RaidTargetIndicator:PreUpdate()
Called before the element has been updated.
* self - the RaidTargetIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local index = GetRaidTargetIndex(self.unit)
if(index) then
SetRaidTargetIconTexture(element, index)
element:Show()
else
element:Hide()
end
--[[ Callback: RaidTargetIndicator:PostUpdate(index)
Called after the element has been updated.
* self - the RaidTargetIndicator element
* index - the index of the raid target marker (number?)[1-8]
--]]
if(element.PostUpdate) then
return element:PostUpdate(index)
end
end
local function Path(self, ...)
--[[ Override: RaidTargetIndicator.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.RaidTargetIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
if(not element.__owner.unit) then return end
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self)
local element = self.RaidTargetIndicator
if(element) then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('RAID_TARGET_UPDATE', Path, true)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\TargetingFrame\UI-RaidTargetingIcons]])
end
return true
end
end
local function Disable(self)
local element = self.RaidTargetIndicator
if(element) then
element:Hide()
self:UnregisterEvent('RAID_TARGET_UPDATE', Path)
end
end
oUF:AddElement('RaidTargetIndicator', Path, Enable, Disable)
@@ -0,0 +1,137 @@
--[[
# Element: Range Fader
Changes the opacity of a unit frame based on whether the frame's unit is in the player's range.
## Widget
Range - A table containing opacity values.
## Notes
Offline units are handled as if they are in range.
## Options
.outsideAlpha - Opacity when the unit is out of range. Defaults to 0.55 (number)[0-1].
.insideAlpha - Opacity when the unit is within range. Defaults to 1 (number)[0-1].
## Examples
-- Register with oUF
self.Range = {
insideAlpha = 1,
outsideAlpha = 1/2,
}
--]]
local ns = oUF
local oUF = ns.oUF
local _FRAMES = {}
local OnRangeFrame
local UnitInRange, UnitIsConnected = UnitInRange, UnitIsConnected
local function Update(self, event)
local element = self.Range
local unit = self.unit
--[[ Callback: Range:PreUpdate()
Called before the element has been updated.
* self - the Range element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local inRange
local connected = UnitIsConnected(unit)
if(connected) then
inRange = UnitInRange(unit)
if(not inRange) then
self:SetAlpha(element.outsideAlpha)
else
self:SetAlpha(element.insideAlpha)
end
else
self:SetAlpha(element.insideAlpha)
end
--[[ Callback: Range:PostUpdate(object, inRange, isConnected)
Called after the element has been updated.
* self - the Range element
* object - the parent object
* inRange - indicates if the unit was within 40 yards of the player (boolean)
* isConnected - indicates if the unit is online (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(self, inRange, connected)
end
end
local function Path(self, ...)
--[[ Override: Range.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.Range.Override or Update) (self, ...)
end
-- Internal updating method
local timer = 0
local function OnRangeUpdate(_, elapsed)
timer = timer + elapsed
if(timer >= .20) then
for _, object in next, _FRAMES do
if(object:IsShown()) then
Path(object, 'OnUpdate')
end
end
timer = 0
end
end
local function Enable(self)
local element = self.Range
if(element) then
element.__owner = self
element.insideAlpha = element.insideAlpha or 1
element.outsideAlpha = element.outsideAlpha or 0.55
if(not OnRangeFrame) then
OnRangeFrame = CreateFrame('Frame')
OnRangeFrame:SetScript('OnUpdate', OnRangeUpdate)
end
table.insert(_FRAMES, self)
OnRangeFrame:Show()
return true
end
end
local function Disable(self)
local element = self.Range
if(element) then
for index, frame in next, _FRAMES do
if(frame == self) then
table.remove(_FRAMES, index)
break
end
end
self:SetAlpha(element.insideAlpha)
if(#_FRAMES == 0) then
OnRangeFrame:Hide()
end
end
end
oUF:AddElement('Range', nil, Enable, Disable)
@@ -0,0 +1,150 @@
--[[
# Element: Ready Check Indicator
Handles the visibility and updating of an indicator based on the unit's ready check status.
## Widget
ReadyCheckIndicator - A `Texture` representing ready check status.
## Notes
This element updates by changing the texture.
Default textures will be applied if the layout does not provide custom ones. See Options.
## Options
.finishedTime - For how many seconds the icon should stick after a check has completed. Defaults to 10 (number).
.fadeTime - For how many seconds the icon should fade away after the stick duration has completed. Defaults to
1.5 (number).
.readyTexture - Path to an alternate texture for the ready check 'ready' status.
.notReadyTexture - Path to an alternate texture for the ready check 'notready' status.
.waitingTexture - Path to an alternate texture for the ready check 'waiting' status.
## Attributes
.status - the unit's ready check status (string?)['ready', 'noready', 'waiting']
## Examples
-- Position and size
local ReadyCheckIndicator = self:CreateTexture(nil, 'OVERLAY')
ReadyCheckIndicator:SetSize(16, 16)
ReadyCheckIndicator:SetPoint('TOP')
-- Register with oUF
self.ReadyCheckIndicator = ReadyCheckIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local GetReadyCheckStatus = GetReadyCheckStatus
local UnitExists = UnitExists
local function OnFinished(self)
local element = self:GetParent()
element:Hide()
--[[ Callback: ReadyCheckIndicator:PostUpdateFadeOut()
Called after the element has been faded out.
* self - the ReadyCheckIndicator element
--]]
if(element.PostUpdateFadeOut) then
element:PostUpdateFadeOut()
end
end
local function Update(self, event)
local element = self.ReadyCheckIndicator
--[[ Callback: ReadyCheckIndicator:PreUpdate()
Called before the element has been updated.
* self - the ReadyCheckIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local unit = self.unit
local status = GetReadyCheckStatus(unit)
if(UnitExists(unit) and status) then
if(status == 'ready') then
element:SetTexture(element.readyTexture)
elseif(status == 'notready') then
element:SetTexture(element.notReadyTexture)
else
element:SetTexture(element.waitingTexture)
end
element.status = status
element:Show()
elseif(event ~= 'READY_CHECK_FINISHED') then
element.status = nil
element:Hide()
end
if(event == 'READY_CHECK_FINISHED') then
if(element.status == 'waiting') then
element:SetTexture(element.notReadyTexture)
end
end
--[[ Callback: ReadyCheckIndicator:PostUpdate(status)
Called after the element has been updated.
* self - the ReadyCheckIndicator element
* status - the unit's ready check status (string?)['ready', 'notready', 'waiting']
--]]
if(element.PostUpdate) then
return element:PostUpdate(status)
end
end
local function Path(self, ...)
--[[ Override: ReadyCheckIndicator.Override(self, event, ...)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
* ... - the arguments accompanying the event
--]]
return (self.ReadyCheckIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.ReadyCheckIndicator
if(element and (unit and (unit:sub(1, 5) == 'party' or unit:sub(1, 4) == 'raid'))) then
element.__owner = self
element.ForceUpdate = ForceUpdate
element.readyTexture = element.readyTexture or READY_CHECK_READY_TEXTURE
element.notReadyTexture = element.notReadyTexture or READY_CHECK_NOT_READY_TEXTURE
element.waitingTexture = element.waitingTexture or READY_CHECK_WAITING_TEXTURE
self:RegisterEvent('READY_CHECK', Path, true)
self:RegisterEvent('READY_CHECK_CONFIRM', Path, true)
self:RegisterEvent('READY_CHECK_FINISHED', Path, true)
return true
end
end
local function Disable(self)
local element = self.ReadyCheckIndicator
if(element) then
element:Hide()
self:UnregisterEvent('READY_CHECK', Path)
self:UnregisterEvent('READY_CHECK_CONFIRM', Path)
self:UnregisterEvent('READY_CHECK_FINISHED', Path)
end
end
oUF:AddElement('ReadyCheckIndicator', Path, Enable, Disable)
@@ -0,0 +1,100 @@
--[[
# Element: Resting Indicator
Toggles the visibility of an indicator based on the player's resting status.
## Widget
RestingIndicator - Any UI widget.
## Notes
A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
## Examples
-- Position and size
local RestingIndicator = self:CreateTexture(nil, 'OVERLAY')
RestingIndicator:SetSize(16, 16)
RestingIndicator:SetPoint('TOPLEFT', self)
-- Register it with oUF
self.RestingIndicator = RestingIndicator
--]]
local ns = oUF
local oUF = ns.oUF
local IsResting = IsResting
local function Update(self, event)
local element = self.RestingIndicator
--[[ Callback: RestingIndicator:PreUpdate()
Called before the element has been updated.
* self - the RestingIndicator element
--]]
if(element.PreUpdate) then
element:PreUpdate()
end
local isResting = IsResting()
if(isResting) then
element:Show()
else
element:Hide()
end
--[[ Callback: RestingIndicator:PostUpdate(isResting)
Called after the element has been updated.
* self - the RestingIndicator element
* isResting - indicates if the player is resting (boolean)
--]]
if(element.PostUpdate) then
return element:PostUpdate(isResting)
end
end
local function Path(self, ...)
--[[ Override: RestingIndicator.Override(self, event)
Used to completely override the internal update function.
* self - the parent object
* event - the event triggering the update (string)
--]]
return (self.RestingIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate')
end
local function Enable(self, unit)
local element = self.RestingIndicator
if(element and unit == 'player') then
element.__owner = self
element.ForceUpdate = ForceUpdate
self:RegisterEvent('PLAYER_UPDATE_RESTING', Path, true)
if(element:IsObjectType('Texture') and not element:GetTexture()) then
element:SetTexture([[Interface\CharacterFrame\UI-StateIcon]])
element:SetTexCoord(0, 0.5, 0, 0.421875)
end
return true
end
end
local function Disable(self)
local element = self.RestingIndicator
if(element) then
element:Hide()
self:UnregisterEvent('PLAYER_UPDATE_RESTING', Path)
end
end
oUF:AddElement('RestingIndicator', Path, Enable, Disable)
@@ -0,0 +1,828 @@
-- Credits: Vika, Cladhaire, Tekkub
--[[
# Element: Tags
Provides a system for text-based display of information by binding a tag string to a font string widget which in turn is
tied to a unit frame.
## Widget
A FontString to hold a tag string. Unlike other elements, this widget must not have a preset name.
## Notes
A `Tag` is a Lua string consisting of a function name surrounded by square brackets. The tag will be replaced by the
output of the function and displayed as text on the font string widget with that the tag has been registered. Literals
can be pre- or appended by separating them with a `>` before or `<` after the function name. The literals will be only
displayed when the function returns a non-nil value. I.e. `"[perhp<%]"` will display the current health as a percentage
of the maximum health followed by the % sign.
A `Tag String` is a Lua string consisting of one or multiple tags with optional literals between them. Each tag will be
updated individually and the output will follow the tags order. Literals will be displayed in the output string
regardless of whether the surrounding tag functions return a value. I.e. `"[curhp]/[maxhp]"` will resolve to something
like `2453/5000`.
A `Tag Function` is used to replace a single tag in a tag string by its output. A tag function receives only two
arguments - the unit and the realUnit of the unit frame used to register the tag (see Options for further details). The
tag function is called when the unit frame is shown or when a specified event has fired. It the tag is registered on an
eventless frame (i.e. one holding the unit "targettarget"), then the tag function is called in a set time interval.
A number of built-in tag functions exist. The layout can also define its own tag functions by adding them to the
`oUF.Tags.Methods` table. The events upon which the function will be called are specified in a white-space separated
list added to the `oUF.Tags.Events` table. Should an event fire without unit information, then it should also be listed
in the `oUF.Tags.SharedEvents` table as follows: `oUF.Tags.SharedEvents.EVENT_NAME = true`.
## Options
.overrideUnit - if specified on the font string widget, the frame's realUnit will be passed as the second argument to
every tag function whose name is contained in the relevant tag string. Otherwise the second argument
is always nil (boolean)
.frequentUpdates - defines how often the correspondig tag function(s) should be called. This will override the events for
the tag(s), if any. If the value is a number, it is taken as a time interval in seconds. If the value
is a boolean, the time interval is set to 0.5 seconds (number or boolean)
## Attributes
.parent - the unit frame on which the tag has been registered
## Examples
-- define the tag function
oUF.Tags.Methods['mylayout:threatname'] = function(unit, realUnit)
local color = _TAGS['threatcolor'](unit)
local name = _TAGS['name'](unit, realUnit)
return string.format('%s%s|r', color, name)
end
-- add the events
oUF.Tags.Events['mylayout:threatname'] = 'UNIT_NAME_UPDATE UNIT_THREAT_SITUATION_UPDATE'
-- create the text widget
local info = self.Health:CreateFontString(nil, 'OVERLAY', 'GameFontNormal')
info:SetPoint('LEFT')
-- register the tag on the text widget with oUF
self:Tag(info, '[mylayout:threatname]')
--]]
local ns = oUF
local oUF = ns.oUF
local _G = _G
local unpack = unpack
local floor = math.floor
local format = string.format
local tinsert, tremove = table.insert, table.remove
local GetComboPoints = GetComboPoints
local GetNumRaidMembers = GetNumRaidMembers
local GetPetHappiness = GetPetHappiness
local GetQuestDifficultyColor = GetQuestDifficultyColor
local GetRaidRosterInfo = GetRaidRosterInfo
local IsResting = IsResting
local UnitCanAttack = UnitCanAttack
local UnitClass = UnitClass
local UnitClassification = UnitClassification
local UnitCreatureFamily = UnitCreatureFamily
local UnitCreatureType = UnitCreatureType
local UnitFactionGroup = UnitFactionGroup
local UnitIsConnected = UnitIsConnected
local UnitIsDead = UnitIsDead
local UnitIsGhost = UnitIsGhost
local UnitIsPVP = UnitIsPVP
local UnitIsPartyLeader = UnitIsPartyLeader
local UnitIsPlayer = UnitIsPlayer
local UnitLevel = UnitLevel
local UnitMana = UnitMana
local UnitManaMax = UnitManaMax
local UnitName = UnitName
local UnitPowerType = UnitPowerType
local UnitRace = UnitRace
local UnitSex = UnitSex
local _PATTERN = '%[..-%]+'
local _ENV = {
Hex = function(r, g, b)
if(type(r) == 'table') then
if(r.r) then
r, g, b = r.r, r.g, r.b
else
r, g, b = unpack(r)
end
end
if not r or type(r) == 'string' then
return '|cffFFFFFF'
end
return format('|cff%02x%02x%02x', r * 255, g * 255, b * 255)
end,
ColorGradient = oUF.ColorGradient,
}
local _PROXY = setmetatable(_ENV, {__index = _G})
local tagStrings = {
['creature'] = [[function(u)
return UnitCreatureFamily(u) or UnitCreatureType(u)
end]],
['dead'] = [[function(u)
if(UnitIsDead(u)) then
return 'Dead'
elseif(UnitIsGhost(u)) then
return 'Ghost'
end
end]],
['difficulty'] = [[function(u)
if UnitCanAttack('player', u) then
local l = UnitLevel(u)
return Hex(GetQuestDifficultyColor((l > 0) and l or 999))
end
end]],
['leader'] = [[function(u)
if(UnitIsPartyLeader(u)) then
return 'L'
end
end]],
['leaderlong'] = [[function(u)
if(UnitIsPartyLeader(u)) then
return 'Leader'
end
end]],
['level'] = [[function(u)
local l = UnitLevel(u)
if(l > 0) then
return l
else
return '??'
end
end]],
['missinghp'] = [[function(u)
local current = UnitHealthMax(u) - UnitHealth(u)
if(current > 0) then
return current
end
end]],
['missingpp'] = [[function(u)
local current = UnitManaMax(u) - UnitMana(u)
if(current > 0) then
return current
end
end]],
['name'] = [[function(u, r)
return UnitName(r or u)
end]],
['offline'] = [[function(u)
if(not UnitIsConnected(u)) then
return 'Offline'
end
end]],
['perhp'] = [[function(u)
local m = UnitHealthMax(u)
if(m == 0) then
return 0
else
return floor(UnitHealth(u) / m * 100 + .5)
end
end]],
['perpp'] = [[function(u)
local m = UnitManaMax(u)
if(m == 0) then
return 0
else
return floor(UnitMana(u) / m * 100 + .5)
end
end]],
['plus'] = [[function(u)
local c = UnitClassification(u)
if(c == 'elite' or c == 'rareelite') then
return '+'
end
end]],
['pvp'] = [[function(u)
if(UnitIsPVP(u)) then
return 'PvP'
end
end]],
['raidcolor'] = [[function(u)
local _, x = UnitClass(u)
if(x) then
return Hex(_COLORS.class[x])
end
end]],
['rare'] = [[function(u)
local c = UnitClassification(u)
if(c == 'rare' or c == 'rareelite') then
return 'Rare'
end
end]],
['resting'] = [[function(u)
if(u == 'player' and IsResting()) then
return 'zzz'
end
end]],
['sex'] = [[function(u)
local s = UnitSex(u)
if(s == 2) then
return 'Male'
elseif(s == 3) then
return 'Female'
end
end]],
['smartclass'] = [[function(u)
if(UnitIsPlayer(u)) then
return _TAGS['class'](u)
end
return _TAGS['creature'](u)
end]],
['status'] = [[function(u)
if(UnitIsDead(u)) then
return 'Dead'
elseif(UnitIsGhost(u)) then
return 'Ghost'
elseif(not UnitIsConnected(u)) then
return 'Offline'
else
return _TAGS['resting'](u)
end
end]],
['cpoints'] = [[function(u)
local cp = GetComboPoints('player', 'target')
if(cp > 0) then
return cp
end
end]],
['smartlevel'] = [[function(u)
local c = UnitClassification(u)
if(c == 'worldboss') then
return 'Boss'
else
local plus = _TAGS['plus'](u)
local level = _TAGS['level'](u)
if(plus) then
return level .. plus
else
return level
end
end
end]],
['classification'] = [[function(u)
local c = UnitClassification(u)
if(c == 'rare') then
return 'Rare'
elseif(c == 'rareelite') then
return 'Rare Elite'
elseif(c == 'elite') then
return 'Elite'
elseif(c == 'worldboss') then
return 'Boss'
end
end]],
['shortclassification'] = [[function(u)
local c = UnitClassification(u)
if(c == 'rare') then
return 'R'
elseif(c == 'rareelite') then
return 'R+'
elseif(c == 'elite') then
return '+'
elseif(c == 'worldboss') then
return 'B'
end
end]],
['group'] = [[function(unit)
local name, server = UnitName(unit)
if(server and server ~= '') then
name = format('%s-%s', name, server)
end
for i=1, GetNumRaidMembers() do
local raidName, _, group = GetRaidRosterInfo(i)
if(raidName == name) then
return group
end
end
end]],
['deficit:name'] = [[function(u)
local missinghp = _TAGS['missinghp'](u)
if(missinghp) then
return '-' .. missinghp
else
return _TAGS['name'](u)
end
end]],
['curmana'] = [[function(unit)
return UnitMana(unit, SPELL_POWER_MANA)
end]],
['maxmana'] = [[function(unit)
return UnitManaMax(unit, SPELL_POWER_MANA)
end]],
['happiness'] = [[function(u)
if(UnitIsUnit(u, 'pet')) then
local happiness = GetPetHappiness()
if(happiness == 1) then
return ':<'
elseif(happiness == 2) then
return ':|'
elseif(happiness == 3) then
return ':D'
end
end
end]],
['powercolor'] = [[function(u)
local pType, pToken, altR, altG, altB = UnitPowerType(u)
local t = _COLORS.power[pToken]
if(not t) then
if(altR) then
if(altR > 1 or altG > 1 or altB > 1) then
return Hex(altR / 255, altG / 255, altB / 255)
else
return Hex(altR, altG, altB)
end
else
return Hex(_COLORS.power[pType])
end
end
return Hex(t)
end]],
}
local tags = setmetatable(
{
curhp = UnitHealth,
curpp = UnitMana,
maxhp = UnitHealthMax,
maxpp = UnitManaMax,
class = UnitClass,
faction = UnitFactionGroup,
race = UnitRace,
},
{
__index = function(self, key)
local tagFunc = tagStrings[key]
if(tagFunc) then
local func, err = loadstring('return ' .. tagFunc)
if(func) then
func = func()
-- Want to trigger __newindex, so no rawset.
self[key] = func
tagStrings[key] = nil
return func
else
error(err, 3)
end
end
end,
__newindex = function(self, key, val)
if(type(val) == 'string') then
tagStrings[key] = val
elseif(type(val) == 'function') then
-- So we don't clash with any custom envs.
if(getfenv(val) == _G) then
setfenv(val, _PROXY)
end
rawset(self, key, val)
end
end,
}
)
_ENV._TAGS = tags
local tagEvents = {
['curhp'] = 'UNIT_HEALTH',
['maxhp'] = 'UNIT_MAXHEALTH',
['curpp'] = 'UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE',
['maxpp'] = 'UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE',
['dead'] = 'UNIT_HEALTH',
['leader'] = 'PARTY_LEADER_CHANGED',
['leaderlong'] = 'PARTY_LEADER_CHANGED',
['level'] = 'UNIT_LEVEL PLAYER_LEVEL_UP',
['missinghp'] = 'UNIT_HEALTH UNIT_MAXHEALTH',
['missingpp'] = 'UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE',
['name'] = 'UNIT_NAME_UPDATE',
['offline'] = 'UNIT_HEALTH',
['perhp'] = 'UNIT_HEALTH UNIT_MAXHEALTH',
['perpp'] = 'UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE',
['plus'] = 'UNIT_CLASSIFICATION_CHANGED',
['pvp'] = 'UNIT_FACTION',
['rare'] = 'UNIT_CLASSIFICATION_CHANGED',
['resting'] = 'PLAYER_UPDATE_RESTING',
['status'] = 'UNIT_HEALTH PLAYER_UPDATE_RESTING',
['cpoints'] = 'PLAYER_COMBO_POINTS PLAYER_TARGET_CHANGED',
['smartlevel'] = 'UNIT_LEVEL PLAYER_LEVEL_UP UNIT_CLASSIFICATION_CHANGED',
['classification'] = 'UNIT_CLASSIFICATION_CHANGED',
['shortclassification'] = 'UNIT_CLASSIFICATION_CHANGED',
['group'] = 'PARTY_MEMBERS_CHANGED RAID_ROSTER_UPDATE',
['curmana'] = 'UNIT_MANA UNIT_MAXMANA',
['maxmana'] = 'UNIT_MANA UNIT_MAXMANA',
['happiness'] = 'UNIT_HAPPINESS',
['powercolor'] = 'UNIT_DISPLAYPOWER',
}
local unitlessEvents = {
PLAYER_LEVEL_UP = true,
PLAYER_UPDATE_RESTING = true,
PLAYER_TARGET_CHANGED = true,
RAID_ROSTER_UPDATE = true,
PARTY_MEMBERS_CHANGED = true,
PARTY_LEADER_CHANGED = true,
PLAYER_COMBO_POINTS = true,
}
local events = {}
local frame = CreateFrame('Frame')
frame:SetScript('OnEvent', function(self, event, unit)
local strings = events[event]
if(strings) then
for _, fontstring in next, strings do
if(fontstring:IsVisible() and (unitlessEvents[event] or fontstring.parent.unit == unit)) then
fontstring:UpdateTag()
end
end
end
end)
local onUpdates = {}
local eventlessUnits = {}
local function createOnUpdate(timer)
local OnUpdate = onUpdates[timer]
if(not OnUpdate) then
local total = timer
local frame = CreateFrame('Frame')
local strings = eventlessUnits[timer]
frame:SetScript('OnUpdate', function()
if(total >= timer) then
for _, fs in next, strings do
if(fs.parent:IsShown() and UnitExists(fs.parent.unit)) then
fs:UpdateTag()
end
end
total = 0
end
total = total + arg1
end)
onUpdates[timer] = frame
end
end
local function onShow(self)
for _, fs in next, self.__tags do
fs:UpdateTag()
end
end
local function getTagName(tag)
local tagStart = (string.match(tag, '>+()') or 2)
local tagEnd = string.match(tag, '.*()<+')
tagEnd = (tagEnd and tagEnd - 1) or -2
return string.sub(tag, tagStart, tagEnd), tagStart, tagEnd
end
local function registerEvent(fontstr, event)
if(not events[event]) then events[event] = {} end
frame:RegisterEvent(event)
tinsert(events[event], fontstr)
end
local function registerEvents(fontstr, tagstr)
for tag in string.gmatch(tagstr, _PATTERN) do
tag = getTagName(tag)
local tagevents = tagEvents[tag]
if(tagevents) then
for event in string.gmatch(tagevents, '%S+') do
registerEvent(fontstr, event)
end
end
end
end
local function unregisterEvents(fontstr)
for event, data in next, events do
for i, tagfsstr in next, data do
if(tagfsstr == fontstr) then
if(getn(data) == 1) then
frame:UnregisterEvent(event)
end
tremove(data, i)
end
end
end
end
local OnEnter = function(self)
for _, fs in pairs(self.__mousetags) do
fs:SetAlpha(1)
end
end
local OnLeave = function(self)
for _, fs in pairs(self.__mousetags) do
fs:SetAlpha(0)
end
end
local onUpdateDelay = {}
local tagPool = {}
local funcPool = {}
local tmp = {}
local escapeSequences = {
["||c"] = "|c",
["||r"] = "|r",
["||T"] = "|T",
["||t"] = "|t",
}
--[[ Tags: frame:Tag(fs, tagstr)
Used to register a tag on a unit frame.
* self - the unit frame on which to register the tag
* fs - the font string to display the tag (FontString)
* tagstr - the tag string (string)
--]]
local function Tag(self, fs, tagstr)
if(not fs or not tagstr) then return end
if(not self.__tags) then
self.__tags = {}
self.__mousetags = {}
tinsert(self.__elements, onShow)
else
-- Since people ignore everything that's good practice - unregister the tag
-- if it already exists.
for _, tag in pairs(self.__tags) do
if(fs == tag) then
-- We don't need to remove it from the __tags table as Untag handles
-- that for us.
self:Untag(fs)
end
end
end
fs.parent = self
for escapeSequence, replacement in pairs(escapeSequences) do
while string.find(tagstr, escapeSequence) do
tagstr = string.gsub(tagstr, escapeSequence, replacement)
end
end
if string.find(tagstr, '%[mouseover%]') then
tinsert(self.__mousetags, fs)
fs:SetAlpha(0)
if not self.__HookFunc then
self:HookScript('OnEnter', OnEnter)
self:HookScript('OnLeave', OnLeave)
self.__HookFunc = true;
end
tagstr = string.gsub(tagstr, '%[mouseover%]', '')
else
for index, fontString in pairs(self.__mousetags) do
if fontString == fs then
self.__mousetags[index] = nil;
fs:SetAlpha(1)
end
end
end
local containsOnUpdate
for tag in string.gmatch(tagstr, _PATTERN) do
tag = getTagName(tag)
if not tagEvents[tag] then
containsOnUpdate = onUpdateDelay[tag] or 0.15;
end
end
local func = tagPool[tagstr]
if(not func) then
local format, numTags = string.gsub(string.gsub(tagstr, '%%', '%%%%'), _PATTERN, '%%s')
local args = {}
for bracket in string.gmatch(tagstr, _PATTERN) do
local tagFunc = funcPool[bracket] or tags[string.sub(bracket, 2, -2)]
if(not tagFunc) then
local tagName, tagStart, tagEnd = getTagName(bracket)
local tag = tags[tagName]
if(tag) then
tagStart = tagStart - 2
tagEnd = tagEnd + 2
if(tagStart ~= 0 and tagEnd ~= 0) then
local prefix = string.sub(bracket, 2, tagStart)
local suffix = string.sub(bracket, tagEnd, -2)
tagFunc = function(unit, realUnit)
local str = tag(unit, realUnit)
if(str) then
return prefix .. str .. suffix
end
end
elseif(tagStart ~= 0) then
local prefix = string.sub(bracket, 2, tagStart)
tagFunc = function(unit, realUnit)
local str = tag(unit, realUnit)
if(str) then
return prefix .. str
end
end
elseif(tagEnd ~= 0) then
local suffix = string.sub(bracket, tagEnd, -2)
tagFunc = function(unit, realUnit)
local str = tag(unit, realUnit)
if(str) then
return str .. suffix
end
end
end
funcPool[bracket] = tagFunc
end
end
if(tagFunc) then
tinsert(args, tagFunc)
else
numTags = -1
func = function(self)
return self:SetText(bracket)
end
end
end
if(numTags == 1) then
func = function(self)
local parent = self.parent
local realUnit
if(self.overrideUnit) then
realUnit = parent.realUnit
end
_ENV._COLORS = parent.colors
return self:SetText(string.format(
format,
args[1](parent.unit, realUnit) or ''
))
end
elseif(numTags == 2) then
func = function(self)
local parent = self.parent
local unit = parent.unit
local realUnit
if(self.overrideUnit) then
realUnit = parent.realUnit
end
_ENV._COLORS = parent.colors
return self:SetText(string.format(
format,
args[1](unit, realUnit) or '',
args[2](unit, realUnit) or ''
))
end
elseif(numTags == 3) then
func = function(self)
local parent = self.parent
local unit = parent.unit
local realUnit
if(self.overrideUnit) then
realUnit = parent.realUnit
end
_ENV._COLORS = parent.colors
return self:SetText(string.format(
format,
args[1](unit, realUnit) or '',
args[2](unit, realUnit) or '',
args[3](unit, realUnit) or ''
))
end
elseif numTags ~= -1 then
func = function(self)
local parent = self.parent
local unit = parent.unit
local realUnit
if(self.overrideUnit) then
realUnit = parent.realUnit
end
_ENV._COLORS = parent.colors
for i, func in next, args do
tmp[i] = func(unit, realUnit) or ''
end
-- We do 1, numTags because tmp can hold several unneeded variables.
return self:SetText(string.format(format, unpack(tmp, 1, numTags)))
end
end
if numTags ~= -1 then
tagPool[tagstr] = func
end
end
fs.UpdateTag = func
local unit = self.unit
if(self.__eventless or fs.frequentUpdates) or containsOnUpdate then
local timer
if(type(fs.frequentUpdates) == 'number') then
timer = fs.frequentUpdates
elseif containsOnUpdate then
timer = containsOnUpdate
else
timer = .5
end
if(not eventlessUnits[timer]) then eventlessUnits[timer] = {} end
tinsert(eventlessUnits[timer], fs)
createOnUpdate(timer)
else
registerEvents(fs, tagstr)
end
tinsert(self.__tags, fs)
end
--[[ Tags: frame:Untag(fs)
Used to unregister a tag from a unit frame.
* self - the unit frame from which to unregister the tag
* fs - the font string holding the tag (FontString)
--]]
local function Untag(self, fs)
if(not fs) then return end
unregisterEvents(fs)
for _, timers in next, eventlessUnits do
for i, fontstr in next, timers do
if(fs == fontstr) then
tremove(timers, i)
end
end
end
for i, fontstr in next, self.__tags do
if(fontstr == fs) then
tremove(self.__tags, i)
end
end
fs.UpdateTag = nil
end
oUF.Tags = {
Methods = tags,
Events = tagEvents,
SharedEvents = unitlessEvents,
OnUpdateThrottle = onUpdateDelay,
}
oUF:RegisterMetaFunction('Tag', Tag)
oUF:RegisterMetaFunction('Untag', Untag)
+145
View File
@@ -0,0 +1,145 @@
local ns = oUF
local oUF = ns.oUF
local Private = oUF.Private
local argcheck = Private.argcheck
local error = Private.error
local frame_metatable = Private.frame_metatable
-- Original event methods
local registerEvent = frame_metatable.__index.RegisterEvent
local unregisterEvent = frame_metatable.__index.UnregisterEvent
function Private.UpdateUnits(frame, unit, realUnit)
if(unit == realUnit) then
realUnit = nil
end
if(frame.unit ~= unit or frame.realUnit ~= realUnit) then
frame.unit = unit
frame.realUnit = realUnit
frame.id = string.match(unit, '^.-(%d+)')
return true
end
end
local function onEvent()
if(this:IsVisible() or event == 'UNIT_COMBO_POINTS') then
--print(this, event, arg and unpack(arg))
--print(this, event, arg1, arg2, arg3, arg4, arg5)
return this[event](this, event, arg1, arg2, arg3, arg4, arg5)
end
end
local event_metatable = {
__call = function(funcs, self, ...)
for _, func in next, funcs do
func(self, unpack(arg))
end
end,
}
--[[ Events: frame:RegisterEvent(event, func, unitless)
Used to register a frame for a game event and add an event handler. OnUpdate polled frames are prevented from
registering events.
* self - frame that will be registered for the given event.
* event - name of the event to register (string)
* func - function that will be executed when the event fires. If a string is passed, then a function by that name
must be defined on the frame. Multiple functions can be added for the same frame and event
(string or function)
* unitless - indicates that the event does not fire for a specific unit, so the event arguments won't be
matched to the frame unit(s). Events that do not start with UNIT_ or are not known to be unit events are
automatically considered unitless (boolean)
--]]
function frame_metatable.__index:RegisterEvent(event, func)
-- Block OnUpdate polled frames from registering events.
-- UNIT_PORTRAIT_UPDATE and UNIT_MODEL_CHANGED which are used for
-- portrait updates.
if(self.__eventless and event ~= 'UNIT_PORTRAIT_UPDATE' and event ~= 'UNIT_MODEL_CHANGED') then return end
argcheck(event, 2, 'string')
if(type(func) == 'string' and type(self[func]) == 'function') then
func = self[func]
end
local curev = self[event]
local kind = type(curev)
if(curev and func) then
if(kind == 'function' and curev ~= func) then
self[event] = setmetatable({curev, func}, event_metatable)
elseif(kind == 'table') then
for _, infunc in next, curev do
if(infunc == func) then return end
end
table.insert(curev, func)
end
elseif(self:IsEventRegistered(event)) then
return
else
if(type(func) == 'function') then
self[event] = func
elseif(not self[event]) then
return error("Style [%s] attempted to register event [%s] on unit [%s] with a handler that doesn't exist.", self.style, event, self.unit or 'unknown')
end
if not self:GetScript('OnEvent') then
self:SetScript('OnEvent', onEvent)
end
registerEvent(self, event)
self.__registeredEvents[event] = true
end
end
--[[ Events: frame:IsEventRegistered(event, func)
Used to determine if a game event is registered.
* self - the frame registered for the event
* event - name of the registered event (string)
--]]
function frame_metatable.__index:IsEventRegistered(event)
argcheck(event, 2, 'string')
return self.__registeredEvents[event] and true or false
end
--[[ Events: frame:UnregisterEvent(event, func)
Used to remove a function from the event handler list for a game event.
* self - the frame registered for the event
* event - name of the registered event (string)
* func - function to be removed from the list of event handlers. If this is the only handler for the given event, then
the frame will be unregistered for the event
--]]
function frame_metatable.__index:UnregisterEvent(event, func)
argcheck(event, 2, 'string')
local curev = self[event]
if(type(curev) == 'table' and func) then
for k, infunc in next, curev do
if(infunc == func) then
table.remove(curev, k)
local n = getn(curev)
if(n == 1) then
local _, handler = next(curev)
self[event] = handler
elseif(n == 0) then
-- This should not happen
unregisterEvent(self, event)
self.__registeredEvents[event] = nil
end
break
end
end
elseif(curev == func) then
self[event] = nil
unregisterEvent(self, event)
self.__registeredEvents[event] = nil
end
end
@@ -0,0 +1,71 @@
local ns = oUF
local oUF = ns.oUF
local Private = oUF.Private
local argcheck = Private.argcheck
local queue = {}
local factory = CreateFrame('Frame')
factory:SetScript('OnEvent', function()
return this[event](this, event, arg and unpack(arg))
end)
factory:RegisterEvent('PLAYER_LOGIN')
factory.active = true
function factory:PLAYER_LOGIN()
if(not self.active) then return end
for _, func in next, queue do
func(oUF)
end
-- Avoid creating dupes.
wipe(queue)
end
--[[ Factory: oUF:Factory(func)
Used to call a function directly if the current character is logged in and the factory is active. Else the function is
queued up to be executed at a later time (upon PLAYER_LOGIN by default).
* self - the global oUF object
* func - function to be executed or delayed (function)
--]]
function oUF:Factory(func)
argcheck(func, 2, 'function')
-- Call the function directly if we're active and logged in.
if(IsLoggedIn() and factory.active) then
return func(self)
else
table.insert(queue, func)
end
end
--[[ Factory: oUF:EnableFactory()
Used to enable the factory.
* self - the global oUF object
--]]
function oUF:EnableFactory()
factory.active = true
end
--[[ Factory: oUF:DisableFactory()
Used to disable the factory.
* self - the global oUF object
--]]
function oUF:DisableFactory()
factory.active = nil
end
--[[ Factory: oUF:RunFactoryQueue()
Used to try to execute queued up functions. The current player must be logged in and the factory must be active for
this to succeed.
* self - the global oUF object
--]]
function oUF:RunFactoryQueue()
factory:PLAYER_LOGIN()
end
@@ -0,0 +1,4 @@
local ns = oUF
-- It's named Private for a reason!
ns.oUF.Private = nil
+5
View File
@@ -0,0 +1,5 @@
oUF = {}
local ns = oUF
ns.oUF = {}
ns.oUF.Private = {}
+58
View File
@@ -0,0 +1,58 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="init.lua"/>
<Script file="private.lua"/>
<Script file="ouf.lua"/>
<Script file="events.lua"/>
<Script file="factory.lua"/>
<Script file="blizzard.lua"/>
<Script file="units.lua"/>
<Script file="colors.lua"/>
<Script file="finalize.lua"/>
<Include file="elements\elements.xml"/>
<Cooldown name="oUF_CooldownFrameTemplate" inherits="CooldownFrameTemplate" drawEdge="true" virtual="true"/>
<!--
Sub-object as a child of the parent unit frame:
<Button name="oUF_HeaderTargetTemplate" inherits="SecureUnitButtonTemplate" virtual="true">
<Frames>
<Button name="$parentTarget" inherits="SecureUnitButtonTemplate">
<Attributes>
<Attribute name="unitsuffix" type="string" value="target"/>
<Attribute name="useparent-unit" type="boolean" value="true"/>
</Attributes>
</Button>
</Frames>
</Button>
Separate unit template example:
<Button name="oUF_HeaderSeparateSubOjectsTemplate" inherits="SecureUnitButtonTemplate" virtual="true">
<Attributes>
<Attribute name="oUF-onlyProcessChildren" type="boolean" value="true"/>
</Attributes>
<Frames>
<Button name="$parentUnit" inherits="SecureUnitButtonTemplate">
<Attributes>
<Attribute name="useparent-unit" type="boolean" value="true"/>
</Attributes>
</Button>
<Button name="$parentPet" inherits="SecureUnitButtonTemplate">
<Attributes>
<Attribute name="unitsuffix" type="string" value="pet"/>
<Attribute name="useparent-unit" type="boolean" value="true"/>
</Attributes>
</Button>
<Button name="$parentTarget" inherits="SecureUnitButtonTemplate">
<Attributes>
<Attribute name="unitsuffix" type="string" value="target"/>
<Attribute name="useparent-unit" type="boolean" value="true"/>
</Attributes>
</Button>
</Frames>
</Button>
-->
</Ui>
+754
View File
@@ -0,0 +1,754 @@
local ns = oUF
local oUF = ns.oUF
local Private = oUF.Private
local argcheck = Private.argcheck
local print = Private.print
local error = Private.error
local styles, style = {}
local callback, units, objects, headers = {}, {}, {}, {}
local elements = {}
local activeElements = {}
local pairs = pairs
local unitExistsWatchers = {}
local unitExistsCache = setmetatable({},{
__index = function(t, k)
local v = UnitExists(k) or false
t[k] = v
return v
end
})
local function updateUnitWatch(frame)
local unit = frame.unit
local exists = (unit and unitExistsCache[unit])
if exists then
frame:Show()
else
frame:Hide()
end
end
local unitWatch = CreateFrame("Frame")
unitWatch:Hide()
local timer = 0
unitWatch:SetScript("OnUpdate", function()
timer = timer - arg1
if timer <= 0 then
timer = 0.2
for k in pairs(unitExistsCache) do
unitExistsCache[k] = nil
end
for frame in pairs(unitExistsWatchers) do
updateUnitWatch(frame)
end
end
end)
unitWatch:SetScript("OnEvent", function() timer = 0 end)
unitWatch:RegisterEvent("PLAYER_TARGET_CHANGED")
unitWatch:RegisterEvent("PLAYER_FOCUS_CHANGED")
unitWatch:RegisterEvent("PLAYER_REGEN_DISABLED")
unitWatch:RegisterEvent("PLAYER_REGEN_ENABLED")
unitWatch:RegisterEvent("UNIT_PET")
unitWatch:RegisterEvent("RAID_ROSTER_UPDATE")
unitWatch:RegisterEvent("PARTY_MEMBERS_CHANGED")
local function RegisterUnitWatch(frame)
unitExistsWatchers[frame] = true
unitWatch:Show()
updateUnitWatch(frame)
end
local function UnregisterUnitWatch(frame)
unitExistsWatchers[frame] = nil
end
-- updating of "invalid" units.
local function enableTargetUpdate(object)
object.onUpdateFrequency = object.onUpdateFrequency or .5
object.__eventless = true
local total = 0
object:SetScript('OnUpdate', function()
if not this.unit then
return
elseif total > this.onUpdateFrequency then
this:UpdateAllElements('OnUpdate')
total = 0
end
total = total + GetTime()
end)
end
Private.enableTargetUpdate = enableTargetUpdate
local function updateActiveUnit(self, event, unit)
return true
end
local function iterateChildren(...)
for i = 1, table.getn(arg) do
local obj = arg[i]
if(type(obj) == 'table' and obj.isChild) then
updateActiveUnit(obj, 'iterateChildren')
end
end
end
local function onAttributeChanged(self, name, value)
if(name == 'unit' and value) then
if(self.hasChildren) then
iterateChildren(self:GetChildren())
end
if(not self.onlyProcessChildren) then
updateActiveUnit(self, 'OnAttributeChanged')
end
--[[
if(self.unit and self.unit == value) then
return
else
if(self.hasChildren) then
iterateChildren(self:GetChildren())
end
end
]]
end
end
local frame_metatable = {
__index = CreateFrame('Button')
}
Private.frame_metatable = frame_metatable
for k, v in next, {
UpdateElement = function(self, name)
local unit = self.unit
if(not unit or not UnitExists(unit)) then return end
local element = elements[name]
if(not element or not self:IsElementEnabled(name) or not activeElements[self]) then return end
if(element.update) then
element.update(self, 'OnShow', unit)
end
end,
UpdateElement = function(self, name)
local unit = self.unit
if(not unit or not UnitExists(unit)) then return end
local element = elements[name]
if(not element or not self:IsElementEnabled(name) or not activeElements[self]) then return end
if(element.update) then
element.update(self, 'OnShow', unit)
end
end,
--[[ frame:EnableElement(name, unit)
Used to activate an element for the given unit frame.
* self - unit frame for which the element should be enabled
* name - name of the element to be enabled (string)
* unit - unit to be passed to the element's Enable function. Defaults to the frame's unit (string?)
--]]
EnableElement = function(self, name, unit)
argcheck(name, 2, 'string')
argcheck(unit, 3, 'string', 'nil')
local element = elements[name]
if(not element or self:IsElementEnabled(name) or not activeElements[self]) then return end
if(element.enable(self, unit or self.unit)) then
activeElements[self][name] = true
if(element.update) then
table.insert(self.__elements, element.update)
end
end
end,
--[[ frame:DisableElement(name)
Used to deactivate an element for the given unit frame.
* self - unit frame for which the element should be disabled
* name - name of the element to be disabled (string)
--]]
DisableElement = function(self, name)
argcheck(name, 2, 'string')
local enabled = self:IsElementEnabled(name)
if(not enabled) then return end
local update = elements[name].update
for k, func in next, self.__elements do
if(func == update) then
table.remove(self.__elements, k)
break
end
end
activeElements[self][name] = nil
-- We need to run a new update cycle in-case we knocked ourself out of sync.
-- The main reason we do this is to make sure the full update is completed
-- if an element for some reason removes itself _during_ the update
-- progress.
self:UpdateAllElements('DisableElement')
return elements[name].disable(self)
end,
--[[ frame:IsElementEnabled(name)
Used to check if an element is enabled on the given frame.
* self - unit frame
* name - name of the element (string)
--]]
IsElementEnabled = function(self, name)
argcheck(name, 2, 'string')
local element = elements[name]
if(not element) then return end
local active = activeElements[self]
return active and active[name]
end,
--[[ frame:Enable(asState)
Used to toggle the visibility of a unit frame based on the existence of its unit. This is a reference to
`RegisterUnitWatch`.
* self - unit frame
* asState - if true, the frame's "state-unitexists" attribute will be set to a boolean value denoting whether the
unit exists; if false, the frame will be shown if its unit exists, and hidden if it does not (boolean)
--]]
Enable = RegisterUnitWatch,
--[[ frame:Disable()
Used to UnregisterUnitWatch for the given frame and hide it.
* self - unit frame
--]]
Disable = function(self)
UnregisterUnitWatch(self)
self:Hide()
end,
--[[ frame:UpdateAllElements(event)
Used to update all enabled elements on the given frame.
* self - unit frame
* event - event name to pass to the elements' update functions (string)
--]]
UpdateAllElements = function(self, event)
local unit = self.unit
if(not UnitExists(unit)) then return end
assert(type(event) == 'string', "Invalid argument 'event' in UpdateAllElements.")
if(self.PreUpdate) then
self:PreUpdate(event)
end
for _, func in next, self.__elements do
func(self, event, unit)
end
if(self.PostUpdate) then
self:PostUpdate(event)
end
end,
} do
frame_metatable.__index[k] = v
end
local secureDropdown
local function InitializeSecureMenu()
local unit = SecureTemplatesDropdown.unit
if(not unit) then return end
local unitType = string.match(unit, '^([a-z]+)[0-9]+$') or unit
local menu
if(unitType == 'party') then
menu = 'PARTY'
elseif(unitType == 'focus') then
menu = 'RAID_TARGET_ICON'
-- elseif(unitType == 'arenapet' or unitType == 'arena') then
elseif(unitType == 'arena') then
menu = 'RAID_TARGET_ICON'
elseif(UnitIsUnit(unit, 'player')) then
menu = 'SELF'
elseif(UnitIsUnit(unit, 'pet')) then
menu = 'PET'
elseif(UnitIsPlayer(unit)) then
if(UnitInRaid(unit)) then
menu = 'RAID_PLAYER'
elseif(UnitInParty(unit)) then
menu = 'PARTY'
else
menu = 'PLAYER'
end
elseif(UnitIsUnit(unit, 'target')) then
menu = 'RAID_TARGET_ICON'
end
if(menu) then
UnitPopup_ShowMenu(SecureTemplatesDropdown, menu, unit)
end
end
local function togglemenu(self, unit)
if(not secureDropdown) then
secureDropdown = CreateFrame('Frame', 'SecureTemplatesDropdown', nil, 'UIDropDownMenuTemplate')
secureDropdown:SetID(1)
table.insert(UnitPopupFrames, secureDropdown:GetName())
UIDropDownMenu_Initialize(secureDropdown, InitializeSecureMenu, 'MENU')
end
if(secureDropdown.openedFor and secureDropdown.openedFor ~= self) then
CloseDropDownMenus()
end
secureDropdown.unit = string.lower(unit)
secureDropdown.openedFor = self
ToggleDropDownMenu(1, nil, secureDropdown, 'cursor')
end
local function onShow()
return this:UpdateAllElements('OnShow')
end
local function initObject(unit, style, styleFunc, header, ...)
local num = table.getn(arg)
for i = 1, num do
local object = arg[i]
local objectUnit = object.guessUnit or unit
local suffix = "ery"
object.__elements = {}
object.__registeredEvents = {}
object.style = style
object = setmetatable(object, frame_metatable)
-- Expose the frame through oUF.objects.
table.insert(objects, object)
-- We have to force update the frames when PEW fires.
object:RegisterEvent('PLAYER_ENTERING_WORLD', object.UpdateAllElements)
if(not header) then
-- No header means it's a frame created through :Spawn().
object.menu = togglemenu
object:SetScript("OnClick", function()
TargetUnit(unit)
end)
-- Other target units are handled by :HandleUnit().
if(suffix == 'target') then
enableTargetUpdate(object)
else
oUF:HandleUnit(object)
end
else
-- Used to update frames when they change position in a group.
object:RegisterEvent('RAID_ROSTER_UPDATE', object.UpdateAllElements)
if(num > 1) then
if(object:GetParent() == header) then
object.hasChildren = true
else
object.isChild = true
end
end
if(suffix == 'target') then
enableTargetUpdate(object)
end
end
Private.UpdateUnits(object, objectUnit)
styleFunc(object, objectUnit, not header)
--object:SetScript('OnAttributeChanged', onAttributeChanged)
object:SetScript('OnShow', onShow)
activeElements[object] = {}
for element in next, elements do
object:EnableElement(element, objectUnit)
end
for _, func in next, callback do
func(object)
end
-- Make Clique kinda happy
_G.ClickCastFrames = ClickCastFrames or {}
ClickCastFrames[object] = true
end
end
local function walkObject(object, unit)
local parent = object:GetParent()
local style = parent.style or style
local styleFunc = styles[style]
local header = parent.headerType and parent
-- Check if we should leave the main frame blank.
if(object.onlyProcessChildren) then
object.hasChildren = true
object:SetScript('OnAttributeChanged', onAttributeChanged)
return initObject(unit, style, styleFunc, header, object:GetChildren())
end
return initObject(unit, style, styleFunc, header, object, object:GetChildren())
end
--[[ oUF:RegisterInitCallback(func)
Used to add a function to a table to be executed upon unit frame/header initialization.
* self - the global oUF object
* func - function to be added
--]]
function oUF:RegisterInitCallback(func)
table.insert(callback, func)
end
--[[ oUF:RegisterMetaFunction(name, func)
Used to make a (table of) function(s) available to all unit frames.
* self - the global oUF object
* name - unique name of the function (string)
* func - function or a table of functions (function or table)
--]]
function oUF:RegisterMetaFunction(name, func)
argcheck(name, 2, 'string')
argcheck(func, 3, 'function', 'table')
if(frame_metatable.__index[name]) then
return
end
frame_metatable.__index[name] = func
end
--[[ oUF:RegisterStyle(name, func)
Used to register a style with oUF. This will also set the active style if it hasn't been set yet.
* self - the global oUF object
* name - name of the style
* func - function(s) defining the style (function or table)
--]]
function oUF:RegisterStyle(name, func)
argcheck(name, 2, 'string')
argcheck(func, 3, 'function', 'table')
if(styles[name]) then return error('Style [%s] already registered.', name) end
if(not style) then style = name end
styles[name] = func
end
--[[ oUF:SetActiveStyle(name)
Used to set the active style.
* self - the global oUF object
* name - name of the style (string)
--]]
function oUF:SetActiveStyle(name)
argcheck(name, 2, 'string')
if(not styles[name]) then return error('Style [%s] does not exist.', name) end
style = name
end
do
local function iter(_, n)
-- don't expose the style functions.
return (next(styles, n))
end
--[[ oUF:IterateStyles()
Returns an iterator over all registered styles.
* self - the global oUF object
--]]
function oUF.IterateStyles()
return iter, nil, nil
end
end
local getCondition
do
local conditions = {
raid40 = '[target=raid26,exists] show;',
raid25 = '[target=raid11,exists] show;',
raid10 = '[target=raid6,exists] show;',
raid = '[group:raid] show;',
party = '[group:party,nogroup:raid] show;',
solo = '[target=player,exists,nogroup:party] show;',
}
function getCondition(...)
local cond = ''
for i = 1, select('#', arg) do
local short = select(i, unpack(arg))
local condition = conditions[short]
if(condition) then
cond = cond .. condition
end
end
return cond .. 'hide'
end
end
local function generateName(unit, ...)
local name = 'oUF_' .. style:gsub('^oUF_?', ''):gsub('[^%a%d_]+', '')
local raid, party, groupFilter
for i = 1, select('#', arg), 2 do
local att, val = select(i, unpack(arg))
if(att == 'showRaid') then
raid = true
elseif(att == 'showParty') then
party = true
elseif(att == 'groupFilter') then
groupFilter = val
end
end
local append
if(raid) then
if(groupFilter) then
if(type(groupFilter) == 'number' and groupFilter > 0) then
append = groupFilter
elseif(groupFilter:match('TANK')) then
append = 'MainTank'
elseif(groupFilter:match('ASSIST')) then
append = 'MainAssist'
else
local _, count = groupFilter:gsub(',', '')
if(count == 0) then
append = 'Raid' .. groupFilter
else
append = 'Raid'
end
end
else
append = 'Raid'
end
elseif(party) then
append = 'Party'
elseif(unit) then
append = unit:gsub('^%l', string.upper)
end
if(append) then
name = name .. append
end
local base = name
local i = 2
while(_G[name]) do
name = base .. i
i = i + 1
end
return name
end
do
local function styleProxy(self, frame, ...)
return walkObject(_G[frame])
end
-- There has to be an easier way to do this.
local initialConfigFunction = function(self)
local header = self:GetParent()
for i = 1, select('#', self), 1 do
local frame = select(i, self)
local unit
-- There's no need to do anything on frames with onlyProcessChildren
if(not frame.onlyProcessChildren) then
-- Attempt to guess what the header is set to spawn.
local groupFilter = header:GetAttribute('groupFilter')
if(type(groupFilter) == 'string' and groupFilter:match('MAIN[AT]')) then
local role = groupFilter:match('MAIN([AT])')
if(role == 'T') then
unit = 'maintank'
else
unit = 'mainassist'
end
elseif(header:GetAttribute('showRaid')) then
unit = 'raid'
elseif(header:GetAttribute('showParty')) then
unit = 'party'
end
local headerType = header.headerType
local suffix = frame:GetAttribute('unitsuffix')
if(unit and suffix) then
if(headerType == 'pet' and suffix == 'target') then
unit = unit .. headerType .. suffix
else
unit = unit .. suffix
end
elseif(unit and headerType == 'pet') then
unit = unit .. headerType
end
frame.menu = togglemenu
frame:SetAttribute('type1', 'target')
frame:SetAttribute('type2', 'menu')
frame.guessUnit = unit
end
end
header:styleFunction(self:GetName())
end
--[[ oUF:SpawnHeader(overrideName, template, visibility, ...)
Used to create a group header and apply the currently active style to it.
* self - the global oUF object
* overrideName - unique global name to be used for the header. Defaults to an auto-generated name based on the name
of the active style and other arguments passed to `:SpawnHeader` (string?)
* template - name of a template to be used for creating the header. Defaults to `'SecureGroupHeaderTemplate'`
(string?)
* visibility - macro conditional(s) which define when to display the header (string).
* ... - further argument pairs. Consult [Group Headers](http://wowprogramming.com/docs/secure_template/Group_Headers)
for possible values.
In addition to the standard group headers, oUF implements some of its own attributes. These can be supplied by the
layout, but are optional.
* oUF-initialConfigFunction - can contain code that will be securely run at the end of the initial secure
configuration (string?)
* oUF-onlyProcessChildren - can be used to force headers to only process children (boolean?)
--]]
function oUF:SpawnHeader(overrideName, template, visibility, ...)
if(not style) then return error('Unable to create frame. No styles have been registered.') end
template = (template or 'SecureGroupHeaderTemplate')
local isPetHeader = string.match(template, 'PetHeader')
local name = overrideName or generateName(nil, unpack(arg))
local header = CreateFrame('Frame', name, UIParent, template)
header:SetAttribute('template', 'SecureUnitButtonTemplate')
for i = 1, select('#', arg), 2 do
local att, val = select(i, unpack(arg))
if(not att) then break end
header:SetAttribute(att, val)
end
header.style = style
header.styleFunction = styleProxy
header.visibility = visibility
-- Expose the header through oUF.headers.
table.insert(headers, header)
header.initialConfigFunction = initialConfigFunction
header.headerType = isPetHeader and 'pet' or 'group'
if(header:GetAttribute('showParty')) then
self:DisableBlizzard('party')
end
if(visibility) then
local type, list = string.split(' ', visibility, 2)
if(list and type == 'custom') then
RegisterStateDriver(header, 'visibility', list)
header.visibility = list
else
local condition = getCondition(string.split(',', visibility))
RegisterStateDriver(header, 'visibility', condition)
header.visibility = condition
end
end
return header
end
end
--[[ oUF:Spawn(unit, overrideName)
Used to create a single unit frame and apply the currently active style to it.
* self - the global oUF object
* unit - the frame's unit (string)
* overrideName - unique global name to use for the unit frame. Defaults to an auto-generated name based on the unit
(string?)
--]]
function oUF:Spawn(unit, overrideName)
argcheck(unit, 2, 'string')
if(not style) then return error('Unable to create frame. No styles have been registered.') end
unit = string.lower(unit)
local name = overrideName or generateName(unit)
local object = CreateFrame('Button', name, UIParent)
object:Hide()
Private.UpdateUnits(object, unit)
self:DisableBlizzard(unit)
units[unit] = object
walkObject(object, unit)
object.unit = unit
return object
end
--[[ oUF:AddElement(name, update, enable, disable)
Used to register an element with oUF.
* self - the global oUF object
* name - unique name of the element (string)
* update - used to update the element (function?)
* enable - used to enable the element for a given unit frame and unit (function?)
* disable - used to disable the element for a given unit frame (function?)
--]]
function oUF:AddElement(name, update, enable, disable)
argcheck(name, 2, 'string')
argcheck(update, 3, 'function', 'nil')
argcheck(enable, 4, 'function', 'nil')
argcheck(disable, 5, 'function', 'nil')
if(elements[name]) then return error('Element [%s] is already registered.', name) end
elements[name] = {
update = update;
enable = enable;
disable = disable;
}
end
--[[ oUF.units
Array containing all unit frames with existing units created by oUF:Spawn.
--]]
oUF.units = units
--[[ oUF.objects
Array containing all unit frames created by `oUF:Spawn`.
--]]
oUF.objects = objects
--[[ oUF.headers
Array containing all group headers created by `oUF:SpawnHeader`.
--]]
oUF.headers = headers
@@ -0,0 +1,22 @@
local ns = oUF
local Private = ns.oUF.Private
function Private.argcheck(value, num, ...)
assert(type(num) == 'number', "Bad argument #2 to 'argcheck' (number expected, got " .. type(num) .. ')')
for i = 1, select('#', arg) do
if(type(value) == select(i, unpack(arg))) then return end
end
local types = strjoin(', ', unpack(arg))
local name = string.match(debugstack(2,2,0), ": in function [`<](.-)['>]")
error(string.format("Bad argument #%d to '%s' (%s expected, got %s)", num, name, types, type(value)), 3)
end
function Private.print(...)
print('|cff33ff99oUF:|r', unpack(arg))
end
function Private.error(...)
Private.print('|cffff0000Error:|r ' .. string.format(unpack(arg)))
end
+20
View File
@@ -0,0 +1,20 @@
local ns = oUF
local oUF = ns.oUF
local Private = oUF.Private
local enableTargetUpdate = Private.enableTargetUpdate
-- Handles unit specific actions.
function oUF:HandleUnit(object, unit)
local unit = object.unit or unit
if(unit == 'target') then
object:RegisterEvent('PLAYER_TARGET_CHANGED', object.UpdateAllElements)
elseif(unit == 'mouseover') then
object:RegisterEvent('UPDATE_MOUSEOVER_UNIT', object.UpdateAllElements)
elseif(unit == 'focus') then
object:RegisterEvent('PLAYER_FOCUS_CHANGED', object.UpdateAllElements)
elseif(string.match(unit, '%w+target')) then
enableTargetUpdate(object)
end
end
@@ -3,6 +3,7 @@
<Include file="Tooltip\Load_Tooltip.xml"/> <Include file="Tooltip\Load_Tooltip.xml"/>
<Include file="DataTexts\Load_DataTexts.xml"/> <Include file="DataTexts\Load_DataTexts.xml"/>
<Include file="ActionBars\Load_ActionBars.xml"/> <Include file="ActionBars\Load_ActionBars.xml"/>
<Include file="UnitFrames\Load_UnitFrames.xml"/>
<Include file="Maps\Load_Maps.xml"/> <Include file="Maps\Load_Maps.xml"/>
<Include file="Misc\Load_Misc.xml"/> <Include file="Misc\Load_Misc.xml"/>
<Include file="Chat\Load_Chat.xml"/> <Include file="Chat\Load_Chat.xml"/>
@@ -0,0 +1,297 @@
local E, L, V, P, G = unpack(ElvUI)
local UF = E:GetModule("UnitFrames");
local ns = oUF
local ElvUF = ns.oUF
local _G = _G;
local setmetatable, getfenv, setfenv = setmetatable, getfenv, setfenv;
local type, unpack, select, pairs = type, unpack, select, pairs;
local min, random = math.min, math.random;
local format = string.format;
local UnitMana = UnitMana;
local UnitManaMax = UnitManaMax;
local UnitHealth = UnitHealth;
local UnitHealthMax = UnitHealthMax;
local UnitName = UnitName;
local UnitClass = UnitClass;
local InCombatLockdown = InCombatLockdown;
local UnregisterUnitWatch = UnregisterUnitWatch;
local RegisterUnitWatch = RegisterUnitWatch;
local RegisterStateDriver = RegisterStateDriver;
local LOCALIZED_CLASS_NAMES_MALE = LOCALIZED_CLASS_NAMES_MALE;
local CLASS_SORT_ORDER = CLASS_SORT_ORDER;
local MAX_RAID_MEMBERS = MAX_RAID_MEMBERS;
local attributeBlacklist = {["showRaid"] = true, ["showParty"] = true, ["showSolo"] = true}
local configEnv
local originalEnvs = {}
local overrideFuncs = {}
local function createConfigEnv()
if( configEnv ) then return end
configEnv = setmetatable({
UnitMana = function (unit, displayType)
if(unit:find("target") or unit:find("focus")) then
return UnitMana(unit, displayType);
end
return random(1, UnitManaMax(unit, displayType) or 1);
end,
UnitHealth = function(unit)
if(unit:find("target") or unit:find("focus")) then
return UnitHealth(unit);
end
return random(1, UnitHealthMax(unit));
end,
UnitName = function(unit)
if(unit:find("target") or unit:find("focus")) then
return UnitName(unit);
end
if(E.CreditsList) then
local max = #E.CreditsList;
return E.CreditsList[random(1, max)];
end
return "Test Name";
end,
UnitClass = function(unit)
if(unit:find("target") or unit:find("focus")) then
return UnitClass(unit);
end
local classToken = CLASS_SORT_ORDER[random(1, #(CLASS_SORT_ORDER))];
return LOCALIZED_CLASS_NAMES_MALE[classToken], classToken;
end,
Hex = function(r, g, b)
if(type(r) == "table") then
if(r.r) then r, g, b = r.r, r.g, r.b; else r, g, b = unpack(r); end
end
return format("|cff%02x%02x%02x", r*255, g*255, b*255);
end,
ColorGradient = ElvUF.ColorGradient,
}, {
__index = _G,
__newindex = function(_, key, value) _G[key] = value end,
})
overrideFuncs["namecolor"] = ElvUF.Tags.Methods["namecolor"]
overrideFuncs["name:veryshort"] = ElvUF.Tags.Methods["name:veryshort"]
overrideFuncs["name:short"] = ElvUF.Tags.Methods["name:short"]
overrideFuncs["name:medium"] = ElvUF.Tags.Methods["name:medium"]
overrideFuncs["name:long"] = ElvUF.Tags.Methods["name:long"]
overrideFuncs["healthcolor"] = ElvUF.Tags.Methods["healthcolor"]
overrideFuncs["health:current"] = ElvUF.Tags.Methods["health:current"]
overrideFuncs["health:deficit"] = ElvUF.Tags.Methods["health:deficit"]
overrideFuncs["health:current-percent"] = ElvUF.Tags.Methods["health:current-percent"]
overrideFuncs["health:current-max"] = ElvUF.Tags.Methods["health:current-max"]
overrideFuncs["health:current-max-percent"] = ElvUF.Tags.Methods["health:current-max-percent"]
overrideFuncs["health:max"] = ElvUF.Tags.Methods["health:max"]
overrideFuncs["health:percent"] = ElvUF.Tags.Methods["health:percent"]
overrideFuncs["powercolor"] = ElvUF.Tags.Methods["powercolor"]
overrideFuncs["power:current"] = ElvUF.Tags.Methods["power:current"]
overrideFuncs["power:deficit"] = ElvUF.Tags.Methods["power:deficit"]
overrideFuncs["power:current-percent"] = ElvUF.Tags.Methods["power:current-percent"]
overrideFuncs["power:current-max"] = ElvUF.Tags.Methods["power:current-max"]
overrideFuncs["power:current-max-percent"] = ElvUF.Tags.Methods["power:current-max-percent"]
overrideFuncs["power:max"] = ElvUF.Tags.Methods["power:max"]
overrideFuncs["power:percent"] = ElvUF.Tags.Methods["power:percent"]
end
function UF:ForceShow(frame)
if InCombatLockdown() then return; end
if not frame.isForced then
frame.oldUnit = frame.unit
frame.unit = "player"
frame.isForced = true;
frame.oldOnUpdate = frame:GetScript("OnUpdate")
end
frame:SetScript("OnUpdate", nil)
frame.forceShowAuras = true
UnregisterUnitWatch(frame)
RegisterUnitWatch(frame, true)
frame:Show()
if frame:IsVisible() and frame.Update then
frame:Update()
end
if(_G[frame:GetName().."Target"]) then
self:ForceShow(_G[frame:GetName().."Target"]);
end
if(_G[frame:GetName().."Pet"]) then
self:ForceShow(_G[frame:GetName().."Pet"]);
end
end
function UF:UnforceShow(frame)
if InCombatLockdown() then return; end
if not frame.isForced then
return
end
frame.forceShowAuras = nil
frame.isForced = nil
-- Ask the SecureStateDriver to show/hide the frame for us
UnregisterUnitWatch(frame)
RegisterUnitWatch(frame)
if frame.oldOnUpdate then
frame:SetScript("OnUpdate", frame.oldOnUpdate)
frame.oldOnUpdate = nil
end
frame.unit = frame.oldUnit or frame.unit
-- If we're visible force an update so everything is properly in a
-- non-config mode state
if frame:IsVisible() and frame.Update then
frame:Update()
end
if(_G[frame:GetName().."Target"]) then
self:UnforceShow(_G[frame:GetName().."Target"])
end
if(_G[frame:GetName().."Pet"]) then
self:UnforceShow(_G[frame:GetName().."Pet"])
end
end
function UF:ShowChildUnits(header, ...)
header.isForced = true
for i=1, select("#", ...) do
local frame = select(i, ...)
frame:RegisterForClicks(nil)
frame:SetID(i)
frame.TargetGlow:SetAlpha(0)
self:ForceShow(frame)
end
end
function UF:UnshowChildUnits(header, ...)
header.isForced = nil
for i=1, select("#", ...) do
local frame = select(i, ...)
frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
frame.TargetGlow:SetAlpha(1)
self:UnforceShow(frame)
end
end
local function OnAttributeChanged(self)
if not self:GetParent().forceShow and not self.forceShow then return; end
if not self:IsShown() then return end
local db = self.db or self:GetParent().db
local maxUnits = MAX_RAID_MEMBERS
local startingIndex = db.raidWideSorting and -(min(db.numGroups * (db.groupsPerRowCol * 5), maxUnits) + 1) or -4
if self:GetAttribute("startingIndex") ~= startingIndex then
self:SetAttribute("startingIndex", startingIndex)
UF:ShowChildUnits(self, self:GetChildren())
end
end
function UF:HeaderConfig(header, configMode)
if InCombatLockdown() then return; end
createConfigEnv()
header.forceShow = configMode
header.forceShowAuras = configMode
header.isForced = configMode
if configMode then
for _, func in pairs(overrideFuncs) do
if type(func) == "function" then
if not originalEnvs[func] then
originalEnvs[func] = getfenv(func)
setfenv(func, configEnv)
end
end
end
RegisterStateDriver(header, "visibility", "show")
else
for func, env in pairs(originalEnvs) do
setfenv(func, env)
originalEnvs[func] = nil
end
RegisterStateDriver(header, "visibility", header.db.visibility)
if(header:GetScript("OnEvent")) then
header:GetScript("OnEvent")(header, "PLAYER_ENTERING_WORLD");
end
end
for i=1, #header.groups do
local group = header.groups[i]
if group:IsShown() then
group.forceShow = header.forceShow
group.forceShowAuras = header.forceShowAuras
group:HookScript("OnAttributeChanged", OnAttributeChanged)
if configMode then
for key in pairs(attributeBlacklist) do
group:SetAttribute(key, nil)
end
OnAttributeChanged(group)
group:Update()
else
for key in pairs(attributeBlacklist) do
group:SetAttribute(key, true)
end
UF:UnshowChildUnits(group, group:GetChildren())
group:SetAttribute("startingIndex", 1)
group:Update()
end
end
end
UF["headerFunctions"][header.groupName]:AdjustVisibility(header);
end
function UF:PLAYER_REGEN_DISABLED()
for _, header in pairs(UF["headers"]) do
if header.forceShow then
self:HeaderConfig(header)
end
end
for _, unit in pairs(UF["units"]) do
local frame = self[unit]
if frame and frame.forceShow then
self:UnforceShow(frame)
end
end
for i=1, 5 do
if self["arena"..i] and self["arena"..i].isForced then
self:UnforceShow(self["arena"..i])
end
end
for i=1, 4 do
if self["boss"..i] and self["boss"..i].isForced then
self:UnforceShow(self["boss"..i])
end
end
for i=1, 4 do
if self["party"..i] and self["party"..i].isForced then
self:UnforceShow(self["party"..i])
end
end
end
UF:RegisterEvent("PLAYER_REGEN_DISABLED")
@@ -0,0 +1,218 @@
local E, L, V, P, G = unpack(ElvUI)
local UF = E:GetModule("UnitFrames")
local random = random
local CreateFrame = CreateFrame
local UnitIsTapped = UnitIsTapped
local UnitIsTappedByPlayer = UnitIsTappedByPlayer
local UnitReaction = UnitReaction
local UnitIsPlayer = UnitIsPlayer
local UnitClass = UnitClass
local UnitIsDeadOrGhost = UnitIsDeadOrGhost
local ns = oUF
local ElvUF = ns.oUF
assert(ElvUF, "ElvUI was unable to locate oUF.")
function UF:Construct_HealthBar(frame, bg, text, textPos)
local health = CreateFrame("StatusBar", nil, frame)
UF["statusbars"][health] = true
health:SetFrameLevel(10)
health.PostUpdate = self.PostUpdateHealth
CreateStatusBarTexturePointer(health)
if bg then
health.bg = health:CreateTexture(nil, "BORDER")
health.bg:SetAllPoints()
health.bg:SetTexture(E["media"].blankTex)
health.bg.multiplier = 0.25
end
if text then
health.value = frame.RaisedElementParent:CreateFontString(nil, "OVERLAY")
UF:Configure_FontString(health.value)
local x = -2
if textPos == "LEFT" then
x = 2
end
health.value:SetPoint(textPos, health, textPos, x, 0)
end
health.colorTapping = true
health.colorDisconnected = true
E:CreateBackdrop(health, "Default", nil, nil, self.thinBorders, true)
return health
end
function UF:Configure_HealthBar(frame)
if not frame.VARIABLES_SET then return end
local db = frame.db
local health = frame.Health
health.Smooth = self.db.smoothbars
health.SmoothSpeed = self.db.smoothSpeed * 10
if health.value then
local attachPoint = self:GetObjectAnchorPoint(frame, db.health.attachTextTo)
health.value:ClearAllPoints()
health.value:SetPoint(db.health.position, attachPoint, db.health.position, db.health.xOffset, db.health.yOffset)
frame:Tag(health.value, db.health.text_format)
end
health.colorSmooth = nil
health.colorHealth = nil
health.colorClass = nil
health.colorReaction = nil
if db.colorOverride and db.colorOverride == "FORCE_ON" then
health.colorClass = true
health.colorReaction = true
elseif db.colorOverride and db.colorOverride == "FORCE_OFF" then
if self.db["colors"].colorhealthbyvalue == true then
health.colorSmooth = true
else
health.colorHealth = true
end
else
if self.db.colors.healthclass ~= true then
if self.db.colors.colorhealthbyvalue == true then
health.colorSmooth = true
else
health.colorHealth = true
end
else
health.colorClass = (not self.db.colors.forcehealthreaction)
health.colorReaction = true
end
end
health:ClearAllPoints()
if frame.ORIENTATION == "LEFT" then
health:SetWidth(frame.UNIT_WIDTH - (frame.BORDER + frame.SPACING) - (frame.HAPPINESS_WIDTH or 0))
health:SetHeight(frame.UNIT_HEIGHT - frame.POWERBAR_HEIGHT - (frame.BORDER + frame.SPACING) - frame.CLASSBAR_YOFFSET)
if frame.USE_POWERBAR_OFFSET then
health:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -frame.BORDER - frame.SPACING - frame.POWERBAR_OFFSET - (frame.HAPPINESS_WIDTH or 0), -frame.BORDER - frame.SPACING - frame.CLASSBAR_YOFFSET)
health:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.PORTRAIT_WIDTH + frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING + frame.POWERBAR_OFFSET)
elseif frame.POWERBAR_DETACHED or not frame.USE_POWERBAR or frame.USE_INSET_POWERBAR then
health:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.PORTRAIT_WIDTH + frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
elseif frame.USE_MINI_POWERBAR then
health:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.PORTRAIT_WIDTH + frame.BORDER + frame.SPACING, frame.SPACING + (frame.POWERBAR_HEIGHT/2))
else
health:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.PORTRAIT_WIDTH + frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
end
elseif frame.ORIENTATION == "RIGHT" then
health:SetPoint("TOPLEFT", frame, "TOPLEFT", frame.BORDER + frame.SPACING + (frame.HAPPINESS_WIDTH or 0), -frame.BORDER - frame.SPACING - frame.CLASSBAR_YOFFSET)
if frame.USE_POWERBAR_OFFSET then
health:SetPoint("TOPLEFT", frame, "TOPLEFT", frame.BORDER + frame.SPACING + frame.POWERBAR_OFFSET + (frame.HAPPINESS_WIDTH or 0), -frame.BORDER - frame.SPACING - frame.CLASSBAR_YOFFSET)
health:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -frame.PORTRAIT_WIDTH - frame.BORDER - frame.SPACING, frame.BORDER + frame.SPACING + frame.POWERBAR_OFFSET)
elseif frame.POWERBAR_DETACHED or not frame.USE_POWERBAR or frame.USE_INSET_POWERBAR then
health:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -frame.PORTRAIT_WIDTH - frame.BORDER - frame.SPACING, frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
elseif frame.USE_MINI_POWERBAR then
health:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -frame.PORTRAIT_WIDTH - frame.BORDER - frame.SPACING, frame.SPACING + (frame.POWERBAR_HEIGHT/2))
else
health:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -frame.PORTRAIT_WIDTH - frame.BORDER - frame.SPACING, frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
end
elseif frame.ORIENTATION == "MIDDLE" then
health:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -frame.BORDER - frame.SPACING - (frame.HAPPINESS_WIDTH or 0), -frame.BORDER - frame.SPACING - frame.CLASSBAR_YOFFSET)
if frame.USE_POWERBAR_OFFSET then
health:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -frame.BORDER - frame.SPACING - frame.POWERBAR_OFFSET, -frame.BORDER - frame.SPACING - frame.CLASSBAR_YOFFSET)
health:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.BORDER + frame.SPACING + frame.POWERBAR_OFFSET, frame.BORDER + frame.SPACING + frame.POWERBAR_OFFSET)
elseif frame.POWERBAR_DETACHED or not frame.USE_POWERBAR or frame.USE_INSET_POWERBAR then
health:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.BORDER + frame.SPACING + frame.POWERBAR_OFFSET, frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
elseif frame.USE_MINI_POWERBAR then
health:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.BORDER + frame.SPACING, frame.SPACING + (frame.POWERBAR_HEIGHT/2))
else
health:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.PORTRAIT_WIDTH + frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING + frame.BOTTOM_OFFSET)
end
end
health.bg:ClearAllPoints()
if not frame.USE_PORTRAIT_OVERLAY then
health.bg:SetParent(health)
health.bg:SetAllPoints()
else
health.bg:SetPoint("BOTTOMLEFT", health.texturePointer, "BOTTOMRIGHT")
health.bg:SetPoint("TOPRIGHT", health)
health.bg:SetParent(frame.Portrait.overlay)
end
if db.health then
if db.health.orientation then
health:SetOrientation(db.health.orientation)
end
if db.health.frequentUpdates then
health.frequentUpdates = db.health.frequentUpdates
end
end
UF:ToggleTransparentStatusBar(UF.db.colors.transparentHealth, frame.Health, frame.Health.bg, (frame.USE_PORTRAIT and frame.USE_PORTRAIT_OVERLAY) ~= true)
frame:UpdateElement("Health")
end
function UF:GetHealthBottomOffset(frame)
local bottomOffset = 0
if frame.USE_POWERBAR and not frame.POWERBAR_DETACHED and not frame.USE_INSET_POWERBAR then
bottomOffset = bottomOffset + frame.POWERBAR_HEIGHT - (frame.BORDER-frame.SPACING)
end
if frame.USE_INFO_PANEL then
bottomOffset = bottomOffset + frame.INFO_PANEL_HEIGHT - (frame.BORDER-frame.SPACING)
end
return bottomOffset
end
function UF:PostUpdateHealth(unit, min, max)
local parent = self:GetParent()
if parent.isForced then
min = random(1, max)
self:SetValue(min)
end
local r, g, b = self:GetStatusBarColor()
local colors = E.db["unitframe"]["colors"]
if ((colors.healthclass == true and colors.colorhealthbyvalue == true) or (colors.colorhealthbyvalue and parent.isForced)) and not (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit)) then
local newr, newg, newb = ElvUF.ColorGradient(min, max, 1, 0, 0, 1, 1, 0, r, g, b)
self:SetStatusBarColor(newr, newg, newb)
if self.bg and self.bg.multiplier then
local mu = self.bg.multiplier
self.bg:SetVertexColor(newr * mu, newg * mu, newb * mu)
end
end
if colors.classbackdrop then
local reaction = UnitReaction(unit, "player")
local t
if UnitIsPlayer(unit) then
local _, class = UnitClass(unit)
t = parent.colors.class[class]
elseif(reaction) then
t = parent.colors.reaction[reaction]
end
if t then
self.bg:SetVertexColor(t[1], t[2], t[3])
end
end
if colors.customhealthbackdrop then
local backdrop = colors.health_backdrop
self.bg:SetVertexColor(backdrop.r, backdrop.g, backdrop.b)
end
if colors.useDeadBackdrop and UnitIsDeadOrGhost(unit) then
local backdrop = colors.health_backdrop_dead
self.bg:SetVertexColor(backdrop.r, backdrop.g, backdrop.b)
end
end
@@ -0,0 +1,46 @@
local E, L, V, P, G = unpack(ElvUI)
local UF = E:GetModule("UnitFrames")
function UF:Construct_InfoPanel(frame)
local infoPanel = CreateFrame("Frame", nil, frame)
infoPanel:SetFrameLevel(7)
local thinBorders = self.thinBorders
infoPanel:CreateBackdrop("Default", true, nil, thinBorders, true)
return infoPanel
end
function UF:Configure_InfoPanel(frame)
if(not frame.VARIABLES_SET) then return end
local db = frame.db
if(frame.USE_INFO_PANEL) then
frame.InfoPanel:Show()
frame.InfoPanel:ClearAllPoints()
if(frame.ORIENTATION == "RIGHT" and not (frame.unitframeType == "arena")) then
frame.InfoPanel:Point("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -frame.BORDER - frame.SPACING, frame.BORDER + frame.SPACING)
if(frame.USE_POWERBAR and not frame.USE_INSET_POWERBAR and not frame.POWERBAR_DETACHED) then
frame.InfoPanel:Point("TOPLEFT", frame.Power.backdrop, "BOTTOMLEFT", frame.BORDER - frame.HAPPINESS_WIDTH, -(frame.SPACING*3))
else
frame.InfoPanel:Point("TOPLEFT", frame.Health.backdrop, "BOTTOMLEFT", frame.BORDER - frame.HAPPINESS_WIDTH, -(frame.SPACING*3))
end
else
frame.InfoPanel:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", frame.BORDER + frame.SPACING, frame.BORDER + frame.SPACING)
if(frame.USE_POWERBAR and not frame.USE_INSET_POWERBAR and not frame.POWERBAR_DETACHED) then
frame.InfoPanel:Point("TOPRIGHT", frame.Power.backdrop, "BOTTOMRIGHT", -frame.BORDER + frame.HAPPINESS_WIDTH, -(frame.SPACING*3))
else
frame.InfoPanel:Point("TOPRIGHT", frame.Health.backdrop, "BOTTOMRIGHT", -frame.BORDER + frame.HAPPINESS_WIDTH, -(frame.SPACING*3))
end
end
local thinBorders = self.thinBorders
if(db.infoPanel.transparent) then
frame.InfoPanel.backdrop:SetTemplate("Transparent", nil, nil, thinBorders, true)
else
frame.InfoPanel.backdrop:SetTemplate("Default", true, nil, thinBorders, true)
end
else
frame.InfoPanel:Hide()
end
end
@@ -0,0 +1,7 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="Health.lua"/>
<Script file="Name.lua"/>
<Script file="Portrait.lua"/>
<Script file="Power.lua"/>
<Script file="InfoPanel.lua"/>
</Ui>
@@ -0,0 +1,48 @@
local E, L, V, P, G = unpack(ElvUI);
local UF = E:GetModule("UnitFrames");
local UnitIsPlayer = UnitIsPlayer
function UF:Construct_NameText(frame)
local name = frame.RaisedElementParent:CreateFontString(nil, "OVERLAY")
UF:Configure_FontString(name)
name:SetPoint("CENTER", frame.Health)
return name
end
function UF:UpdateNameSettings(frame, childType)
local db = frame.db
if childType == "pet" then
db = frame.db.petsGroup
elseif childType == "target" then
db = frame.db.targetsGroup
end
local name = frame.Name
if not db.power or not db.power.enable or not db.power.hideonnpc then
local attachPoint = self:GetObjectAnchorPoint(frame, db.name.attachTextTo)
name:ClearAllPoints()
name:SetPoint(db.name.position, attachPoint, db.name.position, db.name.xOffset, db.name.yOffset)
end
frame:Tag(name, db.name.text_format)
end
function UF:PostNamePosition(frame, unit)
if not frame.Power.value:IsShown() then return end
local db = frame.db
if UnitIsPlayer(unit) or (db.power and not db.power.enable) then
local position = db.name.position
local attachPoint = self:GetObjectAnchorPoint(frame, db.name.attachTextTo)
frame.Power.value:SetAlpha(1)
frame.Name:ClearAllPoints()
frame.Name:SetPoint(position, attachPoint, position, db.name.xOffset, db.name.yOffset)
else
frame.Power.value:SetAlpha(db.power.hideonnpc and 0 or 1)
frame.Name:ClearAllPoints()
frame.Name:SetPoint(frame.Power.value:GetPoint())
end
end
@@ -0,0 +1,115 @@
local E, L, V, P, G = unpack(ElvUI);
local UF = E:GetModule("UnitFrames");
local CreateFrame = CreateFrame;
function UF:Construct_Portrait(frame, type)
local portrait;
if(type == "texture") then
local backdrop = CreateFrame("Frame", nil, frame);
portrait = frame:CreateTexture(nil, "OVERLAY");
portrait:SetTexCoord(0.15, 0.85, 0.15, 0.85);
E:SetOutside(backdrop, portrait);
backdrop:SetFrameLevel(frame:GetFrameLevel());
E:SetTemplate(backdrop, "Default");
portrait.backdrop = backdrop;
else
portrait = CreateFrame("PlayerModel", nil, frame);
E:CreateBackdrop(portrait, "Default", nil, nil, self.thinBorders, true)
end
portrait.PostUpdate = self.PortraitUpdate;
portrait.overlay = CreateFrame("Frame", nil, frame);
portrait.overlay:SetFrameLevel(frame.Health:GetFrameLevel() + 5);
return portrait;
end
function UF:Configure_Portrait(frame, dontHide)
if(not frame.VARIABLES_SET) then return; end
local db = frame.db;
if(frame.Portrait and not dontHide) then
frame.Portrait:Hide();
frame.Portrait:ClearAllPoints();
frame.Portrait.backdrop:Hide();
end
frame.Portrait = db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D;
local portrait = frame.Portrait;
if(frame.USE_PORTRAIT) then
if(not frame:IsElementEnabled("Portrait")) then
frame:EnableElement("Portrait", frame.unit);
end
local color = E.db.unitframe.colors.borderColor
portrait.backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
portrait:ClearAllPoints();
portrait.backdrop:ClearAllPoints();
if(frame.USE_PORTRAIT_OVERLAY) then
if(db.portrait.style == "3D") then
portrait:SetFrameLevel(frame.Health:GetFrameLevel());
else
portrait:SetParent(frame.Health);
end
portrait:SetAllPoints(frame.Health);
portrait:SetAlpha(0.35);
if(not dontHide) then
portrait:Show();
end
portrait.backdrop:Hide();
else
portrait:SetAlpha(1);
if(not dontHide) then
portrait:Show();
end
portrait.backdrop:Show();
if(db.portrait.style == "3D") then
portrait:SetFrameLevel(frame.Health:GetFrameLevel() - 4);
else
portrait:SetParent(frame.Health);
end
if(frame.ORIENTATION == "LEFT") then
portrait.backdrop:SetPoint("TOPLEFT", frame, "TOPLEFT", frame.SPACING, frame.USE_MINI_CLASSBAR and -(frame.CLASSBAR_YOFFSET+frame.SPACING) or -frame.SPACING);
if(frame.USE_MINI_POWERBAR or frame.USE_POWERBAR_OFFSET or not frame.USE_POWERBAR or frame.USE_INSET_POWERBAR or frame.POWERBAR_DETACHED) then
portrait.backdrop:SetPoint("BOTTOMRIGHT", frame.Health.backdrop, "BOTTOMLEFT", frame.BORDER - frame.SPACING*3, 0);
else
portrait.backdrop:SetPoint("BOTTOMRIGHT", frame.Power.backdrop, "BOTTOMLEFT", frame.BORDER - frame.SPACING*3, 0);
end
elseif(frame.ORIENTATION == "RIGHT") then
portrait.backdrop:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -frame.SPACING, frame.USE_MINI_CLASSBAR and -(frame.CLASSBAR_YOFFSET+frame.SPACING) or -frame.SPACING);
if(frame.USE_MINI_POWERBAR or frame.USE_POWERBAR_OFFSET or not frame.USE_POWERBAR or frame.USE_INSET_POWERBAR or frame.POWERBAR_DETACHED) then
portrait.backdrop:SetPoint("BOTTOMLEFT", frame.Health.backdrop, "BOTTOMRIGHT", -frame.BORDER + frame.SPACING*3, 0);
else
portrait.backdrop:SetPoint("BOTTOMLEFT", frame.Power.backdrop, "BOTTOMRIGHT", -frame.BORDER + frame.SPACING*3, 0);
end
end
E:SetInside(portrait, portrait.backdrop, frame.BORDER);
end
else
if(frame:IsElementEnabled("Portrait")) then
frame:DisableElement("Portrait");
portrait:Hide();
portrait.backdrop:Hide();
end
end
end
function UF:PortraitUpdate()
local db = self:GetParent().db;
if(not db) then return; end
local portrait = db.portrait;
if(portrait.enable and self:GetParent().USE_PORTRAIT_OVERLAY) then
self:SetAlpha(0);
self:SetAlpha(0.35);
else
self:SetAlpha(1)
end
end
@@ -0,0 +1,228 @@
local E, L, V, P, G = unpack(ElvUI)
local UF = E:GetModule("UnitFrames")
local random = random
local CreateFrame = CreateFrame
local ns = oUF
local ElvUF = ns.oUF
assert(ElvUF, "ElvUI was unable to locate oUF.")
function UF:Construct_PowerBar(frame, bg, text, textPos)
local power = CreateFrame("StatusBar", nil, frame)
UF["statusbars"][power] = true
power.PostUpdate = self.PostUpdatePower
CreateStatusBarTexturePointer(power)
if bg then
power.bg = power:CreateTexture(nil, "BORDER")
power.bg:SetAllPoints()
power.bg:SetTexture(E["media"].blankTex)
power.bg.multiplier = 0.2
end
if text then
power.value = frame.RaisedElementParent:CreateFontString(nil, "OVERLAY")
power.value.frequentUpdates = true
UF:Configure_FontString(power.value)
local x = -2
if textPos == "LEFT" then
x = 2
end
power.value:SetPoint(textPos, frame.Health, textPos, x, 0)
end
power.colorDisconnected = false
power.colorTapping = false
E:CreateBackdrop(power, "Default", nil, nil, self.thinBorders)
return power
end
function UF:Configure_Power(frame)
if not frame.VARIABLES_SET then return end
local db = frame.db
local power = frame.Power
if frame.USE_POWERBAR then
if not frame:IsElementEnabled("Power") then
frame:EnableElement("Power", frame.unit)
power:Show()
end
power.Smooth = self.db.smoothbars
power.SmoothSpeed = self.db.smoothSpeed * 10
local attachPoint = self:GetObjectAnchorPoint(frame, db.power.attachTextTo)
power.value:ClearAllPoints()
power.value:SetPoint(db.power.position, attachPoint, db.power.position, db.power.xOffset, db.power.yOffset)
frame:Tag(power.value, db.power.text_format)
if db.power.attachTextTo == "Power" then
power.value:SetParent(power)
else
power.value:SetParent(frame.RaisedElementParent)
end
power.colorClass = nil
power.colorReaction = nil
power.colorPower = nil
if self.db["colors"].powerclass then
power.colorClass = true
power.colorReaction = true
else
power.colorPower = true
end
local heightChanged = false
if (not self.thinBorders and not E.PixelMode) and frame.POWERBAR_HEIGHT < 7 then
frame.POWERBAR_HEIGHT = 7
if(db.power) then db.power.height = 7 end
heightChanged = true
elseif (self.thinBorders or E.PixelMode) and frame.POWERBAR_HEIGHT < 3 then
frame.POWERBAR_HEIGHT = 3
if db.power then db.power.height = 3 end
heightChanged = true
end
if heightChanged then
frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
UF:Configure_HealthBar(frame)
end
power:ClearAllPoints()
if frame.POWERBAR_DETACHED then
power:SetWidth(frame.POWERBAR_WIDTH - ((frame.BORDER + frame.SPACING)*2))
power:SetHeight(frame.POWERBAR_HEIGHT - ((frame.BORDER + frame.SPACING)*2))
if not power.Holder or (power.Holder and not power.Holder.mover) then
power.Holder = CreateFrame("Frame", nil, power)
power.Holder:SetWidth(frame.POWERBAR_WIDTH)
power.Holder:SetHeight(frame.POWERBAR_HEIGHT)
power.Holder:SetPoint("BOTTOM", frame, "BOTTOM", 0, -20)
power:ClearAllPoints()
power:SetPoint("BOTTOMLEFT", power.Holder, "BOTTOMLEFT", frame.BORDER+frame.SPACING, frame.BORDER+frame.SPACING)
if(frame.unitframeType and frame.unitframeType == "player") then
E:CreateMover(power.Holder, "PlayerPowerBarMover", L["Player Powerbar"], nil, nil, nil, "ALL,SOLO")
elseif(frame.unitframeType and frame.unitframeType == "target") then
E:CreateMover(power.Holder, "TargetPowerBarMover", L["Target Powerbar"], nil, nil, nil, "ALL,SOLO")
end
else
power.Holder:SetWidth(frame.POWERBAR_WIDTH)
power.Holder:SetHeight(frame.POWERBAR_HEIGHT)
power:ClearAllPoints()
power:SetPoint("BOTTOMLEFT", power.Holder, "BOTTOMLEFT", frame.BORDER+frame.SPACING, frame.BORDER+frame.SPACING)
power.Holder.mover:SetScale(1)
power.Holder.mover:SetAlpha(1)
end
power:SetFrameLevel(50)
elseif frame.USE_POWERBAR_OFFSET then
if frame.ORIENTATION == "LEFT" then
power:SetPoint("TOPRIGHT", frame.Health, "TOPRIGHT", frame.POWERBAR_OFFSET + frame.HAPPINESS_WIDTH, -frame.POWERBAR_OFFSET)
power:SetPoint("BOTTOMLEFT", frame.Health, "BOTTOMLEFT", frame.POWERBAR_OFFSET, -frame.POWERBAR_OFFSET)
elseif frame.ORIENTATION == "MIDDLE" then
power:SetPoint("TOPLEFT", frame, "TOPLEFT", frame.BORDER + frame.SPACING, -frame.POWERBAR_OFFSET -frame.CLASSBAR_YOFFSET)
power:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -frame.BORDER - frame.SPACING, frame.BORDER)
else
power:SetPoint("TOPLEFT", frame.Health, "TOPLEFT", -frame.POWERBAR_OFFSET - frame.HAPPINESS_WIDTH, -frame.POWERBAR_OFFSET)
power:SetPoint("BOTTOMRIGHT", frame.Health, "BOTTOMRIGHT", -frame.POWERBAR_OFFSET, -frame.POWERBAR_OFFSET)
end
power:SetFrameLevel(frame.Health:GetFrameLevel() -5)
elseif frame.USE_INSET_POWERBAR then
power:SetHeight(frame.POWERBAR_HEIGHT - ((frame.BORDER + frame.SPACING)*2))
power:SetPoint("BOTTOMLEFT", frame.Health, "BOTTOMLEFT", frame.BORDER + (frame.BORDER*2), frame.BORDER + (frame.BORDER*2))
power:SetPoint("BOTTOMRIGHT", frame.Health, "BOTTOMRIGHT", -(frame.BORDER + (frame.BORDER*2)), frame.BORDER + (frame.BORDER*2))
power:SetFrameLevel(50)
elseif frame.USE_MINI_POWERBAR then
power:SetWidth(frame.POWERBAR_HEIGHT - ((frame.BORDER + frame.SPACING)*2))
if frame.ORIENTATION == "LEFT" then
power:SetWidth(frame.POWERBAR_WIDTH - frame.BORDER*2)
power:SetPoint("RIGHT", frame, "BOTTOMRIGHT", -(frame.BORDER*2 + 4) -frame.HAPPINESS_WIDTH, ((frame.POWERBAR_HEIGHT-frame.BORDER)/2))
elseif frame.ORIENTATION == "RIGHT" then
power:SetWidth(frame.POWERBAR_WIDTH - frame.BORDER*2)
power:SetPoint("LEFT", frame, "BOTTOMLEFT", (frame.BORDER*2 + 4) +frame.HAPPINESS_WIDTH, ((frame.POWERBAR_HEIGHT-frame.BORDER)/2))
else
power:SetPoint("LEFT", frame, "BOTTOMLEFT", (frame.BORDER*2 + 4), ((frame.POWERBAR_HEIGHT-frame.BORDER)/2))
power:SetPoint("RIGHT", frame, "BOTTOMRIGHT", -(frame.BORDER*2 + 4) -frame.HAPPINESS_WIDTH, ((frame.POWERBAR_HEIGHT-frame.BORDER)/2))
end
power:SetFrameLevel(50)
else
power:SetPoint("TOPRIGHT", frame.Health.backdrop, "BOTTOMRIGHT", -frame.BORDER, -frame.SPACING*3)
power:SetPoint("TOPLEFT", frame.Health.backdrop, "BOTTOMLEFT", frame.BORDER, -frame.SPACING*3)
power:SetHeight(frame.POWERBAR_HEIGHT - ((frame.BORDER + frame.SPACING)*2))
power:SetFrameLevel(frame.Health:GetFrameLevel() - 5)
end
if not frame.POWERBAR_DETACHED then
if power.Holder and power.Holder.mover then
power.Holder.mover:SetScale(0.0001)
power.Holder.mover:SetAlpha(0)
end
end
if db.power.strataAndLevel and db.power.strataAndLevel.useCustomStrata then
power:SetFrameStrata(db.power.strataAndLevel.frameStrata)
else
power:SetFrameStrata("LOW")
end
if db.power.strataAndLevel and db.power.strataAndLevel.useCustomLevel then
power:SetFrameLevel(db.power.strataAndLevel.frameLevel)
power.backdrop:SetFrameLevel(power:GetFrameLevel() - 1)
end
if frame.POWERBAR_DETACHED and db.power.parent == "UIPARENT" then
power:SetParent(E.UIParent)
else
power:SetParent(frame)
end
elseif frame:IsElementEnabled("Power") then
frame:DisableElement("Power")
power:Hide()
end
if frame.DruidAltMana then
if(db.power.druidMana) then
frame:EnableElement("DruidAltMana")
else
frame:DisableElement("DruidAltMana")
frame.DruidAltMana:Hide()
end
end
if frame.Power then
UF:ToggleTransparentStatusBar(UF.db.colors.transparentPower, frame.Power, frame.Power.bg)
end
end
function UF:PostUpdatePower(unit, cur, max)
local parent = self:GetParent()
if parent.isForced then
local pType = random(0, 3)
local color = ElvUF["colors"].power[pType]
cur = random(1, max)
self:SetValue(cur)
if not self.colorClass then
self:SetStatusBarColor(color[1], color[2], color[3])
local mu = self.bg.multiplier or 1
self.bg:SetVertexColor(color[1] * mu, color[2] * mu, color[3] * mu)
end
end
local db = parent.db
if db and db.power and db.power.hideonnpc then
UF:PostNamePosition(parent, unit)
end
end
@@ -0,0 +1,6 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="UnitFrames.lua"/>
<Script file="Tags.lua"/>
<Include file="Elements\Load_Elements.xml"/>
<Include file="Units\Load_Units.xml"/>
</Ui>
@@ -0,0 +1,552 @@
local E, L, V, P, G = unpack(ElvUI)
local _G = _G;
local floor = math.floor;
local format = string.format;
local GetPVPTimer = GetPVPTimer;
local GetTime = GetTime;
local UnitClass = UnitClass;
local UnitClassification = UnitClassification;
local UnitGUID = UnitGUID;
local UnitIsAFK = UnitIsAFK;
local UnitIsConnected = UnitIsConnected;
local UnitIsDND = UnitIsDND;
local UnitIsDead = UnitIsDead;
local UnitIsDeadOrGhost = UnitIsDeadOrGhost;
local UnitIsGhost = UnitIsGhost;
local UnitIsPVP = UnitIsPVP;
local UnitIsPVPFreeForAll = UnitIsPVPFreeForAll;
local UnitIsPlayer = UnitIsPlayer;
local UnitLevel = UnitLevel;
local UnitMana = UnitMana;
local UnitManaMax = UnitManaMax;
local UnitPowerType = UnitPowerType;
local UnitReaction = UnitReaction;
local DEFAULT_AFK_MESSAGE = DEFAULT_AFK_MESSAGE;
local PVP = PVP;
------------------------------------------------------------------------
-- Tags
------------------------------------------------------------------------
ElvUF.Tags.Events["afk"] = "PLAYER_FLAGS_CHANGED"
ElvUF.Tags.Methods["afk"] = function(unit)
local isAFK = UnitIsAFK(unit)
if isAFK then
return ("|cffFFFFFF[|r|cffFF0000%s|r|cFFFFFFFF]|r"):format(DEFAULT_AFK_MESSAGE)
else
return ""
end
end
ElvUF.Tags.Events["healthcolor"] = "UNIT_HEALTH UNIT_CONNECTION PLAYER_FLAGS_CHANGED"
ElvUF.Tags.Methods["healthcolor"] = function(unit)
if UnitIsDeadOrGhost(unit) or not UnitIsConnected(unit) then
return Hex(0.84, 0.75, 0.65)
else
local r, g, b = ElvUF.ColorGradient(UnitHealth(unit), UnitHealthMax(unit), 0.69, 0.31, 0.31, 0.65, 0.63, 0.35, 0.33, 0.59, 0.33)
return Hex(r, g, b)
end
end
ElvUF.Tags.Events["health:current"] = "UNIT_HEALTH UNIT_MAXHEALTH UNIT_CONNECTION PLAYER_FLAGS_CHANGED"
ElvUF.Tags.Methods["health:current"] = function(unit)
local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
if (status) then
return status
else
return E:GetFormattedText("CURRENT", UnitHealth(unit), UnitHealthMax(unit))
end
end
ElvUF.Tags.Events["health:deficit"] = "UNIT_HEALTH UNIT_MAXHEALTH UNIT_CONNECTION PLAYER_FLAGS_CHANGED"
ElvUF.Tags.Methods["health:deficit"] = function(unit)
local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
if (status) then
return status
else
return E:GetFormattedText("DEFICIT", UnitHealth(unit), UnitHealthMax(unit))
end
end
ElvUF.Tags.Events["health:current-percent"] = "UNIT_HEALTH UNIT_MAXHEALTH UNIT_CONNECTION PLAYER_FLAGS_CHANGED"
ElvUF.Tags.Methods["health:current-percent"] = function(unit)
local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
if (status) then
return status
else
return E:GetFormattedText("CURRENT_PERCENT", UnitHealth(unit), UnitHealthMax(unit))
end
end
ElvUF.Tags.Events["health:current-max"] = "UNIT_HEALTH UNIT_MAXHEALTH UNIT_CONNECTION PLAYER_FLAGS_CHANGED"
ElvUF.Tags.Methods["health:current-max"] = function(unit)
local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
if (status) then
return status
else
return E:GetFormattedText("CURRENT_MAX", UnitHealth(unit), UnitHealthMax(unit))
end
end
ElvUF.Tags.Events["health:current-max-percent"] = "UNIT_HEALTH UNIT_MAXHEALTH UNIT_CONNECTION PLAYER_FLAGS_CHANGED"
ElvUF.Tags.Methods["health:current-max-percent"] = function(unit)
local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
if (status) then
return status
else
return E:GetFormattedText("CURRENT_MAX_PERCENT", UnitHealth(unit), UnitHealthMax(unit))
end
end
ElvUF.Tags.Events["health:max"] = "UNIT_MAXHEALTH"
ElvUF.Tags.Methods["health:max"] = function(unit)
local max = UnitHealthMax(unit)
return E:GetFormattedText("CURRENT", max, max)
end
ElvUF.Tags.Events["health:percent"] = "UNIT_HEALTH UNIT_MAXHEALTH UNIT_CONNECTION PLAYER_FLAGS_CHANGED"
ElvUF.Tags.Methods["health:percent"] = function(unit)
local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
if (status) then
return status
else
return E:GetFormattedText("PERCENT", UnitHealth(unit), UnitHealthMax(unit))
end
end
ElvUF.Tags.Events["health:current-nostatus"] = "UNIT_HEALTH UNIT_MAXHEALTH";
ElvUF.Tags.Methods["health:current-nostatus"] = function(unit)
return E:GetFormattedText("CURRENT", UnitHealth(unit), UnitHealthMax(unit));
end
ElvUF.Tags.Events["health:deficit-nostatus"] = "UNIT_HEALTH UNIT_MAXHEALTH";
ElvUF.Tags.Methods["health:deficit-nostatus"] = function(unit)
return E:GetFormattedText("DEFICIT", UnitHealth(unit), UnitHealthMax(unit));
end
ElvUF.Tags.Events["health:current-percent-nostatus"] = "UNIT_HEALTH UNIT_MAXHEALTH";
ElvUF.Tags.Methods["health:current-percent-nostatus"] = function(unit)
return E:GetFormattedText("CURRENT_PERCENT", UnitHealth(unit), UnitHealthMax(unit));
end
ElvUF.Tags.Events["health:current-max-nostatus"] = "UNIT_HEALTH UNIT_MAXHEALTH";
ElvUF.Tags.Methods["health:current-max-nostatus"] = function(unit)
return E:GetFormattedText("CURRENT_MAX", UnitHealth(unit), UnitHealthMax(unit));
end
ElvUF.Tags.Events["health:current-max-percent-nostatus"] = "UNIT_HEALTH UNIT_MAXHEALTH";
ElvUF.Tags.Methods["health:current-max-percent-nostatus"] = function(unit)
return E:GetFormattedText("CURRENT_MAX_PERCENT", UnitHealth(unit), UnitHealthMax(unit));
end
ElvUF.Tags.Events["health:percent-nostatus"] = "UNIT_HEALTH UNIT_MAXHEALTH";
ElvUF.Tags.Methods["health:percent-nostatus"] = function(unit)
return E:GetFormattedText("PERCENT", UnitHealth(unit), UnitHealthMax(unit));
end
ElvUF.Tags.Events["health:deficit-percent:name"] = "UNIT_HEALTH UNIT_MAXHEALTH";
ElvUF.Tags.Methods["health:deficit-percent:name"] = function(unit)
local currentHealth = UnitHealth(unit)
local deficit = UnitHealthMax(unit) - currentHealth;
if (deficit > 0 and currentHealth > 0) then
return _TAGS["health:percent-nostatus"](unit);
else
return _TAGS["name"](unit);
end
end
ElvUF.Tags.Events["health:deficit-percent:name-long"] = "UNIT_HEALTH UNIT_MAXHEALTH"
ElvUF.Tags.Methods["health:deficit-percent:name-long"] = function(unit)
local currentHealth = UnitHealth(unit)
local deficit = UnitHealthMax(unit) - currentHealth
if (deficit > 0 and currentHealth > 0) then
return _TAGS["health:percent-nostatus"](unit)
else
return _TAGS["name:long"](unit)
end
end
ElvUF.Tags.Events["health:deficit-percent:name-medium"] = "UNIT_HEALTH UNIT_MAXHEALTH"
ElvUF.Tags.Methods["health:deficit-percent:name-medium"] = function(unit)
local currentHealth = UnitHealth(unit)
local deficit = UnitHealthMax(unit) - currentHealth
if (deficit > 0 and currentHealth > 0) then
return _TAGS["health:percent-nostatus"](unit)
else
return _TAGS["name:medium"](unit)
end
end
ElvUF.Tags.Events["health:deficit-percent:name-short"] = "UNIT_HEALTH UNIT_MAXHEALTH"
ElvUF.Tags.Methods["health:deficit-percent:name-short"] = function(unit)
local currentHealth = UnitHealth(unit)
local deficit = UnitHealthMax(unit) - currentHealth
if (deficit > 0 and currentHealth > 0) then
return _TAGS["health:percent-nostatus"](unit)
else
return _TAGS["name:short"](unit)
end
end
ElvUF.Tags.Events["health:deficit-percent:name-veryshort"] = "UNIT_HEALTH UNIT_MAXHEALTH"
ElvUF.Tags.Methods["health:deficit-percent:name-veryshort"] = function(unit)
local currentHealth = UnitHealth(unit)
local deficit = UnitHealthMax(unit) - currentHealth
if (deficit > 0 and currentHealth > 0) then
return _TAGS["health:percent-nostatus"](unit)
else
return _TAGS["name:veryshort"](unit)
end
end
ElvUF.Tags.Events["powercolor"] = "UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_RUNIC_POWER UNIT_MAXPOWER"
ElvUF.Tags.Methods["powercolor"] = function(unit)
local color = ElvUF["colors"].power[UnitPowerType(unit)]
if color then
return Hex(color[1], color[2], color[3])
else
return Hex(unpack(ElvUF["colors"].power[0]))
end
end
ElvUF.Tags.Events["power:current"] = "UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_RUNIC_POWER UNIT_MAXPOWER"
ElvUF.Tags.Methods["power:current"] = function(unit)
local min = UnitMana(unit)
return min == 0 and " " or E:GetFormattedText("CURRENT", min, UnitManaMax(unit))
end
ElvUF.Tags.Events["power:current-max"] = "UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_RUNIC_POWER UNIT_MAXPOWER"
ElvUF.Tags.Methods["power:current-max"] = function(unit)
local min = UnitMana(unit)
return min == 0 and " " or E:GetFormattedText("CURRENT_MAX", min, UnitManaMax(unit))
end
ElvUF.Tags.Events["power:current-percent"] = "UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_RUNIC_POWER UNIT_MAXPOWER"
ElvUF.Tags.Methods["power:current-percent"] = function(unit)
local min = UnitMana(unit)
return min == 0 and " " or E:GetFormattedText("CURRENT_PERCENT", min, UnitManaMax(unit))
end
ElvUF.Tags.Events["power:current-max-percent"] = "UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_RUNIC_POWER UNIT_MAXPOWER"
ElvUF.Tags.Methods["power:current-max-percent"] = function(unit)
local min = UnitMana(unit)
return min == 0 and " " or E:GetFormattedText("CURRENT_MAX_PERCENT", min, UnitManaMax(unit))
end
ElvUF.Tags.Events["power:percent"] = "UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_RUNIC_POWER UNIT_MAXPOWER"
ElvUF.Tags.Methods["power:percent"] = function(unit)
local min = UnitMana(unit)
return min == 0 and " " or E:GetFormattedText("PERCENT", min, UnitManaMax(unit))
end
ElvUF.Tags.Events["power:deficit"] = "UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_RUNIC_POWER UNIT_MAXPOWER"
ElvUF.Tags.Methods["power:deficit"] = function(unit)
return E:GetFormattedText("DEFICIT", UnitMana(unit), UnitManaMax(unit))
end
ElvUF.Tags.Events["power:max"] = "UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_MAXRUNIC_POWER"
ElvUF.Tags.Methods["power:max"] = function(unit)
local max = UnitManaMax(unit)
return E:GetFormattedText("CURRENT", max, max)
end
ElvUF.Tags.Methods["manacolor"] = function()
local altR, altG, altB = PowerBarColor["MANA"].r, PowerBarColor["MANA"].g, PowerBarColor["MANA"].b
local color = ElvUF["colors"].power["MANA"]
if color then
return Hex(color[1], color[2], color[3])
else
return Hex(altR, altG, altB)
end
end
ElvUF.Tags.Events["mana:current"] = "UNIT_MANA UNIT_MAXMANA"
ElvUF.Tags.Methods["mana:current"] = function(unit)
local min = UnitMana(unit)
return min == 0 and " " or E:GetFormattedText("CURRENT", min, UnitManaMax(unit))
end
ElvUF.Tags.Events["mana:current-max"] = "UNIT_MANA UNIT_MAXMANA"
ElvUF.Tags.Methods["mana:current-max"] = function(unit)
local min = UnitMana(unit)
return min == 0 and " " or E:GetFormattedText("CURRENT_MAX", min, UnitManaMax(unit))
end
ElvUF.Tags.Events["mana:current-percent"] = "UNIT_MANA UNIT_MAXMANA"
ElvUF.Tags.Methods["mana:current-percent"] = function(unit)
local min = UnitMana(unit)
return min == 0 and " " or E:GetFormattedText("CURRENT_PERCENT", min, UnitManaMax(unit))
end
ElvUF.Tags.Events["mana:current-max-percent"] = "UNIT_MANA UNIT_MAXMANA"
ElvUF.Tags.Methods["mana:current-max-percent"] = function(unit)
local min = UnitMana(unit)
return min == 0 and " " or E:GetFormattedText("CURRENT_MAX_PERCENT", min, UnitManaMax(unit))
end
ElvUF.Tags.Events["mana:percent"] = "UNIT_MANA UNIT_MAXMANA"
ElvUF.Tags.Methods["mana:percent"] = function(unit)
local min = UnitMana(unit)
return min == 0 and " " or E:GetFormattedText("PERCENT", min, UnitManaMax(unit))
end
ElvUF.Tags.Events["mana:deficit"] = "UNIT_MANA UNIT_MAXMANA"
ElvUF.Tags.Methods["mana:deficit"] = function(unit)
return E:GetFormattedText("DEFICIT", UnitMana(unit), UnitManaMax(unit))
end
ElvUF.Tags.Events["mana:max"] = "UNIT_MAXMANA"
ElvUF.Tags.Methods["mana:max"] = function(unit)
local max = UnitManaMax(unit)
return E:GetFormattedText("CURRENT", max, max)
end
ElvUF.Tags.Events["difficultycolor"] = "UNIT_LEVEL PLAYER_LEVEL_UP"
ElvUF.Tags.Methods["difficultycolor"] = function(unit)
local r, g, b = 0.69, 0.31, 0.31
local level = UnitLevel(unit)
if (level > 1) then
local DiffColor = UnitLevel(unit) - UnitLevel("player")
if (DiffColor >= 5) then
r, g, b = 0.69, 0.31, 0.31
elseif (DiffColor >= 3) then
r, g, b = 0.71, 0.43, 0.27
elseif (DiffColor >= -2) then
r, g, b = 0.84, 0.75, 0.65
elseif (-DiffColor <= GetQuestGreenRange()) then
r, g, b = 0.33, 0.59, 0.33
else
r, g, b = 0.55, 0.57, 0.61
end
end
return Hex(r, g, b)
end
ElvUF.Tags.Events["namecolor"] = "UNIT_NAME_UPDATE"
ElvUF.Tags.Methods["namecolor"] = function(unit)
local unitReaction = UnitReaction(unit, "player")
local _, unitClass = UnitClass(unit)
if (UnitIsPlayer(unit)) then
local class = ElvUF.colors.class[unitClass]
if not class then return "" end
return Hex(class[1], class[2], class[3])
elseif (unitReaction) then
local reaction = ElvUF["colors"].reaction[unitReaction]
return Hex(reaction[1], reaction[2], reaction[3])
else
return "|cFFC2C2C2"
end
end
ElvUF.Tags.Events["smartlevel"] = "UNIT_LEVEL PLAYER_LEVEL_UP"
ElvUF.Tags.Methods["smartlevel"] = function(unit)
local level = UnitLevel(unit)
if level == UnitLevel("player") then
return ""
elseif(level > 0) then
return level
else
return "??"
end
end
ElvUF.Tags.Events["name:veryshort"] = "UNIT_NAME_UPDATE"
ElvUF.Tags.Methods["name:veryshort"] = function(unit)
local name = UnitName(unit)
return name ~= nil and E:ShortenString(name, 5) or ""
end
ElvUF.Tags.Events["name:short"] = "UNIT_NAME_UPDATE"
ElvUF.Tags.Methods["name:short"] = function(unit)
local name = UnitName(unit)
return name ~= nil and E:ShortenString(name, 10) or ""
end
ElvUF.Tags.Events["name:medium"] = "UNIT_NAME_UPDATE"
ElvUF.Tags.Methods["name:medium"] = function(unit)
local name = UnitName(unit)
return name ~= nil and E:ShortenString(name, 15) or ""
end
ElvUF.Tags.Events["name:long"] = "UNIT_NAME_UPDATE"
ElvUF.Tags.Methods["name:long"] = function(unit)
local name = UnitName(unit)
return name ~= nil and E:ShortenString(name, 20) or ""
end
ElvUF.Tags.Events["name:veryshort:status"] = "UNIT_NAME_UPDATE UNIT_CONNECTION PLAYER_FLAGS_CHANGED UNIT_HEALTH"
ElvUF.Tags.Methods["name:veryshort:status"] = function(unit)
local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
local name = UnitName(unit)
if (status) then
return status
else
return name ~= nil and E:ShortenString(name, 5) or ""
end
end
ElvUF.Tags.Events["name:short:status"] = "UNIT_NAME_UPDATE UNIT_CONNECTION PLAYER_FLAGS_CHANGED UNIT_HEALTH"
ElvUF.Tags.Methods["name:short:status"] = function(unit)
local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
local name = UnitName(unit)
if (status) then
return status
else
return name ~= nil and E:ShortenString(name, 10) or ""
end
end
ElvUF.Tags.Events["name:medium:status"] = "UNIT_NAME_UPDATE UNIT_CONNECTION PLAYER_FLAGS_CHANGED UNIT_HEALTH"
ElvUF.Tags.Methods["name:medium:status"] = function(unit)
local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
local name = UnitName(unit)
if (status) then
return status
else
return name ~= nil and E:ShortenString(name, 15) or ""
end
end
ElvUF.Tags.Events["name:long:status"] = "UNIT_NAME_UPDATE UNIT_CONNECTION PLAYER_FLAGS_CHANGED UNIT_HEALTH"
ElvUF.Tags.Methods["name:long:status"] = function(unit)
local status = UnitIsDead(unit) and L["Dead"] or UnitIsGhost(unit) and L["Ghost"] or not UnitIsConnected(unit) and L["Offline"]
local name = UnitName(unit)
if (status) then
return status
else
return name ~= nil and E:ShortenString(name, 20) or ""
end
end
local unitStatus = {}
ElvUF.Tags.OnUpdateThrottle["statustimer"] = 1
ElvUF.Tags.Methods["statustimer"] = function(unit)
if not UnitIsPlayer(unit) then return; end
local guid = UnitGUID(unit)
if (UnitIsAFK(unit)) then
if not unitStatus[guid] or unitStatus[guid] and unitStatus[guid][1] ~= "AFK" then
unitStatus[guid] = {"AFK", GetTime()}
end
elseif(UnitIsDND(unit)) then
if not unitStatus[guid] or unitStatus[guid] and unitStatus[guid][1] ~= "DND" then
unitStatus[guid] = {"DND", GetTime()}
end
elseif(UnitIsDead(unit)) or (UnitIsGhost(unit))then
if not unitStatus[guid] or unitStatus[guid] and unitStatus[guid][1] ~= "Dead" then
unitStatus[guid] = {"Dead", GetTime()}
end
elseif(not UnitIsConnected(unit)) then
if not unitStatus[guid] or unitStatus[guid] and unitStatus[guid][1] ~= "Offline" then
unitStatus[guid] = {"Offline", GetTime()}
end
else
unitStatus[guid] = nil
end
if unitStatus[guid] ~= nil then
local status = unitStatus[guid][1]
local timer = GetTime() - unitStatus[guid][2]
local mins = floor(timer / 60)
local secs = floor(timer - (mins * 60))
return ("%s (%01.f:%02.f)"):format(status, mins, secs)
else
return ""
end
end
ElvUF.Tags.OnUpdateThrottle["pvptimer"] = 1
ElvUF.Tags.Methods["pvptimer"] = function(unit)
if (UnitIsPVPFreeForAll(unit) or UnitIsPVP(unit)) then
local timer = GetPVPTimer()
if timer ~= 301000 and timer ~= -1 then
local mins = floor((timer / 1000) / 60)
local secs = floor((timer / 1000) - (mins * 60))
return ("%s (%01.f:%02.f)"):format(PVP, mins, secs)
else
return PVP
end
else
return ""
end
end
ElvUF.Tags.Events["classificationcolor"] = "UNIT_CLASSIFICATION_CHANGED";
ElvUF.Tags.Methods["classificationcolor"] = function(unit)
local c = UnitClassification(unit);
if(c == "rare" or c == "elite") then
return Hex(1, 0.5, 0.25); -- Orange
elseif(c == "rareelite" or c == "worldboss") then
return Hex(1, 0, 0); -- Red
end
end
ElvUF.Tags.Events["guild"] = "PLAYER_GUILD_UPDATE"
ElvUF.Tags.Methods["guild"] = function(unit)
local guildName = GetGuildInfo(unit)
return guildName or ""
end
ElvUF.Tags.Events["guild:brackets"] = "PLAYER_GUILD_UPDATE"
ElvUF.Tags.Methods["guild:brackets"] = function(unit)
local guildName = GetGuildInfo(unit)
return guildName and format("<%s>", guildName) or ""
end
ElvUF.Tags.Events["target:veryshort"] = "UNIT_TARGET"
ElvUF.Tags.Methods["target:veryshort"] = function(unit)
local targetName = UnitName(unit.."target")
return targetName ~= nil and E:ShortenString(targetName, 5) or ""
end
ElvUF.Tags.Events["target:short"] = "UNIT_TARGET"
ElvUF.Tags.Methods["target:short"] = function(unit)
local targetName = UnitName(unit.."target")
return targetName ~= nil and E:ShortenString(targetName, 10) or ""
end
ElvUF.Tags.Events["target:medium"] = "UNIT_TARGET"
ElvUF.Tags.Methods["target:medium"] = function(unit)
local targetName = UnitName(unit.."target")
return targetName ~= nil and E:ShortenString(targetName, 15) or ""
end
ElvUF.Tags.Events["target:long"] = "UNIT_TARGET"
ElvUF.Tags.Methods["target:long"] = function(unit)
local targetName = UnitName(unit.."target")
return targetName ~= nil and E:ShortenString(targetName, 20) or ""
end
ElvUF.Tags.Events["target"] = "UNIT_TARGET"
ElvUF.Tags.Methods["target"] = function(unit)
local targetName = UnitName(unit.."target")
return targetName or ""
end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,10 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="Player.lua"/>
<Script file="Target.lua"/>
<Script file="TargetTarget.lua"/>
<Script file="focus.lua"/>
<Script file="focustarget.lua"/>
<Script file="pet.lua"/>
<Script file="pettarget.lua"/>
<Script file="targettargettarget.lua"/>
</Ui>
@@ -0,0 +1,94 @@
local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local UF = E:GetModule("UnitFrames");
--Cache global variables
--Lua functions
local _G = _G
local ns = oUF
local ElvUF = ns.oUF
assert(ElvUF, "ElvUI was unable to locate oUF.")
local CAN_HAVE_CLASSBAR = E.myclass == "DRUID"
function UF:Construct_PlayerFrame(frame)
frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
frame.Health.frequentUpdates = true
frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
frame.Power.frequentUpdates = true
frame.Name = self:Construct_NameText(frame)
frame.Portrait3D = self:Construct_Portrait(frame, "model")
frame.Portrait2D = self:Construct_Portrait(frame, "texture")
frame:SetPoint("BOTTOMLEFT", E.UIParent, "BOTTOM", -413, 68)
E:CreateMover(frame, frame:GetName().."Mover", L["Player Frame"], nil, nil, nil, "ALL,SOLO")
frame.unitframeType = "player"
end
function UF:Update_PlayerFrame(frame, db)
frame.db = db
do
frame.ORIENTATION = db.orientation
frame.UNIT_WIDTH = db.width
frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
frame.USE_POWERBAR = db.power.enable
frame.POWERBAR_DETACHED = db.power.detachFromFrame
frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
frame.USE_PORTRAIT = db.portrait and db.portrait.enable
frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
frame.CAN_HAVE_CLASSBAR = CAN_HAVE_CLASSBAR
frame.MAX_CLASS_BAR = frame.MAX_CLASS_BAR or UF.classMaxResourceBar[E.myclass] or 0
frame.USE_CLASSBAR = db.classbar.enable and frame.CAN_HAVE_CLASSBAR
frame.CLASSBAR_SHOWN = frame.CAN_HAVE_CLASSBAR and frame[frame.ClassBar]:IsShown()
frame.CLASSBAR_DETACHED = db.classbar.detachFromFrame
frame.USE_MINI_CLASSBAR = db.classbar.fill == "spaced" and frame.USE_CLASSBAR
frame.CLASSBAR_HEIGHT = frame.USE_CLASSBAR and db.classbar.height or 0
frame.CLASSBAR_WIDTH = frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2) - frame.PORTRAIT_WIDTH -(frame.ORIENTATION == "MIDDLE" and (frame.POWERBAR_OFFSET*2) or frame.POWERBAR_OFFSET)
frame.CLASSBAR_YOFFSET = (not frame.USE_CLASSBAR or not frame.CLASSBAR_SHOWN or frame.CLASSBAR_DETACHED) and 0 or (frame.USE_MINI_CLASSBAR and (frame.SPACING+(frame.CLASSBAR_HEIGHT/2)) or (frame.CLASSBAR_HEIGHT - (frame.BORDER-frame.SPACING)))
frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
frame.HAPPINESS_WIDTH = 0
frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
frame.VARIABLES_SET = true
end
frame.colors = ElvUF.colors
frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
--frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
frame:SetWidth(frame.UNIT_WIDTH)
frame:SetHeight(frame.UNIT_HEIGHT)
_G[frame:GetName().."Mover"]:SetWidth(frame:GetWidth())
_G[frame:GetName().."Mover"]:SetHeight(frame:GetHeight())
UF:Configure_HealthBar(frame)
UF:UpdateNameSettings(frame)
UF:Configure_Power(frame)
UF:Configure_Portrait(frame)
E:SetMoverSnapOffset(frame:GetName().."Mover", -(12 + db.castbar.height))
frame:UpdateAllElements("ElvUI_UpdateAllElements")
end
tinsert(UF["unitstoload"], "player")
@@ -0,0 +1,90 @@
local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local UF = E:GetModule("UnitFrames");
--Cache global variables
--Lua functions
local _G = _G
local ns = oUF
local ElvUF = ns.oUF
assert(ElvUF, "ElvUI was unable to locate oUF.")
function UF:Construct_TargetFrame(frame)
frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
frame.Health.frequentUpdates = true
frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
frame.Power.frequentUpdates = true
frame.Name = self:Construct_NameText(frame)
frame.Portrait3D = self:Construct_Portrait(frame, "model")
frame.Portrait2D = self:Construct_Portrait(frame, "texture")
frame:SetPoint("BOTTOMRIGHT", E.UIParent, "BOTTOM", 413, 68)
E:CreateMover(frame, frame:GetName().."Mover", L["Target Frame"], nil, nil, nil, "ALL,SOLO")
frame.unitframeType = "target"
end
function UF:Update_TargetFrame(frame, db)
frame.db = db
do
frame.ORIENTATION = db.orientation
frame.UNIT_WIDTH = db.width
frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
frame.USE_POWERBAR = db.power.enable
frame.POWERBAR_DETACHED = db.power.detachFromFrame
frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
frame.USE_PORTRAIT = db.portrait and db.portrait.enable
frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
frame.CAN_HAVE_CLASSBAR = db.combobar.enable
frame.MAX_CLASS_BAR = MAX_COMBO_POINTS
frame.USE_CLASSBAR = db.combobar.enable
frame.CLASSBAR_SHOWN = frame.CAN_HAVE_CLASSBAR and frame.ComboPoints and frame.ComboPoints:IsShown()
frame.CLASSBAR_DETACHED = db.combobar.detachFromFrame
frame.USE_MINI_CLASSBAR = db.combobar.fill == "spaced" and frame.USE_CLASSBAR
frame.CLASSBAR_HEIGHT = frame.USE_CLASSBAR and db.combobar.height or 0
frame.CLASSBAR_WIDTH = frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2) - frame.PORTRAIT_WIDTH - frame.POWERBAR_OFFSET
frame.CLASSBAR_YOFFSET = (not frame.USE_CLASSBAR or not frame.CLASSBAR_SHOWN or frame.CLASSBAR_DETACHED) and 0 or (frame.USE_MINI_CLASSBAR and (frame.SPACING+(frame.CLASSBAR_HEIGHT/2)) or (frame.CLASSBAR_HEIGHT + frame.SPACING))
frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
frame.VARIABLES_SET = true
end
frame.colors = ElvUF.colors
frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
--frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
frame:SetWidth(frame.UNIT_WIDTH)
frame:SetHeight(frame.UNIT_HEIGHT)
_G[frame:GetName().."Mover"]:SetWidth(frame:GetWidth())
_G[frame:GetName().."Mover"]:SetHeight(frame:GetHeight())
UF:Configure_HealthBar(frame)
UF:UpdateNameSettings(frame)
UF:Configure_Power(frame)
UF:Configure_Portrait(frame)
E:SetMoverSnapOffset(frame:GetName().."Mover", -(12 + db.castbar.height))
frame:UpdateAllElements("ElvUI_UpdateAllElements")
end
tinsert(UF["unitstoload"], "target")
@@ -0,0 +1,74 @@
local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local UF = E:GetModule("UnitFrames");
--Cache global variables
--Lua functions
local _G = _G
local ns = oUF
local ElvUF = ns.oUF
assert(ElvUF, "ElvUI was unable to locate oUF.")
function UF:Construct_TargetTargetFrame(frame)
frame.Health = self:Construct_HealthBar(frame, true, true, "RIGHT")
frame.Power = self:Construct_PowerBar(frame, true, true, "LEFT")
frame.Name = self:Construct_NameText(frame)
frame.Portrait3D = self:Construct_Portrait(frame, "model")
frame.Portrait2D = self:Construct_Portrait(frame, "texture")
frame:SetPoint("BOTTOM", E.UIParent, "BOTTOM", 0, 75)
E:CreateMover(frame, frame:GetName().."Mover", L["TargetTarget Frame"], nil, nil, nil, "ALL,SOLO")
frame.unitframeType = "targettarget";
end
function UF:Update_TargetTargetFrame(frame, db)
frame.db = db
do
frame.ORIENTATION = db.orientation
frame.UNIT_WIDTH = db.width
frame.UNIT_HEIGHT = db.infoPanel.enable and (db.height + db.infoPanel.height) or db.height
frame.USE_POWERBAR = db.power.enable
frame.POWERBAR_DETACHED = db.power.detachFromFrame
frame.USE_INSET_POWERBAR = not frame.POWERBAR_DETACHED and db.power.width == "inset" and frame.USE_POWERBAR
frame.USE_MINI_POWERBAR = (not frame.POWERBAR_DETACHED and db.power.width == "spaced" and frame.USE_POWERBAR)
frame.USE_POWERBAR_OFFSET = db.power.offset ~= 0 and frame.USE_POWERBAR and not frame.POWERBAR_DETACHED
frame.POWERBAR_OFFSET = frame.USE_POWERBAR_OFFSET and db.power.offset or 0
frame.POWERBAR_HEIGHT = not frame.USE_POWERBAR and 0 or db.power.height
frame.POWERBAR_WIDTH = frame.USE_MINI_POWERBAR and (frame.UNIT_WIDTH - (frame.BORDER*2))/2 or (frame.POWERBAR_DETACHED and db.power.detachedWidth or (frame.UNIT_WIDTH - ((frame.BORDER+frame.SPACING)*2)))
frame.USE_PORTRAIT = db.portrait and db.portrait.enable
frame.USE_PORTRAIT_OVERLAY = frame.USE_PORTRAIT and (db.portrait.overlay or frame.ORIENTATION == "MIDDLE")
frame.PORTRAIT_WIDTH = (frame.USE_PORTRAIT_OVERLAY or not frame.USE_PORTRAIT) and 0 or db.portrait.width
frame.USE_INFO_PANEL = not frame.USE_MINI_POWERBAR and not frame.USE_POWERBAR_OFFSET and db.infoPanel.enable
frame.INFO_PANEL_HEIGHT = frame.USE_INFO_PANEL and db.infoPanel.height or 0
frame.BOTTOM_OFFSET = UF:GetHealthBottomOffset(frame)
frame.VARIABLES_SET = true
end
frame.colors = ElvUF.colors
frame.Portrait = frame.Portrait or (db.portrait.style == "2D" and frame.Portrait2D or frame.Portrait3D)
--frame:RegisterForClicks(self.db.targetOnMouseDown and "AnyDown" or "AnyUp")
frame:SetWidth(frame.UNIT_WIDTH)
frame:SetHeight(frame.UNIT_HEIGHT)
_G[frame:GetName().."Mover"]:SetWidth(frame:GetWidth())
_G[frame:GetName().."Mover"]:SetHeight(frame:GetHeight())
UF:Configure_HealthBar(frame)
UF:UpdateNameSettings(frame)
UF:Configure_Power(frame)
UF:Configure_Portrait(frame)
E:SetMoverSnapOffset(frame:GetName().."Mover", -(12 + self.db["units"].player.castbar.height))
frame:UpdateAllElements("ElvUI_UpdateAllElements")
end
tinsert(UF["unitstoload"], "targettarget")
+12
View File
@@ -37,6 +37,18 @@ V["tooltip"] = {
["enable"] = true ["enable"] = true
} }
V["unitframe"] = {
["enable"] = true,
["disabledBlizzardFrames"] = {
["player"] = true,
["target"] = true,
["focus"] = true,
["boss"] = true,
["arena"] = true,
["party"] = true,
},
}
V["actionbar"] = { V["actionbar"] = {
["enable"] = true ["enable"] = true
} }
File diff suppressed because it is too large Load Diff
@@ -9,3 +9,4 @@
Libraries\Load_Libraries.xml Libraries\Load_Libraries.xml
locales\load_locales.xml locales\load_locales.xml
core.lua core.lua
UnitFrames.lua
@@ -12,14 +12,15 @@ Very light wrapper library that combines all the AceConfig subcomponents into on
]] ]]
local cfgreg = LibStub("AceConfigRegistry-3.0-ElvUI") local MAJOR, MINOR = "AceConfig-3.0", 2
local cfgcmd = LibStub("AceConfigCmd-3.0-ElvUI")
local MAJOR, MINOR = "AceConfig-3.0-ElvUI", 2
local AceConfig = LibStub:NewLibrary(MAJOR, MINOR) local AceConfig = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfig then return end if not AceConfig then return end
AceConfig.embeds = AceConfig.embeds or {}
local cfgreg = LibStub("AceConfigRegistry-3.0")
local cfgcmd = LibStub("AceConfigCmd-3.0")
--TODO: local cfgdlg = LibStub("AceConfigDialog-3.0", true) --TODO: local cfgdlg = LibStub("AceConfigDialog-3.0", true)
--TODO: local cfgdrp = LibStub("AceConfigDropdown-3.0", true) --TODO: local cfgdrp = LibStub("AceConfigDropdown-3.0", true)
@@ -43,16 +44,27 @@ local pcall, error, type, pairs = pcall, error, type, pairs
-- local AceConfig = LibStub("AceConfig-3.0") -- local AceConfig = LibStub("AceConfig-3.0")
-- AceConfig:RegisterOptionsTable("MyAddon", myOptions, {"/myslash", "/my"}) -- AceConfig:RegisterOptionsTable("MyAddon", myOptions, {"/myslash", "/my"})
function AceConfig:RegisterOptionsTable(appName, options, slashcmd) function AceConfig:RegisterOptionsTable(appName, options, slashcmd)
if self == AceConfig then
error([[Usage: RegisterOptionsTable(appName, options[, slashcmd]): 'self' - use your own 'self']], 2)
end
local ok,msg = pcall(cfgreg.RegisterOptionsTable, self, appName, options) local ok,msg = pcall(cfgreg.RegisterOptionsTable, self, appName, options)
if not ok then error(msg, 2) end if not ok then error(msg, 2) end
if slashcmd then if slashcmd then
if type(slashcmd) == "table" then if type(slashcmd) == "table" then
for _,cmd in pairs(slashcmd) do for _,cmd in pairs(slashcmd) do
cfgcmd:CreateChatCommand(cmd, appName) cfgcmd.CreateChatCommand(self, cmd, appName)
end end
else else
cfgcmd:CreateChatCommand(slashcmd, appName) cfgcmd.CreateChatCommand(self, slashcmd, appName)
end end
end end
end end
function AceConfig:Embed(target)
target["RegisterOptionsTable"] = self["RegisterOptionsTable"]
end
for addon in pairs(AceConfig.embeds) do
AceConfig:Embed(addon)
end
@@ -14,29 +14,37 @@ REQUIRES: AceConsole-3.0 for command registration (loaded on demand)
-- TODO: plugin args -- TODO: plugin args
local cfgreg = LibStub("AceConfigRegistry-3.0-ElvUI")
local MAJOR, MINOR = "AceConfigCmd-3.0-ElvUI", 2 local MAJOR, MINOR = "AceConfigCmd-3.0", 13
local AceConfigCmd = LibStub:NewLibrary(MAJOR, MINOR) local AceConfigCmd = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfigCmd then return end if not AceConfigCmd then return end
local AceCore = LibStub("AceCore-3.0")
local Dispatchers = AceCore.Dispatchers
local strtrim = AceCore.strtrim
local strsplit = AceCore.strsplit
local new, del = AceCore.new, AceCore.del
local wipe = AceCore.wipe
AceConfigCmd.commands = AceConfigCmd.commands or {} AceConfigCmd.commands = AceConfigCmd.commands or {}
AceConfigCmd.embeds = AceConfigCmd.embeds or {}
local commands = AceConfigCmd.commands local commands = AceConfigCmd.commands
local cfgreg = LibStub("AceConfigRegistry-3.0")
local AceConsole -- LoD local AceConsole -- LoD
local AceConsoleName = "AceConsole-3.0" local AceConsoleName = "AceConsole-3.0"
-- Lua APIs -- Lua APIs
local strsub, strsplit, strlower, strmatch, strtrim, strupper = string.sub, string.split, string.lower, string.match, string.trim, string.upper local strbyte, strsub = string.byte, string.sub
local format, tonumber, tostring, len, find, byte = string.format, tonumber, tostring, string.len, string.find, string.byte local strlen, strupper, strlower = string.len, string.upper, string.lower
local tsort, tinsert, tgetn = table.sort, table.insert, table.getn local strfind, strgfind, strgsub = string.find, string.gfind, string.gsub
local select, pairs, next, type, unpack = select, pairs, next, type, unpack
local error, assert = error, assert local format = string.format
local mod = math.mod local tsort, tinsert, tgetn, tremove = table.sort, table.insert, table.getn, table.remove
-- WoW APIs -- WoW APIs
local _G = getfenv() local _G = AceCore._G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
@@ -61,18 +69,7 @@ local handlermsg = "expected a table"
local functypes = {["function"]=true, ["string"]=true} local functypes = {["function"]=true, ["string"]=true}
local funcmsg = "expected function or member name" local funcmsg = "expected function or member name"
local pickfirstset = AceCore.pickfirstset
-- pickfirstset() - picks the first non-nil value and returns it
local function pickfirstset(...)
local args = unpack(arg)
for i=1,select("#", args) do
if select(i,args)~=nil then
return select(i,args)
end
end
end
-- err() - produce real error() regarding malformed options tables etc -- err() - produce real error() regarding malformed options tables etc
@@ -92,23 +89,26 @@ end
-- callmethod() - call a given named method (e.g. "get", "set") with given arguments -- callmethod() - call a given named method (e.g. "get", "set") with given arguments
local function callmethod(info, inputpos, tab, methodtype, ...)
local function callmethod(info, inputpos, tab, methodtype, argc, a1, a2, a3, a4)
local method = info[methodtype] local method = info[methodtype]
if not method then if not method then
err(info, inputpos, "'"..methodtype.."': not set") err(info, inputpos, "'"..methodtype.."': not set")
end end
argc = argc or 0
info.arg = tab.arg info.arg = tab.arg
info.option = tab info.option = tab
info.type = tab.type info.type = tab.type
if type(method)=="function" then if type(method)=="function" then
return method(info, unpack(arg)) return Dispatchers[argc+1](method, info, a1, a2, a3, a4)
elseif type(method)=="string" then elseif type(method)=="string" then
if type(info.handler[method])~="function" then if type(info.handler[method])~="function" then
err(info, inputpos, "'"..methodtype.."': '"..method.."' is not a member function of "..tostring(info.handler)) err(info, inputpos, "'"..methodtype.."': '"..method.."' is not a member function of "..tostring(info.handler))
end end
return info.handler[method](info.handler, info, unpack(arg)) return Dispatchers[argc+2](info.handler[method], info.handler, info, a1, a2, a3, a4)
else else
assert(false) -- type should have already been checked on read assert(false) -- type should have already been checked on read
end end
@@ -116,7 +116,8 @@ end
-- callfunction() - call a given named function (e.g. "name", "desc") with given arguments -- callfunction() - call a given named function (e.g. "name", "desc") with given arguments
local function callfunction(info, tab, methodtype, ...) -- Ace3v: the variable arguments are currently unused, so we removed it
local function callfunction(info, tab, methodtype)
local method = tab[methodtype] local method = tab[methodtype]
info.arg = tab.arg info.arg = tab.arg
@@ -124,17 +125,18 @@ local function callfunction(info, tab, methodtype, ...)
info.type = tab.type info.type = tab.type
if type(method)=="function" then if type(method)=="function" then
return method(info, unpack(arg)) return method(info)
else else
assert(false) -- type should have already been checked on read assert(false) -- type should have already been checked on read
end end
end end
-- do_final() - do the final step (set/execute) along with validation and confirmation -- do_final() - do the final step (set/execute) along with validation and confirmation
-- Ace3v: experimental
local function do_final(info, inputpos, tab, methodtype, ...) -- @param argc number of variable arguments
local function do_final(info, inputpos, tab, methodtype, argc, a1, a2, a3, a4) -- currently maximum 4 arguments
if info.validate then if info.validate then
local res = callmethod(info,inputpos,tab,"validate",unpack(arg)) local res = callmethod(info,inputpos,tab,"validate",argc,a1,a2,a3,a4)
if type(res)=="string" then if type(res)=="string" then
usererr(info, inputpos, "'"..strsub(info.input, inputpos).."' - "..res) usererr(info, inputpos, "'"..strsub(info.input, inputpos).."' - "..res)
return return
@@ -142,7 +144,7 @@ local function do_final(info, inputpos, tab, methodtype, ...)
end end
-- console ignores .confirm -- console ignores .confirm
callmethod(info,inputpos,tab,methodtype, unpack(arg)) callmethod(info,inputpos,tab,methodtype,argc,a1,a2,a3,a4)
end end
@@ -165,8 +167,6 @@ end
-- iterateargs(tab) - custom iterator that iterates both t.args and t.plugins.* -- iterateargs(tab) - custom iterator that iterates both t.args and t.plugins.*
local dummytable={}
local function iterateargs(tab) local function iterateargs(tab)
if not tab.plugins then if not tab.plugins then
return pairs(tab.args) return pairs(tab.args)
@@ -191,17 +191,21 @@ local function iterateargs(tab)
end end
end end
local function getValueFromTab(info, inputpos, tab, key)
local v = tab[key]
if type(v) == "function" or type(v) == "string" then
info[key] = v
v = callmethod(info, inputpos, tab, key)
info[key] = nil
end
return v
end
local function checkhidden(info, inputpos, tab) local function checkhidden(info, inputpos, tab)
if tab.cmdHidden~=nil then if tab.cmdHidden~=nil then
return tab.cmdHidden return tab.cmdHidden
end end
local hidden = tab.hidden return getValueFromTab(info, inputpos, tab, "hidden")
if type(hidden) == "function" or type(hidden) == "string" then
info.hidden = hidden
hidden = callmethod(info, inputpos, tab, 'hidden')
info.hidden = nil
end
return hidden
end end
local function showhelp(info, inputpos, tab, depth, noHead) local function showhelp(info, inputpos, tab, depth, noHead)
@@ -209,8 +213,8 @@ local function showhelp(info, inputpos, tab, depth, noHead)
print("|cff33ff99"..info.appName.."|r: Arguments to |cffffff78/"..info[0].."|r "..strsub(info.input,1,inputpos-1)..":") print("|cff33ff99"..info.appName.."|r: Arguments to |cffffff78/"..info[0].."|r "..strsub(info.input,1,inputpos-1)..":")
end end
local sortTbl = {} -- [1..n]=name local sortTbl = new() -- [1..n]=name
local refTbl = {} -- [name]=tableref local refTbl = new() -- [name]=tableref
for k,v in iterateargs(tab) do for k,v in iterateargs(tab) do
if not refTbl[k] then -- a plugin overriding something in .args if not refTbl[k] then -- a plugin overriding something in .args
@@ -224,16 +228,16 @@ local function showhelp(info, inputpos, tab, depth, noHead)
local o2 = refTbl[two].order or 100 local o2 = refTbl[two].order or 100
if type(o1) == "function" or type(o1) == "string" then if type(o1) == "function" or type(o1) == "string" then
info.order = o1 info.order = o1
info[tgetn(info)+1] = one tinsert(info, one)
o1 = callmethod(info, inputpos, refTbl[one], "order") o1 = callmethod(info, inputpos, refTbl[one], "order")
info[tgetn(info)] = nil tremove(info)
info.order = nil info.order = nil
end end
if type(o2) == "function" or type(o1) == "string" then if type(o2) == "function" or type(o1) == "string" then
info.order = o2 info.order = o2
info[tgetn(info)+1] = two tinsert(info, two)
o2 = callmethod(info, inputpos, refTbl[two], "order") o2 = callmethod(info, inputpos, refTbl[two], "order")
info[tgetn(info)] = nil tremove(info)
info.order = nil info.order = nil
end end
if o1<0 and o2<0 then return o1<o2 end if o1<0 and o2<0 then return o1<o2 end
@@ -256,21 +260,22 @@ local function showhelp(info, inputpos, tab, depth, noHead)
if type(desc) == "function" then if type(desc) == "function" then
desc = callfunction(info, v, 'desc') desc = callfunction(info, v, 'desc')
end end
if v.type == "group" and pickfirstset(v.cmdInline, v.inline, false) then if v.type == "group" and pickfirstset(3, v.cmdInline, v.inline, false) then
print(" "..(desc or name)..":") print(" "..(desc or name)..":")
local oldhandler,oldhandler_at = getparam(info, inputpos, v, depth, "handler", handlertypes, handlermsg) local oldhandler,oldhandler_at = getparam(info, inputpos, v, depth, "handler", handlertypes, handlermsg)
showhelp(info, inputpos, v, depth, true) showhelp(info, inputpos, v, depth, true)
info.handler,info.handler_at = oldhandler,oldhandler_at info.handler,info.handler_at = oldhandler,oldhandler_at
else else
local key = gsub(k, " ", "_") local key = strgsub(k, " ", "_")
print(" |cffffff78"..key.."|r - "..(desc or name or "")) print(" |cffffff78"..key.."|r - "..(desc or name or ""))
end end
end end
end end
end end
del(sortTbl) -- Ace3v: release the tables
del(refTbl)
end end
local function keybindingValidateFunc(text) local function keybindingValidateFunc(text)
if text == nil or text == "NONE" then if text == nil or text == "NONE" then
return nil return nil
@@ -313,7 +318,7 @@ local function keybindingValidateFunc(text)
if text == "" then if text == "" then
return false return false
end end
if not find(text, "^F%d+$") and text ~= "CAPSLOCK" and len(text) ~= 1 and (byte(text) < 128 or len(text) > 4) and not _G["KEY_" .. text] then if not strfind(text,"^F%d+$") and text ~= "CAPSLOCK" and strlen(text) ~= 1 and (strbyte(text) < 128 or strlen(text) > 4) and not _G["KEY_" .. text] then
return false return false
end end
local s = text local s = text
@@ -359,7 +364,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
if tab.plugins and type(tab.plugins)~="table" then err(info,inputpos) end if tab.plugins and type(tab.plugins)~="table" then err(info,inputpos) end
-- grab next arg from input -- grab next arg from input
local _,nextpos,arg = find(info.input, " *([^ ]+) *", inputpos) local _,nextpos,arg = strfind(info.input, " *([^ ]+) *", inputpos)
if not arg then if not arg then
showhelp(info, inputpos, tab, depth) showhelp(info, inputpos, tab, depth)
return return
@@ -371,17 +376,17 @@ local function handle(info, inputpos, tab, depth, retfalse)
if not(type(k)=="string" and type(v)=="table" and type(v.type)=="string") then err(info,inputpos, "options table child '"..tostring(k).."' is malformed") end if not(type(k)=="string" and type(v)=="table" and type(v.type)=="string") then err(info,inputpos, "options table child '"..tostring(k).."' is malformed") end
-- is this child an inline group? if so, traverse into it -- is this child an inline group? if so, traverse into it
if v.type=="group" and pickfirstset(v.cmdInline, v.inline, false) then if v.type=="group" and pickfirstset(3, v.cmdInline, v.inline, false) then
info[depth+1] = k tinsert(info,k)
if handle(info, inputpos, v, depth+1, true)==false then if handle(info, inputpos, v, depth+1, true)==false then
info[depth+1] = nil tremove(info)
-- wasn't found in there, but that's ok, we just keep looking down here -- wasn't found in there, but that's ok, we just keep looking down here
else else
return -- done, name was found in inline group return -- done, name was found in inline group
end end
-- matching name and not a inline group -- matching name and not a inline group
elseif strlower(arg)==strlower(gsub(k, " ", "_")) then elseif strlower(arg)==strlower(strgsub(k, " ", "_")) then
info[depth+1] = k tinsert(info,k)
return handle(info,nextpos,v,depth+1) return handle(info,nextpos,v,depth+1)
end end
end end
@@ -414,16 +419,21 @@ local function handle(info, inputpos, tab, depth, retfalse)
elseif tab.type=="input" then elseif tab.type=="input" then
------------ input -------------------------------------------- ------------ input --------------------------------------------
if str=="" and tab.nullable == false then
usererr(info, inputpos, "'"..str.."' - " .. L["invalid input"])
return
end
local res = true local res = true
if tab.pattern then if tab.pattern then
if not(type(tab.pattern)=="string") then err(info, inputpos, "'pattern' - expected a string") end if not(type(tab.pattern)=="string") then err(info, inputpos, "'pattern' - expected a string") end
if not strmatch(str, tab.pattern) then if not strfind(str, tab.pattern) then
usererr(info, inputpos, "'"..str.."' - " .. L["invalid input"]) usererr(info, inputpos, "'"..str.."' - " .. L["invalid input"])
return return
end end
end end
do_final(info, inputpos, tab, "set", str) do_final(info, inputpos, tab, "set", 1, str)
@@ -462,47 +472,63 @@ local function handle(info, inputpos, tab, depth, retfalse)
return return
end end
do_final(info, inputpos, tab, "set", b) do_final(info, inputpos, tab, "set", 1, b)
elseif tab.type=="range" then elseif tab.type=="range" then
------------ range -------------------------------------------- ------------ range --------------------------------------------
local str = strtrim(strlower(str))
if str == "" then
-- TODO: Show current value
return
end
local val = tonumber(str) local val = tonumber(str)
if not val then if not val then
usererr(info, inputpos, "'"..str.."' - "..L["expected number"]) usererr(info, inputpos, "'"..str.."' - "..L["expected number"])
return return
end end
if type(info.step)=="number" then
val = val- mod(val, info.step) local step = getValueFromTab(info, inputpos, tab, "step")
local min = getValueFromTab(info, inputpos, tab, "min")
if type(step)=="number" then
val = min + math.floor((val-min)/step) * step
end end
if type(info.min)=="number" and val<info.min then
usererr(info, inputpos, val.." - "..format(L["must be equal to or higher than %s"], tostring(info.min)) ) if type(min)=="number" and val<min then
return usererr(info, inputpos, val.." - "..format(L["must be equal to or higher than %s"], tostring(min)) )
end
if type(info.max)=="number" and val>info.max then
usererr(info, inputpos, val.." - "..format(L["must be equal to or lower than %s"], tostring(info.max)) )
return return
end end
do_final(info, inputpos, tab, "set", val) local max = getValueFromTab(info, inputpos, tab, "max")
if type(max)=="number" and val>max then
usererr(info, inputpos, val.." - "..format(L["must be equal to or lower than %s"], tostring(max)) )
return
end
do_final(info, inputpos, tab, "set", 1, val)
elseif tab.type=="select" then elseif tab.type=="select" then
------------ select ------------------------------------ ------------ select ------------------------------------
local str = strtrim(strlower(str)) local str = strtrim(strlower(str))
local values = tab.values local values = getValueFromTab(info, inputpos, tab, "values")
if type(values) == "function" or type(values) == "string" then
info.values = values
values = callmethod(info, inputpos, tab, "values")
info.values = nil
end
if str == "" then if str == "" then
local b = callmethod(info, inputpos, tab, "get") -- Ace3v: it is possbile to not have a current value
-- we do this only for select but not for multiselect
local b = tab.get
if type(b) == "function" or type(b) == "string" then
b = callmethod(info, inputpos, tab, "get")
else
b = nil
end
local fmt = "|cffffff78- [%s]|r %s" local fmt = "|cffffff78- [%s]|r %s"
local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r" local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
print(L["Options for |cffffff78"..info[thetn(info)].."|r:"]) print(L["Options for |cffffff78"..info[tgetn(info)].."|r:"])
for k, v in pairs(values) do for k, v in pairs(values) do
if b == k then if b == k then
print(format(fmt_sel, k, v)) print(format(fmt_sel, k, v))
@@ -510,6 +536,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
print(format(fmt, k, v)) print(format(fmt, k, v))
end end
end end
if tab.valuesTableDestroyable then del(values) end
return return
end end
@@ -521,45 +548,42 @@ local function handle(info, inputpos, tab, depth, retfalse)
break break
end end
end end
if tab.valuesTableDestroyable then del(values) end
if not ok then if not ok then
usererr(info, inputpos, "'"..str.."' - "..L["unknown selection"]) usererr(info, inputpos, "'"..str.."' - "..L["unknown selection"])
return return
end end
do_final(info, inputpos, tab, "set", str) do_final(info, inputpos, tab, "set", 1, str)
elseif tab.type=="multiselect" then elseif tab.type=="multiselect" then
------------ multiselect ------------------------------------------- ------------ multiselect -------------------------------------------
local str = strtrim(strlower(str)) local str = strtrim(strlower(str))
local values = tab.values local values = getValueFromTab(info, inputpos, tab, "values")
if type(values) == "function" or type(values) == "string" then
info.values = values
values = callmethod(info, inputpos, tab, "values")
info.values = nil
end
if str == "" then if str == "" then
local fmt = "|cffffff78- [%s]|r %s" local fmt = "|cffffff78- [%s]|r %s"
local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r" local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
print(L["Options for |cffffff78"..info[tgetn(info)].."|r (multiple possible):"]) print(L["Options for |cffffff78"..info[tgetn(info)].."|r (multiple possible):"])
for k, v in pairs(values) do for k, v in pairs(values) do
if callmethod(info, inputpos, tab, "get", k) then if callmethod(info, inputpos, tab, "get", 1, k) then
print(format(fmt_sel, k, v)) print(format(fmt_sel, k, v))
else else
print(format(fmt, k, v)) print(format(fmt, k, v))
end end
end end
if tab.valuesTableDestroyable then del(values) end
return return
end end
--build a table of the selections, checking that they exist --build a table of the selections, checking that they exist
--parse for =on =off =default in the process --parse for =on =off =default in the process
--table will be key = true for options that should toggle, key = [on|off|default] for options to be set --table will be key = true for options that should toggle, key = [on|off|default] for options to be set
local sels = {} local sels = new()
for v in gmatch(str, "[^ ]+") do for v in strgfind(str, "[^ ]+") do
--parse option=on etc --parse option=on etc
local opt, val = strmatch(v, '(.+)=(.+)') local _, _, opt, val = strfind(v, '(.+)=(.+)')
--get option if toggling --get option if toggling
if not opt then if not opt then
opt = v opt = v
@@ -574,6 +598,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
break break
end end
end end
if tab.valuesTableDestroyable then del(values) end
if not ok then if not ok then
usererr(info, inputpos, "'"..opt.."' - "..L["unknown selection"]) usererr(info, inputpos, "'"..opt.."' - "..L["unknown selection"])
@@ -591,6 +616,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
else else
usererr(info, inputpos, format(L["'%s' '%s' - expected 'on' or 'off', or no argument to toggle."], v, val)) usererr(info, inputpos, format(L["'%s' '%s' - expected 'on' or 'off', or no argument to toggle."], v, val))
end end
del(sels)
return return
end end
else else
@@ -604,7 +630,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
if (val == true) then if (val == true) then
--toggle the option --toggle the option
local b = callmethod(info, inputpos, tab, "get", opt) local b = callmethod(info, inputpos, tab, "get", 1, opt)
if tab.tristate then if tab.tristate then
--cycle in true, nil, false order --cycle in true, nil, false order
@@ -630,8 +656,9 @@ local function handle(info, inputpos, tab, depth, retfalse)
end end
end end
do_final(info, inputpos, tab, "set", opt, newval) do_final(info, inputpos, tab, "set", 2, opt, newval)
end end
del(sels)
elseif tab.type=="color" then elseif tab.type=="color" then
@@ -642,22 +669,17 @@ local function handle(info, inputpos, tab, depth, retfalse)
return return
end end
local r, g, b, a local _, r, g, b, a
local hasAlpha = tab.hasAlpha local hasAlpha = getValueFromTab(info, inputpos, tab, 'hasAlpha')
if type(hasAlpha) == "function" or type(hasAlpha) == "string" then
info.hasAlpha = hasAlpha
hasAlpha = callmethod(info, inputpos, tab, 'hasAlpha')
info.hasAlpha = nil
end
if hasAlpha then if hasAlpha then
if len(str) == 8 and find(str, "^%x*$") then if strlen(str) == 8 and strfind(str, "^%x*$") then
--parse a hex string --parse a hex string
r,g,b,a = tonumber(sub(str, 1, 2), 16) / 255, tonumber(sub(str, 3, 4), 16) / 255, tonumber(sub(str, 5, 6), 16) / 255 r,g,b,a = tonumber(strsub(str, 1, 2), 16) / 255, tonumber(strsub(str, 3, 4), 16) / 255, tonumber(strsub(str, 5, 6), 16) / 255, tonumber(strsub(str, 7, 8), 16) / 255
else else
--parse seperate values --parse seperate values
r,g,b,a = strmatch(str, "^([%d%.]+) ([%d%.]+) ([%d%.]+) ([%d%.]+)$") _,_,r,g,b,a = strfind(str, "^([%d%.]+) ([%d%.]+) ([%d%.]+) ([%d%.]+)$")
r,g,b,a = tonumber(r), tonumber(g), tonumber(b), tonumber(a) r,g,b,a = tonumber(r), tonumber(g), tonumber(b), tonumber(a)
end end
if not (r and g and b and a) then if not (r and g and b and a) then
@@ -679,12 +701,12 @@ local function handle(info, inputpos, tab, depth, retfalse)
end end
else else
a = 1.0 a = 1.0
if len(str) == 6 and find(str, "^%x*$") then if strlen(str) == 6 and strfind(str, "^%x*$") then
--parse a hex string --parse a hex string
r,g,b = tonumber(sub(str, 1, 2), 16) / 255, tonumber(sub(str, 3, 4), 16) / 255, tonumber(sub(str, 5, 6), 16) / 255 r,g,b = tonumber(strsub(str, 1, 2), 16) / 255, tonumber(strsub(str, 3, 4), 16) / 255, tonumber(strsub(str, 5, 6), 16) / 255
else else
--parse seperate values --parse seperate values
r,g,b = strmatch(str, "^([%d%.]+) ([%d%.]+) ([%d%.]+)$") _,_,r,g,b = strfind(str, "^([%d%.]+) ([%d%.]+) ([%d%.]+)$")
r,g,b = tonumber(r), tonumber(g), tonumber(b) r,g,b = tonumber(r), tonumber(g), tonumber(b)
end end
if not (r and g and b) then if not (r and g and b) then
@@ -704,7 +726,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
end end
end end
do_final(info, inputpos, tab, "set", r,g,b,a) do_final(info, inputpos, tab, "set", 4, r,g,b,a)
elseif tab.type=="keybinding" then elseif tab.type=="keybinding" then
------------ keybinding -------------------------------------------- ------------ keybinding --------------------------------------------
@@ -719,7 +741,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
return return
end end
do_final(info, inputpos, tab, "set", value) do_final(info, inputpos, tab, "set", 1, value)
elseif tab.type=="description" then elseif tab.type=="description" then
------------ description -------------------- ------------ description --------------------
@@ -749,6 +771,9 @@ end
-- LibStub("AceConfigCmd-3.0").HandleCommand(MyAddon, "mychat", "MyOptions", input) -- LibStub("AceConfigCmd-3.0").HandleCommand(MyAddon, "mychat", "MyOptions", input)
-- end -- end
-- end -- end
-- Ace3v: experimental, user should copy info table if he wanna reuse it outside
-- then handler
local info_ = {}
function AceConfigCmd:HandleCommand(slashcmd, appName, input) function AceConfigCmd:HandleCommand(slashcmd, appName, input)
local optgetter = cfgreg:GetOptionsTable(appName) local optgetter = cfgreg:GetOptionsTable(appName)
@@ -757,32 +782,65 @@ function AceConfigCmd:HandleCommand(slashcmd, appName, input)
end end
local options = assert( optgetter("cmd", MAJOR) ) local options = assert( optgetter("cmd", MAJOR) )
local info = { -- Don't try to recycle this, it gets handed off to callbacks and whatnot -- Ace3v: prevent user from using AceConfigCmd as self
[0] = slashcmd, if self == AceConfigCmd then
appName = appName, error([[Usage: HandleCommand("slashcmd", "appName", "input"): 'self' - use your own 'self']], 2)
options = options, end
input = input,
self = self,
handler = self,
uiType = "cmd",
uiName = MAJOR,
}
handle(info, 1, options, 0) -- (info, inputpos, table, depth) --local info = { -- Don't try to recycle this, it gets handed off to callbacks and whatnot
-- [0] = slashcmd,
-- appName = appName,
-- options = options,
-- input = input,
-- self = self,
-- handler = self,
-- uiType = "cmd",
-- uiName = MAJOR,
--}
wipe(info_)
info_[0] = slashcmd
info_.appName = appName
info_.options = options
info_.input = input
info_.self = self
info_.handler = self
info_.uiType = "cmd"
info_.uiName = MAJOR
handle(info_, 1, options, 0) -- (info, inputpos, table, depth)
end end
--- Utility function to create a slash command handler. --- Utility function to create a slash command handler.
-- Also registers tab completion with AceTab -- Also registers tab completion with AceTab
-- @param slashcmd The slash command WITHOUT leading slash (only used for error output) -- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
-- @param appName The application name as given to `:RegisterOptionsTable()` -- @param appName The application name as given to `:RegisterOptionsTable()`
function AceConfigCmd:CreateChatCommand(slashcmd, appName) function AceConfigCmd:CreateChatCommand(slashcmd, appName, func)
if not AceConsole then if not AceConsole then
AceConsole = LibStub(AceConsoleName) AceConsole = LibStub(AceConsoleName)
end end
if AceConsole.RegisterChatCommand(self, slashcmd, function(input)
AceConfigCmd.HandleCommand(self, slashcmd, appName, input) -- upgradable -- Ace3v: prevent user from using AceConfigCmd as self
end, if self == AceConfigCmd then
true) then -- succesfully registered so lets get the command -> app table in error([[Usage: CreateChatCommand("slashcmd", "appName"[, "func"]): 'self' - use your own 'self']], 2)
end
local t = type(func)
-- Ace3v: make it possible to call another function
local handler
if t == "string" then
handler = function(input) self[func](self, input, slashcmd, appName) end
elseif t ~= "function" then
handler = function(input)
AceConfigCmd.HandleCommand(self, slashcmd, appName, input) -- upgradable
end
else
handler = func
end
if AceConsole.RegisterChatCommand(self, slashcmd, handler, true) then
-- succesfully registered so lets get the command -> app table in
commands[slashcmd] = appName commands[slashcmd] = appName
end end
end end
@@ -794,3 +852,12 @@ end
function AceConfigCmd:GetChatCommandOptions(slashcmd) function AceConfigCmd:GetChatCommandOptions(slashcmd)
return commands[slashcmd] return commands[slashcmd]
end end
function AceConfigCmd:Embed(target)
target["HandleCommand"] = self["HandleCommand"]
target["CreateChatCommand"] = self["CreateChatCommand"]
end
for addon in pairs(AceConfigCmd.embeds) do
AceConfigCmd:Embed(addon)
end
@@ -8,25 +8,24 @@
-- :IterateOptionsTables() (and :GetOptionsTable() if only given one argument) return a function reference that the requesting config handling addon must call with valid "uiType", "uiName". -- :IterateOptionsTables() (and :GetOptionsTable() if only given one argument) return a function reference that the requesting config handling addon must call with valid "uiType", "uiName".
-- @class file -- @class file
-- @name AceConfigRegistry-3.0 -- @name AceConfigRegistry-3.0
-- @release $Id: AceConfigRegistry-3.0.lua 1105 2013-12-08 22:11:58Z nevcairiel $ -- @release $Id: AceConfigRegistry-3.0.lua 1139 2016-07-03 07:43:51Z nevcairiel $
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0") local MAJOR, MINOR = "AceConfigRegistry-3.0", 16
local MAJOR, MINOR = "AceConfigRegistry-3.0-ElvUI", 2
local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR) local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfigRegistry then return end if not AceConfigRegistry then return end
AceConfigRegistry.tables = AceConfigRegistry.tables or {} AceConfigRegistry.tables = AceConfigRegistry.tables or {}
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
if not AceConfigRegistry.callbacks then if not AceConfigRegistry.callbacks then
AceConfigRegistry.callbacks = CallbackHandler:New(AceConfigRegistry) AceConfigRegistry.callbacks = CallbackHandler:New(AceConfigRegistry)
end end
-- Lua APIs -- Lua APIs
local tinsert, tconcat = table.insert, table.concat local tinsert, tconcat, tgetn = table.insert, table.concat, table.getn
local strfind, strmatch = string.find, string.match local strfind = string.find
local tgetn = table.getn local type, tostring, pairs = type, tostring, pairs
local type, tostring, select, pairs, unpack = type, tostring, select, pairs, unpack
local error, assert = error, assert local error, assert = error, assert
----------------------------------------------------------------------- -----------------------------------------------------------------------
@@ -41,17 +40,17 @@ AceConfigRegistry.validated = {
dialog = {}, dialog = {},
} }
local function err(msg, errlvl, ...) local function err(msg, errlvl, ...)
local t = {} local l = tgetn(arg)
for i=tgetn(arg),1,-1 do local i,j = 1,l
tinsert(t, (arg[i])) while i < j do
arg[i], arg[j] = arg[j], arg[i]
i = i+1
j = j-1
end end
error(MAJOR..":ValidateOptionsTable(): "..tconcat(t,".")..msg, errlvl+2) error(MAJOR..":ValidateOptionsTable(): "..tconcat(arg,".")..msg, errlvl+2)
end end
local isstring={["string"]=true, _="string"} local isstring={["string"]=true, _="string"}
local isstringfunc={["string"]=true,["function"]=true, _="string or funcref"} local isstringfunc={["string"]=true,["function"]=true, _="string or funcref"}
local istable={["table"]=true, _="table"} local istable={["table"]=true, _="table"}
@@ -92,17 +91,6 @@ local basekeys={
func=optmethodfalse, func=optmethodfalse,
arg={["*"]=true}, arg={["*"]=true},
width=optstring, width=optstring,
customWidth=optnumber,
textWidth=optmethodbool,
buttonElvUI=optmethodbool,
dragdrop=optmethodbool,
dragOnEnter=optmethodfalse,
dragOnLeave=optmethodfalse,
dragOnClick=optmethodfalse,
dragOnMouseUp=optmethodfalse,
dragOnMouseDown=optmethodfalse,
stateSwitchOnClick=optmethodfalse,
stateSwitchGetText=optmethodfalse,
} }
local typedkeys={ local typedkeys={
@@ -137,6 +125,7 @@ local typedkeys={
dialogControl=optstring, dialogControl=optstring,
dropdownControl=optstring, dropdownControl=optstring,
multiline=optboolnumber, multiline=optboolnumber,
nullable=optbool,
}, },
toggle={ toggle={
tristate=optbool, tristate=optbool,
@@ -156,6 +145,7 @@ local typedkeys={
}, },
select={ select={
values=ismethodtable, values=ismethodtable,
valuesTableDestroyable=optbool, -- Ace3v: if the values table is generated by AceCore.new
style={ style={
["nil"]=true, ["nil"]=true,
["string"]={dropdown=true,radio=true}, ["string"]={dropdown=true,radio=true},
@@ -168,6 +158,7 @@ local typedkeys={
}, },
multiselect={ multiselect={
values=ismethodtable, values=ismethodtable,
valuesTableDestroyable=optbool, -- Ace3v: if the values table is generated by AceCore.new
style=optstring, style=optstring,
tristate=optbool, tristate=optbool,
control=optstring, control=optstring,
@@ -176,82 +167,81 @@ local typedkeys={
}, },
color={ color={
hasAlpha=optmethodbool, hasAlpha=optmethodbool,
reset=opttable,
}, },
keybinding={ keybinding={
-- TODO -- TODO
}, },
} }
local function validateKey(k,errlvl,...) local function validateKey(k,errlvl,arg)
errlvl=(errlvl or 0)+1 errlvl=(errlvl or 0)+1
if type(k)~="string" then if type(k)~="string" then
err("["..tostring(k).."] - key is not a string", errlvl,unpack(arg)) err("["..tostring(k).."] - key is not a string", errlvl, arg)
end end
if strfind(k, "[%c\127]") then if strfind(k, "[%c\127]") then
err("["..tostring(k).."] - key name contained control characters", errlvl,unpack(arg)) err("["..tostring(k).."] - key name contained control characters", errlvl, arg)
end end
end end
local function validateVal(v, oktypes, errlvl,...) local function validateVal(v, oktypes, errlvl, arg)
errlvl=(errlvl or 0)+1 errlvl=(errlvl or 0)+1
local isok=oktypes[type(v)] or oktypes["*"] local isok=oktypes[type(v)] or oktypes["*"]
if not isok then if not isok then
err(": expected a "..oktypes._..", got '"..tostring(v).."'", errlvl,unpack(arg)) err(": expected a "..oktypes._..", got '"..tostring(v).."'", errlvl, arg)
end end
if type(isok)=="table" then -- isok was a table containing specific values to be tested for! if type(isok)=="table" then -- isok was a table containing specific values to be tested for!
if not isok[v] then if not isok[v] then
err(": did not expect "..type(v).." value '"..tostring(v).."'", errlvl,unpack(arg)) err(": did not expect "..type(v).." value '"..tostring(v).."'", errlvl, arg)
end end
end end
end end
local function validate(options,errlvl,...) local function validate(options,errlvl,arg)
errlvl=(errlvl or 0)+1 errlvl=(errlvl or 0)+1
-- basic consistency -- basic consistency
if type(options)~="table" then if type(options)~="table" then
err(": expected a table, got a "..type(options), errlvl,unpack(arg)) err(": expected a table, got a "..type(options), errlvl, arg)
end end
if type(options.type)~="string" then if type(options.type)~="string" then
err(".type: expected a string, got a "..type(options.type), errlvl,unpack(arg)) err(".type: expected a string, got a "..type(options.type), errlvl, arg)
end end
-- get type and 'typedkeys' member -- get type and 'typedkeys' member
local tk = typedkeys[options.type] local tk = typedkeys[options.type]
if not tk then if not tk then
err(".type: unknown type '"..options.type.."'", errlvl,unpack(arg)) err(".type: unknown type '"..options.type.."'", errlvl, arg)
end end
-- make sure that all options[] are known parameters -- make sure that all options[] are known parameters
for k,v in pairs(options) do for k,v in pairs(options) do
if not (tk[k] or basekeys[k]) then if not (tk[k] or basekeys[k]) then
err(": unknown parameter", errlvl,tostring(k),unpack(arg)) err(": unknown parameter", errlvl,tostring(k), arg)
end end
end end
-- verify that required params are there, and that everything is the right type -- verify that required params are there, and that everything is the right type
for k,oktypes in pairs(basekeys) do for k,oktypes in pairs(basekeys) do
validateVal(options[k], oktypes, errlvl,k,unpack(arg)) validateVal(options[k], oktypes, errlvl, k, arg)
end end
for k,oktypes in pairs(tk) do for k,oktypes in pairs(tk) do
validateVal(options[k], oktypes, errlvl,k,unpack(arg)) validateVal(options[k], oktypes, errlvl, k, arg)
end end
-- extra logic for groups -- extra logic for groups
if options.type=="group" then if options.type=="group" then
for k,v in pairs(options.args) do for k,v in pairs(options.args) do
validateKey(k,errlvl,"args",unpack(arg)) validateKey(k,errlvl,"args", arg)
validate(v, errlvl,k,"args",unpack(arg)) validate(v, errlvl,k,"args", arg)
end end
if options.plugins then if options.plugins then
for plugname,plugin in pairs(options.plugins) do for plugname,plugin in pairs(options.plugins) do
if type(plugin)~="table" then if type(plugin)~="table" then
err(": expected a table, got '"..tostring(plugin).."'", errlvl,tostring(plugname),"plugins",unpack(arg)) err(": expected a table, got '"..tostring(plugin).."'", errlvl,tostring(plugname), "plugins", arg)
end end
for k,v in pairs(plugin) do for k,v in pairs(plugin) do
validateKey(k,errlvl,tostring(plugname),"plugins",unpack(arg)) validateKey(k,errlvl,tostring(plugname),"plugins",arg)
validate(v, errlvl,k,tostring(plugname),"plugins",unpack(arg)) validate(v, errlvl,k,tostring(plugname),"plugins",arg)
end end
end end
end end
@@ -279,7 +269,7 @@ end
-- @param appName The application name as given to `:RegisterOptionsTable()` -- @param appName The application name as given to `:RegisterOptionsTable()`
function AceConfigRegistry:NotifyChange(appName) function AceConfigRegistry:NotifyChange(appName)
if not AceConfigRegistry.tables[appName] then return end if not AceConfigRegistry.tables[appName] then return end
AceConfigRegistry.callbacks:Fire("ConfigTableChange", appName) AceConfigRegistry.callbacks:Fire("ConfigTableChange", 1, appName)
end end
-- ------------------------------------------------------------------- -- -------------------------------------------------------------------
@@ -293,7 +283,7 @@ local function validateGetterArgs(uiType, uiName, errlvl)
if uiType~="cmd" and uiType~="dropdown" and uiType~="dialog" then if uiType~="cmd" and uiType~="dropdown" and uiType~="dialog" then
error(MAJOR..": Requesting options table: 'uiType' - invalid configuration UI type, expected 'cmd', 'dropdown' or 'dialog'", errlvl) error(MAJOR..": Requesting options table: 'uiType' - invalid configuration UI type, expected 'cmd', 'dropdown' or 'dialog'", errlvl)
end end
if not strmatch(uiName, "[A-Za-z]%-[0-9]") then -- Expecting e.g. "MyLib-1.2" if not strfind(uiName, "[A-Za-z]+-[0-9]") then -- Expecting e.g. "MyLib-1.2"
error(MAJOR..": Requesting options table: 'uiName' - badly formatted or missing version number. Expected e.g. 'MyLib-1.2'", errlvl) error(MAJOR..": Requesting options table: 'uiName' - badly formatted or missing version number. Expected e.g. 'MyLib-1.2'", errlvl)
end end
end end
@@ -1,12 +1,15 @@
--- AceDBOptions-3.0 provides a universal AceConfig options screen for managing AceDB-3.0 profiles. --- AceDBOptions-3.0 provides a universal AceConfig options screen for managing AceDB-3.0 profiles.
-- @class file -- @class file
-- @name AceDBOptions-3.0 -- @name AceDBOptions-3.0
-- @release $Id: AceDBOptions-3.0.lua 1066 2012-09-18 14:36:49Z nevcairiel $ -- @release $Id: AceDBOptions-3.0.lua 1140 2016-07-03 07:53:29Z nevcairiel $
local ACEDBO_MAJOR, ACEDBO_MINOR = "AceDBOptions-3.0", 15 local ACEDBO_MAJOR, ACEDBO_MINOR = "AceDBOptions-3.0", 15
local AceDBOptions, oldminor = LibStub:NewLibrary(ACEDBO_MAJOR, ACEDBO_MINOR) local AceDBOptions, oldminor = LibStub:NewLibrary(ACEDBO_MAJOR, ACEDBO_MINOR)
if not AceDBOptions then return end -- No upgrade needed if not AceDBOptions then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0")
local new, del = AceCore.new, AceCore.del
-- Lua APIs -- Lua APIs
local pairs, next = pairs, next local pairs, next = pairs, next
@@ -230,7 +233,6 @@ elseif LOCALE == "ptBR" then
end end
local defaultProfiles local defaultProfiles
local tmpprofiles = {}
-- Get a list of available profiles for the specified database. -- Get a list of available profiles for the specified database.
-- You can specify which profiles to include/exclude in the list using the two boolean parameters listed below. -- You can specify which profiles to include/exclude in the list using the two boolean parameters listed below.
@@ -239,8 +241,8 @@ local tmpprofiles = {}
-- @param nocurrent If true, then getProfileList will not display the current profile in the list -- @param nocurrent If true, then getProfileList will not display the current profile in the list
-- @return Hashtable of all profiles with the internal name as keys and the display name as value. -- @return Hashtable of all profiles with the internal name as keys and the display name as value.
local function getProfileList(db, common, nocurrent) local function getProfileList(db, common, nocurrent)
local profiles = {} local profiles = new()
local tmpprofiles = new()
-- copy existing profiles into the table -- copy existing profiles into the table
local currentProfile = db:GetCurrentProfile() local currentProfile = db:GetCurrentProfile()
for i,v in pairs(db:GetProfiles(tmpprofiles)) do for i,v in pairs(db:GetProfiles(tmpprofiles)) do
@@ -248,6 +250,7 @@ local function getProfileList(db, common, nocurrent)
profiles[v] = v profiles[v] = v
end end
end end
del(tmpprofiles)
-- add our default profiles to choose from ( or rename existing profiles) -- add our default profiles to choose from ( or rename existing profiles)
for k,v in pairs(defaultProfiles) do for k,v in pairs(defaultProfiles) do
@@ -290,6 +293,8 @@ end
"common" - returns all avaialble profiles + some commonly used profiles ("char - realm", "realm", "class", "Default") "common" - returns all avaialble profiles + some commonly used profiles ("char - realm", "realm", "class", "Default")
"both" - common except the active profile "both" - common except the active profile
]] ]]
-- Ace3v: It is recommanded to destroy the returned table by AceCore.del
-- if it is no longer needed
function OptionsHandlerPrototype:ListProfiles(info) function OptionsHandlerPrototype:ListProfiles(info)
local arg = info.arg local arg = info.arg
local profiles local profiles
@@ -308,7 +313,9 @@ end
function OptionsHandlerPrototype:HasNoProfiles(info) function OptionsHandlerPrototype:HasNoProfiles(info)
local profiles = self:ListProfiles(info) local profiles = self:ListProfiles(info)
return ((not next(profiles)) and true or false) local r = (not next(profiles)) and true or false
del(profiles)
return r
end end
--[[ Copy a profile ]] --[[ Copy a profile ]]
@@ -371,8 +378,7 @@ local optionsTable = {
current = { current = {
order = 11, order = 11,
type = "description", type = "description",
--name = function(info) return L["current"] .. " " .. NORMAL_FONT_COLOR_CODE .. info.handler:GetCurrentProfile() .. FONT_COLOR_CODE_CLOSE end, name = function(info) return L["current"] .. " " .. NORMAL_FONT_COLOR_CODE .. info.handler:GetCurrentProfile() .. FONT_COLOR_CODE_CLOSE end,
name = "t",
width = "default", width = "default",
}, },
choosedesc = { choosedesc = {
@@ -387,6 +393,7 @@ local optionsTable = {
order = 30, order = 30,
get = false, get = false,
set = "SetProfile", set = "SetProfile",
nullable = false, -- Ace3v: we do not want a null or empty value
}, },
choose = { choose = {
name = L["choose"], name = L["choose"],
@@ -396,6 +403,7 @@ local optionsTable = {
get = "GetCurrentProfile", get = "GetCurrentProfile",
set = "SetProfile", set = "SetProfile",
values = "ListProfiles", values = "ListProfiles",
valuesTableDestroyable = true,
arg = "common", arg = "common",
}, },
copydesc = { copydesc = {
@@ -411,6 +419,7 @@ local optionsTable = {
get = false, get = false,
set = "CopyProfile", set = "CopyProfile",
values = "ListProfiles", values = "ListProfiles",
valuesTableDestroyable = true,
disabled = "HasNoProfiles", disabled = "HasNoProfiles",
arg = "nocurrent", arg = "nocurrent",
}, },
@@ -427,6 +436,7 @@ local optionsTable = {
get = false, get = false,
set = "DeleteProfile", set = "DeleteProfile",
values = "ListProfiles", values = "ListProfiles",
valuesTableDestroyable = true,
disabled = "HasNoProfiles", disabled = "HasNoProfiles",
arg = "nocurrent", arg = "nocurrent",
confirm = true, confirm = true,
@@ -30,13 +30,17 @@ local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
if not AceGUI then return end -- No upgrade needed if not AceGUI then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0")
local hooksecurefunc = AceCore.hooksecurefunc
local safecall = AceCore.safecall
-- Lua APIs -- Lua APIs
local tconcat, tgetn, tremove, tinsert = table.concat, table.getn,table.remove, table.insert local tconcat, tremove, tinsert, tgetn, tsetn = table.concat, table.remove, table.insert, table.getn, table.setn
local gsub, strupper = string.gsub, string.upper local pairs, next, type = pairs, next, type
local select, pairs, next, type = select, pairs, next, type
local error, assert, loadstring = error, assert, loadstring local error, assert, loadstring = error, assert, loadstring
local setmetatable, rawget, rawset = setmetatable, rawget, rawset local setmetatable, rawget, rawset = setmetatable, rawget, rawset
local math_max = math.max local math_max = math.max
local strupper, strfmt = string.upper, string.format
-- WoW APIs -- WoW APIs
local UIParent = UIParent local UIParent = UIParent
@@ -52,73 +56,17 @@ AceGUI.LayoutRegistry = AceGUI.LayoutRegistry or {}
AceGUI.WidgetBase = AceGUI.WidgetBase or {} AceGUI.WidgetBase = AceGUI.WidgetBase or {}
AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {} AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {}
AceGUI.WidgetVersions = AceGUI.WidgetVersions or {} AceGUI.WidgetVersions = AceGUI.WidgetVersions or {}
AceGUI.HookedFunctions = AceGUI.HookedFunctions or {}
-- local upvalues -- local upvalues
local WidgetRegistry = AceGUI.WidgetRegistry local WidgetRegistry = AceGUI.WidgetRegistry
local LayoutRegistry = AceGUI.LayoutRegistry local LayoutRegistry = AceGUI.LayoutRegistry
local WidgetVersions = AceGUI.WidgetVersions local WidgetVersions = AceGUI.WidgetVersions
local HookedFunctions = AceGUI.HookedFunctions
--[[
xpcall safecall implementation
]]
local xpcall = xpcall
local function errorhandler(err)
return geterrorhandler()(err)
end
local function CreateDispatcher(argCount)
local code = [[
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = unpack(arg)
return xpcall(call, function(err) return geterrorhandler()(err) end)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = gsub(code, "ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
end
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
Dispatchers[0] = function(func)
return xpcall(func, errorhandler)
end
local function safecall(func, ...)
return Dispatchers[tgetn(arg)](func, unpack(arg))
end
-- Recycling functions -- Recycling functions
local newWidget, delWidget local newWidget, delWidget
do do
-- Version Upgrade in Minor 29
-- Internal Storage of the objects changed, from an array table
-- to a hash table, and additionally we introduced versioning on
-- the widgets which would discard all widgets from a pre-29 version
-- anyway, so we just clear the storage now, and don't try to
-- convert the storage tables to the new format.
-- This should generally not cause *many* widgets to end up in trash,
-- since once dialogs are opened, all addons should be loaded already
-- and AceGUI should be on the latest version available on the users
-- setup.
-- -- nevcairiel - Nov 2nd, 2009
if oldminor and oldminor < 29 and AceGUI.objPools then
AceGUI.objPools = nil
end
AceGUI.objPools = AceGUI.objPools or {} AceGUI.objPools = AceGUI.objPools or {}
local objPools = AceGUI.objPools local objPools = AceGUI.objPools
--Returns a new instance, if none are available either returns a new table or calls the given contructor --Returns a new instance, if none are available either returns a new table or calls the given contructor
@@ -157,6 +105,35 @@ do
end end
end end
-- Ace3v: when a container contains many children, we can only use the variable arguments
local function _fixlevels(parent, ...)
local lv = parent:GetFrameLevel() + 1
for i = 1, tgetn(arg) do
local child = arg[i]
child:SetFrameLevel(lv)
_fixlevels(child, child:GetChildren())
end
end
local function fixlevels(parent)
return _fixlevels(parent, parent:GetChildren())
end
AceGUI.fixlevels = fixlevels
-- Ace3v: attention! this function is recursive
local function _fixstrata(strata, parent, ...)
parent:SetFrameStrata(strata)
for i = 1, tgetn(arg) do
local child = arg[i]
_fixstrata(strata, child, child:GetChildren())
end
end
local function fixstrata(strata, parent)
return _fixstrata(strata, parent, parent:GetChildren())
end
AceGUI.fixstrata = fixstrata
------------------- -------------------
-- API Functions -- -- API Functions --
@@ -173,27 +150,15 @@ function AceGUI:Create(type)
if WidgetRegistry[type] then if WidgetRegistry[type] then
local widget = newWidget(type) local widget = newWidget(type)
if rawget(widget, "Acquire") then
widget.OnAcquire = widget.Acquire
widget.Acquire = nil
elseif rawget(widget, "Aquire") then
widget.OnAcquire = widget.Aquire
widget.Aquire = nil
end
if rawget(widget, "Release") then
widget.OnRelease = rawget(widget, "Release")
widget.Release = nil
end
if widget.OnAcquire then if widget.OnAcquire then
widget:OnAcquire() widget:OnAcquire()
else else
error(format("Widget type %s doesn't supply an OnAcquire Function", type)) error(strfmt("Widget type %s doesn't supply an OnAcquire Function", type))
end end
-- Set the default Layout ("List") -- Set the default Layout ("List")
safecall(widget.SetLayout, widget, "List") safecall(widget.SetLayout, 2, widget, "List")
safecall(widget.ResumeLayout, widget) safecall(widget.ResumeLayout, 1, widget)
return widget return widget
end end
end end
@@ -204,14 +169,14 @@ end
-- If this widget is a Container-Widget, all of its Child-Widgets will be releases as well. -- If this widget is a Container-Widget, all of its Child-Widgets will be releases as well.
-- @param widget The widget to release -- @param widget The widget to release
function AceGUI:Release(widget) function AceGUI:Release(widget)
safecall(widget.PauseLayout, widget) safecall(widget.PauseLayout, 1, widget)
widget:Fire("OnRelease") widget:Fire("OnRelease")
safecall(widget.ReleaseChildren, widget) safecall(widget.ReleaseChildren, 1, widget)
if widget.OnRelease then if widget.OnRelease then
widget:OnRelease() widget:OnRelease()
-- else -- else
-- error(format("Widget type %s doesn't supply an OnRelease Function", widget.type)) -- error(strfmt("Widget type %s doesn't supply an OnRelease Function", widget.type))
end end
for k in pairs(widget.userdata) do for k in pairs(widget.userdata) do
widget.userdata[k] = nil widget.userdata[k] = nil
@@ -246,7 +211,7 @@ end
-- @param widget The widget that should be focused -- @param widget The widget that should be focused
function AceGUI:SetFocus(widget) function AceGUI:SetFocus(widget)
if self.FocusedWidget and self.FocusedWidget ~= widget then if self.FocusedWidget and self.FocusedWidget ~= widget then
safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget) safecall(self.FocusedWidget.ClearFocus, 1, self.FocusedWidget)
end end
self.FocusedWidget = widget self.FocusedWidget = widget
end end
@@ -256,7 +221,7 @@ end
-- e.g. titlebar of a frame being clicked -- e.g. titlebar of a frame being clicked
function AceGUI:ClearFocus() function AceGUI:ClearFocus()
if self.FocusedWidget then if self.FocusedWidget then
safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget) safecall(self.FocusedWidget.ClearFocus, 1, self.FocusedWidget)
self.FocusedWidget = nil self.FocusedWidget = nil
end end
end end
@@ -301,6 +266,7 @@ do
frame:SetParent(nil) frame:SetParent(nil)
frame:SetParent(parent.content) frame:SetParent(parent.content)
self.parent = parent self.parent = parent
fixlevels(frame)
end end
WidgetBase.SetCallback = function(self, name, func) WidgetBase.SetCallback = function(self, name, func)
@@ -309,9 +275,11 @@ do
end end
end end
WidgetBase.Fire = function(self, name, ...) WidgetBase.Fire = function(self,name,argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
if self.events[name] then argc = argc or 0
local success, ret = safecall(self.events[name], self, name, unpack(arg)) local func = self.events[name]
if func then
local success, ret = safecall(func,argc+3,self,name,argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
if success then if success then
return ret return ret
end end
@@ -362,8 +330,8 @@ do
AceGUI:Release(self) AceGUI:Release(self)
end end
WidgetBase.SetPoint = function(self, ...) WidgetBase.SetPoint = function(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
return self.frame:SetPoint(unpack(arg)) return self.frame:SetPoint(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
end end
WidgetBase.ClearAllPoints = function(self) WidgetBase.ClearAllPoints = function(self)
@@ -374,8 +342,8 @@ do
return self.frame:GetNumPoints() return self.frame:GetNumPoints()
end end
WidgetBase.GetPoint = function(self, ...) WidgetBase.GetPoint = function(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
return self.frame:GetPoint(unpack(arg)) return self.frame:GetPoint(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
end end
WidgetBase.GetUserDataTable = function(self) WidgetBase.GetUserDataTable = function(self)
@@ -433,7 +401,7 @@ do
if self.LayoutPaused then if self.LayoutPaused then
return return
end end
safecall(self.LayoutFunc, self.content, self.children) safecall(self.LayoutFunc, 2, self.content, self.children)
end end
--call this function to layout, makes sure layed out objects get a frame to get sizes etc --call this function to layout, makes sure layed out objects get a frame to get sizes etc
@@ -462,21 +430,48 @@ do
self:DoLayout() self:DoLayout()
end end
WidgetContainerBase.AddChildren = function(self, ...) do
for i = 1, tgetn(arg) do local args = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
local child = arg[i] WidgetContainerBase.AddChildren = function(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
args[1] = a1
args[2] = a2
args[3] = a3
args[4] = a4
args[5] = a5
args[6] = a6
args[7] = a7
args[8] = a8
args[9] = a9
args[10] = a10
for i = 1,10 do
local child = args[i]
arg[i] = nil
if not child then break end
tinsert(self.children, child) tinsert(self.children, child)
child:SetParent(self) child:SetParent(self)
child.frame:Show() child.frame:Show()
end end
self:DoLayout() self:DoLayout()
end end
end -- WidgetContainerBase.AddChildren
WidgetContainerBase.ReleaseChildren = function(self) WidgetContainerBase.ReleaseChildren = function(self)
local children = self.children local children = self.children
for i = 1,tgetn(children) do for i = 1,tgetn(children) do
AceGUI:Release(children[i]) AceGUI:Release(tremove(children))
children[i] = nil end
end
WidgetContainerBase.SetParent = function(self, parent)
WidgetBase.SetParent(self, parent)
local lv = self.frame:GetFrameLevel()
self.content:SetFrameLevel(lv+1)
local children = self.children
for i = 1,tgetn(children) do
local child = children[i]
child:SetParent(self)
end end
end end
@@ -573,7 +568,7 @@ end
function AceGUI:RegisterLayout(Name, LayoutFunc) function AceGUI:RegisterLayout(Name, LayoutFunc)
assert(type(LayoutFunc) == "function") assert(type(LayoutFunc) == "function")
if type(Name) == "string" then if type(Name) == "string" then
Name = strupper(Name) Name = string.upper(Name)
end end
LayoutRegistry[Name] = LayoutFunc LayoutRegistry[Name] = LayoutFunc
end end
@@ -658,7 +653,7 @@ AceGUI:RegisterLayout("List",
height = height + (frame.height or frame:GetHeight() or 0) height = height + (frame.height or frame:GetHeight() or 0)
end end
safecall(content.obj.LayoutFinished, content.obj, nil, height) safecall(content.obj.LayoutFinished, 3, content.obj, nil, height)
end) end)
-- A single control fills the whole content area -- A single control fills the whole content area
@@ -669,14 +664,15 @@ AceGUI:RegisterLayout("Fill",
children[1]:SetHeight(content:GetHeight() or 0) children[1]:SetHeight(content:GetHeight() or 0)
children[1].frame:SetAllPoints(content) children[1].frame:SetAllPoints(content)
children[1].frame:Show() children[1].frame:Show()
safecall(content.obj.LayoutFinished, content.obj, nil, children[1].frame:GetHeight()) safecall(content.obj.LayoutFinished, 3, content.obj, nil, children[1].frame:GetHeight())
end end
end) end)
-- Ace3v: currently only a1 used
local layoutrecursionblock = nil local layoutrecursionblock = nil
local function safelayoutcall(object, func, ...) local function safelayoutcall(object, func, a1)
layoutrecursionblock = true layoutrecursionblock = true
object[func](object, unpack(arg)) object[func](object, a1)
layoutrecursionblock = nil layoutrecursionblock = nil
end end
@@ -809,5 +805,5 @@ AceGUI:RegisterLayout("Flow",
end end
height = height + rowheight + 3 height = height + rowheight + 3
safecall(content.obj.LayoutFinished, content.obj, nil, height) safecall(content.obj.LayoutFinished, 3, content.obj, nil, height)
end) end)
@@ -1,5 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ <Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd"> ..\FrameXML\UI.xsd">
<Script file="AceGUI-3.0.lua"/> <Script file="AceGUI-3.0.lua"/>
<Include file="widgets\widgets.xml"/>
</Ui> </Ui>
@@ -15,11 +15,11 @@ local CreateFrame = CreateFrame
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function SelectedGroup(self, event, value) local function SelectedGroup(self, event, _, value)
local group = self.parentgroup local group = self.parentgroup
local status = group.status or group.localstatus local status = group.status or group.localstatus
status.selected = value status.selected = value
self.parentgroup:Fire("OnGroupSelected", value) self.parentgroup:Fire("OnGroupSelected", 1, value)
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -63,7 +63,7 @@ local methods = {
self.dropdown:SetValue(group) self.dropdown:SetValue(group)
local status = self.status or self.localstatus local status = self.status or self.localstatus
status.selected = group status.selected = group
self:Fire("OnGroupSelected", group) self:Fire("OnGroupSelected", 1, group)
end, end,
["OnWidthSet"] = function(self, width) ["OnWidthSet"] = function(self, width)
@@ -1,13 +1,15 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Frame Container Frame Container
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Frame", 26 local Type, Version = "Frame", 24
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local AceCore = LibStub("AceCore-3.0")
local wipe = AceCore.wipe
-- Lua APIs -- Lua APIs
local pairs, assert, type = pairs, assert, type local pairs, assert, type = pairs, assert, type
local wipe = table.wipe
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
@@ -25,10 +27,6 @@ local function Button_OnClick()
this.obj:Hide() this.obj:Hide()
end end
local function Frame_OnShow()
this.obj:Fire("OnShow")
end
local function Frame_OnClose() local function Frame_OnClose()
this.obj:Fire("OnClose") this.obj:Fire("OnClose")
end end
@@ -190,7 +188,6 @@ local function Constructor()
frame:SetBackdropColor(0, 0, 0, 1) frame:SetBackdropColor(0, 0, 0, 1)
frame:SetMinResize(400, 200) frame:SetMinResize(400, 200)
frame:SetToplevel(true) frame:SetToplevel(true)
frame:SetScript("OnShow", Frame_OnShow)
frame:SetScript("OnHide", Frame_OnClose) frame:SetScript("OnHide", Frame_OnClose)
frame:SetScript("OnMouseDown", Frame_OnMouseDown) frame:SetScript("OnMouseDown", Frame_OnMouseDown)
@@ -248,6 +245,7 @@ local function Constructor()
titlebg_r:SetWidth(30) titlebg_r:SetWidth(30)
titlebg_r:SetHeight(40) titlebg_r:SetHeight(40)
-- bottom right sizer
local sizer_se = CreateFrame("Frame", nil, frame) local sizer_se = CreateFrame("Frame", nil, frame)
sizer_se:SetPoint("BOTTOMRIGHT", 0, 0) sizer_se:SetPoint("BOTTOMRIGHT", 0, 0)
sizer_se:SetWidth(25) sizer_se:SetWidth(25)
@@ -6,9 +6,12 @@ local Type, Version = "ScrollFrame", 24
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local fixlevels = AceGUI.fixlevels
-- Lua APIs -- Lua APIs
local pairs, assert, type = pairs, assert, type local pairs, assert, type = pairs, assert, type
local min, max, floor, abs = math.min, math.max, math.floor, math.abs local min, max, floor, abs = math.min, math.max, math.floor, math.abs
local format = string.format
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
@@ -24,16 +27,16 @@ end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function ScrollFrame_OnMouseWheel(frame, value) local function ScrollFrame_OnMouseWheel()
frame.obj:MoveScroll(value) this.obj:MoveScroll(arg1)
end end
local function ScrollFrame_OnSizeChanged() local function ScrollFrame_OnSizeChanged()
this:SetScript("OnUpdate", FixScrollOnUpdate) this:SetScript("OnUpdate", FixScrollOnUpdate)
end end
local function ScrollBar_OnScrollValueChanged(frame, value) local function ScrollBar_OnScrollValueChanged()
frame.obj:SetScroll(value) this.obj:SetScroll(arg1)
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -50,7 +53,7 @@ local methods = {
for k in pairs(self.localstatus) do for k in pairs(self.localstatus) do
self.localstatus[k] = nil self.localstatus[k] = nil
end end
self.scrollframe:SetPoint("BOTTOMRIGHT", 0, 0) self.scrollframe:SetPoint("BOTTOMRIGHT",0,0)
self.scrollbar:Hide() self.scrollbar:Hide()
self.scrollBarShown = nil self.scrollBarShown = nil
self.content.height, self.content.width = nil, nil self.content.height, self.content.width = nil, nil
@@ -89,40 +92,46 @@ local methods = {
end, end,
["FixScroll"] = function(self) ["FixScroll"] = function(self)
if self.updateLock then return end if self.updateLock then return end
self.updateLock = true self.updateLock = true
local status = self.status or self.localstatus local status = self.status or self.localstatus
local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight() local scrollframe, content, scrollbar = self.scrollframe, self.content, self.scrollbar
local viewheight, height = self.scrollframe:GetHeight(), self.content:GetHeight()
local offset = status.offset or 0 local offset = status.offset or 0
local curvalue = self.scrollbar:GetValue() local curvalue = scrollbar:GetValue()
-- Give us a margin of error of 2 pixels to stop some conditions that i would blame on floating point inaccuracys -- Give us a margin of error of 2 pixels to stop some conditions that i would blame on floating point inaccuracys
-- No-one is going to miss 2 pixels at the bottom of the frame, anyhow! -- No-one is going to miss 2 pixels at the bottom of the frame, anyhow!
if viewheight < height + 2 then
if height < viewheight + 2 then
if self.scrollBarShown then if self.scrollBarShown then
self.scrollBarShown = nil self.scrollBarShown = nil
self.scrollbar:Hide() scrollbar:Hide()
self.scrollbar:SetValue(0) scrollbar:SetValue(0)
self.scrollframe:SetPoint("BOTTOMRIGHT", 0, 0) scrollframe:SetPoint("BOTTOMRIGHT",0,0)
self:DoLayout() self:DoLayout()
end end
offset = 0
else else
if not self.scrollBarShown then if not self.scrollBarShown then
self.scrollBarShown = true self.scrollBarShown = true
self.scrollbar:Show() scrollbar:Show()
self.scrollframe:SetPoint("BOTTOMRIGHT", -20, 0) scrollframe:SetPoint("BOTTOMRIGHT", -20, 0)
self:DoLayout() self:DoLayout()
end end
local value = (offset / (viewheight - height) * 1000) local value = (offset / (height - viewheight) * 1000)
if value > 1000 then value = 1000 end if value > 1000 then
self.scrollbar:SetValue(value) value = 1000
self:SetScroll(value) offset = height - viewheight
if value < 1000 then
self.content:ClearAllPoints()
self.content:SetPoint("TOPLEFT", 0, offset)
self.content:SetPoint("TOPRIGHT", 0, offset)
status.offset = offset
end end
scrollbar:SetValue(value)
self:SetScroll(value)
end end
status.offset = offset
scrollframe:SetScrollChild(content)
content:ClearAllPoints()
content:SetPoint("TOPLEFT", 0, offset)
content:SetPoint("TOPRIGHT", 0, offset)
self.updateLock = nil self.updateLock = nil
end, end,
@@ -157,8 +166,8 @@ local function Constructor()
local num = AceGUI:GetNextWidgetNum(Type) local num = AceGUI:GetNextWidgetNum(Type)
local scrollframe = CreateFrame("ScrollFrame", nil, frame) local scrollframe = CreateFrame("ScrollFrame", nil, frame)
scrollframe:SetPoint("TOPLEFT", 0, 0) scrollframe:SetPoint("TOPLEFT",0,0)
scrollframe:SetPoint("BOTTOMRIGHT", 0, 0) scrollframe:SetPoint("BOTTOMRIGHT",0,0)
scrollframe:EnableMouseWheel(true) scrollframe:EnableMouseWheel(true)
scrollframe:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel) scrollframe:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel)
scrollframe:SetScript("OnSizeChanged", ScrollFrame_OnSizeChanged) scrollframe:SetScript("OnSizeChanged", ScrollFrame_OnSizeChanged)
@@ -180,8 +189,8 @@ local function Constructor()
--Container Support --Container Support
local content = CreateFrame("Frame", nil, scrollframe) local content = CreateFrame("Frame", nil, scrollframe)
content:SetPoint("TOPLEFT", 0, 0) content:SetPoint("TOPLEFT",0,0)
content:SetPoint("TOPRIGHT", 0, 0) content:SetPoint("TOPRIGHT",0,0)
content:SetHeight(400) content:SetHeight(400)
scrollframe:SetScrollChild(content) scrollframe:SetScrollChild(content)
@@ -2,18 +2,22 @@
TabGroup Container TabGroup Container
Container that uses tabs on top to switch between groups. Container that uses tabs on top to switch between groups.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "TabGroup", 36 local Type, Version = "TabGroup", 35
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local AceCore = LibStub("AceCore-3.0")
local wipe = AceCore.wipe
-- Lua APIs -- Lua APIs
local pairs, ipairs, assert, type, wipe = pairs, ipairs, assert, type, wipe local pairs, ipairs, assert, type, wipe = pairs, ipairs, assert, type, wipe
local tgetn = table.getn local tgetn = table.getn
local strfmt = string.format
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
local _G = _G local _G = AceCore._G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
@@ -30,57 +34,60 @@ Support functions
local function UpdateTabLook(frame) local function UpdateTabLook(frame)
if frame.disabled then if frame.disabled then
PanelTemplates_SetDisabledTabState(frame) PanelTemplates_SetDisabledTabState(frame)
frame:SetAlpha(0.5)
elseif frame.selected then elseif frame.selected then
PanelTemplates_SelectTab(frame) PanelTemplates_SelectTab(frame)
frame:SetAlpha(1)
else else
PanelTemplates_DeselectTab(frame) PanelTemplates_DeselectTab(frame)
frame:SetAlpha(0.5)
end end
end end
local function Tab_SetText(frame, text) local function Tab_SetText(tab, text)
frame:_SetText(text) tab:_SetText(text)
local width = frame.obj.frame.width or frame.obj.frame:GetWidth() or 0 local width = tab.obj.frame.width or tab.obj.frame:GetWidth() or 0
PanelTemplates_TabResize(frame, 0, nil, width, frame:GetFontString():GetStringWidth()) PanelTemplates_TabResize(0, tab, nil, width)
end end
local function Tab_SetSelected(frame, selected) local function Tab_SetSelected(tab, selected)
frame.selected = selected tab.selected = selected
UpdateTabLook(frame) UpdateTabLook(tab)
end end
local function Tab_SetDisabled(frame, disabled) local function Tab_SetDisabled(tab, disabled)
frame.disabled = disabled tab.disabled = disabled
UpdateTabLook(frame) UpdateTabLook(tab)
end end
local function BuildTabsOnUpdate(frame) local function BuildTabsOnUpdate()
local self = frame.obj local self = this.obj
self:BuildTabs() self:BuildTabs()
frame:SetScript("OnUpdate", nil) this:SetScript("OnUpdate", nil)
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Tab_OnClick(frame) local function Tab_OnClick()
if not (frame.selected or frame.disabled) then if not (this.selected or this.disabled) then
PlaySound("igCharacterInfoTab") PlaySound("igCharacterInfoTab")
frame.obj:SelectTab(frame.value) this.obj:SelectTab(this.value)
end end
end end
local function Tab_OnEnter(frame) local function Tab_OnEnter()
local self = frame.obj local self = this.obj
self:Fire("OnTabEnter", self.tabs[frame.id].value, frame) self:Fire("OnTabEnter", 2, self.tabs[this.id].value, this)
end end
local function Tab_OnLeave(frame) local function Tab_OnLeave()
local self = frame.obj local self = this.obj
self:Fire("OnTabLeave", self.tabs[frame.id].value, frame) self:Fire("OnTabLeave", 2, self.tabs[this.id].value, this)
end end
local function Tab_OnShow(frame) local function Tab_OnShow()
_G[frame:GetName().."HighlightTexture"]:SetWidth(frame:GetTextWidth() + 30) _G[this:GetName().."HighlightTexture"]:SetWidth(this:GetTextWidth() + 30)
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -103,16 +110,31 @@ local methods = {
end, end,
["CreateTab"] = function(self, id) ["CreateTab"] = function(self, id)
local tabname = format("AceGUITabGroup%dTab%d", self.num, id) local tabname = strfmt("AceGUITabGroup%dTab%d", self.num, id)
local tab = CreateFrame("Button", tabname, self.border, "OptionsFrameTabButtonTemplate") local tab = CreateFrame("Button", tabname, self.border, "TabButtonTemplate")
-- Normal texture
local texture = getglobal(tabname.."Left")
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
texture:ClearAllPoints()
texture:SetPoint("BOTTOMLEFT", tab,"BOTTOMLEFT")
texture:SetPoint("TOPLEFT", tab,"TOPLEFT")
texture = getglobal(tabname.."Middle")
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
texture = getglobal(tabname.."Right")
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
-- Disabled texture
texture = getglobal(tabname.."LeftDisabled")
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
texture:SetPoint("BOTTOMLEFT", tab,"BOTTOMLEFT")
texture:SetPoint("TOPLEFT", tab,"TOPLEFT")
texture = getglobal(tabname.."MiddleDisabled")
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
texture = getglobal(tabname.."RightDisabled")
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
tab.obj = self tab.obj = self
tab.id = id tab.id = id
tab.text = _G[tabname .. "Text"]
tab.text:ClearAllPoints()
tab.text:SetPoint("LEFT", 14, -3)
tab.text:SetPoint("RIGHT", -12, -3)
tab:SetScript("OnClick", Tab_OnClick) tab:SetScript("OnClick", Tab_OnClick)
tab:SetScript("OnEnter", Tab_OnEnter) tab:SetScript("OnEnter", Tab_OnEnter)
tab:SetScript("OnLeave", Tab_OnLeave) tab:SetScript("OnLeave", Tab_OnLeave)
@@ -154,7 +176,7 @@ local methods = {
end end
status.selected = value status.selected = value
if found then if found then
self:Fire("OnGroupSelected",value) self:Fire("OnGroupSelected",1,value)
end end
end, end,
@@ -187,9 +209,14 @@ local methods = {
end end
tab:Show() tab:Show()
tab:SetText(v.text) if type(v) == "table" then
tab:SetDisabled(v.disabled) tab:SetText(v.text)
tab.value = v.value tab:SetDisabled(v.disabled)
tab.value = v.value
elseif type(v) == "string" then
tab:SetText(v)
tab.value = v
end
widths[i] = tab:GetWidth() - 6 --tabs are anchored 10 pixels from the right side of the previous one to reduce spacing, but add a fixed 4px padding for the text widths[i] = tab:GetWidth() - 6 --tabs are anchored 10 pixels from the right side of the previous one to reduce spacing, but add a fixed 4px padding for the text
end end
@@ -257,12 +284,12 @@ local methods = {
end end
for i = starttab, endtab do for i = starttab, endtab do
PanelTemplates_TabResize(tabs[i], padding + 4, nil, width, tabs[i]:GetFontString():GetStringWidth()) PanelTemplates_TabResize(padding + 4, tabs[i], nil, width)
end end
starttab = endtab + 1 starttab = endtab + 1
end end
self.borderoffset = (hastitle and 17 or 10)+((numrows)*20) self.borderoffset = (hastitle and 17 or 10)+((numrows)*20)+7
self.border:SetPoint("TOPLEFT", 1, -self.borderoffset) self.border:SetPoint("TOPLEFT", 1, -self.borderoffset)
end, end,
@@ -6,12 +6,15 @@ local Type, Version = "TreeGroup", 40
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local AceCore = LibStub("AceCore-3.0")
local strsplit = AceCore.strsplit
local _G = AceCore._G
-- Lua APIs -- Lua APIs
local next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type local next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type
local math_min, math_max, floor = math.min, math.max, floor local math_min, math_max, floor = math.min, math.max, floor
local select, tremove, unpack, tconcat = select, table.remove, unpack, table.concat local tgetn, tremove, unpack, tconcat = table.getn, table.remove, unpack, table.concat
local strsplit = string.split local strfmt = string.format
local tgetn = table.getn
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
@@ -81,12 +84,13 @@ local function UpdateButton(button, treeline, selected, canExpand, isExpanded)
local normalTexture = button:GetNormalTexture() local normalTexture = button:GetNormalTexture()
local line = button.line local line = button.line
button.level = level button.level = level
if ( level == 1 ) then if ( level == 1 ) then
button:SetNormalFontObject("GameFontNormal") button.text:SetFontObject("GameFontNormal")
button:SetHighlightFontObject("GameFontHighlight") button:SetHighlightFontObject("GameFontHighlight")
button.text:SetPoint("LEFT", (icon and 16 or 0) + 8, 2) button.text:SetPoint("LEFT", (icon and 16 or 0) + 8, 2)
else else
button:SetNormalFontObject("GameFontHighlightSmall") button.text:SetFontObject("GameFontHighlightSmall")
button:SetHighlightFontObject("GameFontHighlightSmall") button:SetHighlightFontObject("GameFontHighlightSmall")
button.text:SetPoint("LEFT", (icon and 16 or 0) + 8 * level, 2) button.text:SetPoint("LEFT", (icon and 16 or 0) + 8 * level, 2)
end end
@@ -156,134 +160,143 @@ local function addLine(self, v, tree, level, parent)
else else
line.hasChildren = nil line.hasChildren = nil
end end
self.lines[tgetn(self.lines)+1] = line tinsert(self.lines, line)
return line return line
end end
--fire an update after one frame to catch the treeframes height --fire an update after one frame to catch the treeframes height
local function FirstFrameUpdate(frame) local function FirstFrameUpdate()
local self = frame.obj local self = this.obj
frame:SetScript("OnUpdate", nil) this:SetScript("OnUpdate", nil)
self:RefreshTree() self:RefreshTree()
end end
local function BuildUniqueValue(...) local BuildUniqueValue
local n = select('#', arg) do
if n == 1 then local args = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
return arg1 function BuildUniqueValue(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
else args[1] = a1
return (unpack(arg)).."\001"..BuildUniqueValue(select(2,arg)) args[2] = a2
end args[3] = a3
args[4] = a4
args[5] = a5
args[6] = a6
args[7] = a7
args[8] = a8
args[9] = a9
args[10] = a10
return tconcat(tmp, "\001", 1, tgetn(args))
end
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Expand_OnClick(frame) local function Expand_OnClick()
local button = frame.button local button = this.button
local self = button.obj local self = button.obj
local status = (self.status or self.localstatus).groups local status = (self.status or self.localstatus).groups
status[button.uniquevalue] = not status[button.uniquevalue] status[button.uniquevalue] = not status[button.uniquevalue]
self:RefreshTree() self:RefreshTree()
end end
local function Button_OnClick(frame) local function Button_OnClick()
local self = frame.obj local self = this.obj
self:Fire("OnClick", frame.uniquevalue, frame.selected) self:Fire("OnClick", 2, this.uniquevalue, this.selected)
if not frame.selected then if not this.selected then
self:SetSelected(frame.uniquevalue) self:SetSelected(this.uniquevalue)
frame.selected = true this.selected = true
frame:LockHighlight() this:LockHighlight()
self:RefreshTree() self:RefreshTree()
end end
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function Button_OnDoubleClick(button) local function Button_OnDoubleClick()
local self = button.obj local self = this.obj
local status = self.status or self.localstatus local status = self.status or self.localstatus
local status = (self.status or self.localstatus).groups local status = (self.status or self.localstatus).groups
status[button.uniquevalue] = not status[button.uniquevalue] status[this.uniquevalue] = not status[this.uniquevalue]
self:RefreshTree() self:RefreshTree()
end end
local function Button_OnEnter(frame) local function Button_OnEnter()
local self = frame.obj local self = this.obj
self:Fire("OnButtonEnter", frame.uniquevalue, frame) self:Fire("OnButtonEnter", 2, this.uniquevalue, this)
if self.enabletooltips then if self.enabletooltips then
GameTooltip:SetOwner(frame, "ANCHOR_NONE") GameTooltip:SetOwner(this, "ANCHOR_NONE")
GameTooltip:SetPoint("LEFT",frame,"RIGHT") GameTooltip:SetPoint("LEFT",this,"RIGHT")
GameTooltip:SetText(frame.text:GetText() or "", 1, .82, 0, 1) GameTooltip:SetText(this.text:GetText() or "", 1, .82, 0, true)
GameTooltip:Show() GameTooltip:Show()
end end
end end
local function Button_OnLeave(frame) local function Button_OnLeave()
local self = frame.obj local self = this.obj
self:Fire("OnButtonLeave", frame.uniquevalue, frame) self:Fire("OnButtonLeave", 2, this.uniquevalue, this)
if self.enabletooltips then if self.enabletooltips then
GameTooltip:Hide() GameTooltip:Hide()
end end
end end
local function OnScrollValueChanged(frame, value) local function OnScrollValueChanged()
if frame.obj.noupdate then return end if this.obj.noupdate then return end
local self = frame.obj local self = this.obj
local status = self.status or self.localstatus local status = self.status or self.localstatus
status.scrollvalue = floor(value + 0.5) status.scrollvalue = floor(arg1 + 0.5)
self:RefreshTree() self:RefreshTree()
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function Tree_OnSizeChanged(frame) local function Tree_OnSizeChanged()
frame.obj:RefreshTree() this.obj:RefreshTree()
end end
local function Tree_OnMouseWheel(frame, delta) local function Tree_OnMouseWheel()
local self = frame.obj local self = this.obj
if self.showscroll then if self.showscroll then
local scrollbar = self.scrollbar local scrollbar = self.scrollbar
local min, max = scrollbar:GetMinMaxValues() local min, max = scrollbar:GetMinMaxValues()
local value = scrollbar:GetValue() local value = scrollbar:GetValue()
local newvalue = math_min(max,math_max(min,value - delta)) local newvalue = math_min(max,math_max(min,value - arg1))
if value ~= newvalue then if value ~= newvalue then
scrollbar:SetValue(newvalue) scrollbar:SetValue(newvalue)
end end
end end
end end
local function Dragger_OnLeave(frame) local function Dragger_OnLeave()
frame:SetBackdropColor(1, 1, 1, 0) this:SetBackdropColor(1, 1, 1, 0)
end end
local function Dragger_OnEnter(frame) local function Dragger_OnEnter()
frame:SetBackdropColor(1, 1, 1, 0.8) this:SetBackdropColor(1, 1, 1, 0.8)
end end
local function Dragger_OnMouseDown(frame) local function Dragger_OnMouseDown()
local treeframe = frame:GetParent() local treeframe = this:GetParent()
treeframe:StartSizing("RIGHT") treeframe:StartSizing("RIGHT")
end end
local function Dragger_OnMouseUp(frame) local function Dragger_OnMouseUp()
local treeframe = frame:GetParent() local treeframe = this:GetParent()
local self = treeframe.obj local self = treeframe.obj
local frame = treeframe:GetParent() local this = treeframe:GetParent()
treeframe:StopMovingOrSizing() treeframe:StopMovingOrSizing()
--treeframe:SetScript("OnUpdate", nil) --treeframe:SetScript("OnUpdate", nil)
treeframe:SetUserPlaced(false) treeframe:SetUserPlaced(false)
--Without this :GetHeight will get stuck on the current height, causing the tree contents to not resize --Without this :GetHeight will get stuck on the current height, causing the tree contents to not resize
treeframe:SetHeight(0) treeframe:SetHeight(0)
treeframe:SetPoint("TOPLEFT", frame, "TOPLEFT",0,0) treeframe:SetPoint("TOPLEFT", this, "TOPLEFT",0,0)
treeframe:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT",0,0) treeframe:SetPoint("BOTTOMLEFT", this, "BOTTOMLEFT",0,0)
local status = self.status or self.localstatus local status = self.status or self.localstatus
status.treewidth = treeframe:GetWidth() status.treewidth = treeframe:GetWidth()
treeframe.obj:Fire("OnTreeResize",treeframe:GetWidth()) treeframe.obj:Fire("OnTreeResize", 1, treeframe:GetWidth())
-- recalculate the content width -- recalculate the content width
treeframe.obj:OnWidthSet(status.fullwidth) treeframe.obj:OnWidthSet(status.fullwidth)
-- update the layout of the content -- update the layout of the content
@@ -293,7 +306,10 @@ end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Methods Methods
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local methods = { local methods
do
local select_args = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
methods = {
["OnAcquire"] = function(self) ["OnAcquire"] = function(self)
self:SetTreeWidth(DEFAULT_TREE_WIDTH, DEFAULT_TREE_SIZABLE) self:SetTreeWidth(DEFAULT_TREE_WIDTH, DEFAULT_TREE_SIZABLE)
self:EnableButtonTooltips(true) self:EnableButtonTooltips(true)
@@ -322,8 +338,39 @@ local methods = {
["CreateButton"] = function(self) ["CreateButton"] = function(self)
local num = AceGUI:GetNextWidgetNum("TreeGroupButton") local num = AceGUI:GetNextWidgetNum("TreeGroupButton")
local button = CreateFrame("Button", format("AceGUI30TreeButton%d", num), self.treeframe, "OptionsListButtonTemplate")
local button = CreateFrame("Button", strfmt("AceGUI30TreeButton%d", num), self.treeframe)
button.obj = self button.obj = self
button:SetWidth(175)
button:SetHeight(18)
local toggle = CreateFrame("Button", nil, button)
toggle.obj = button
button.toggle = toggle
toggle:SetWidth(14)
toggle:SetHeight(14)
toggle:ClearAllPoints()
toggle:SetPoint("TOPRIGHT", button, "TOPRIGHT", -6, -1)
toggle:SetScript("OnClick", Button_OnClick)
toggle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP")
toggle:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-DOWN")
toggle:SetHighlightTexture("Interface\Buttons\UI-PlusButton-Hilight", "ADD")
local text = button:CreateFontString()
button.text = text
text:SetFontObject(GameFontNormal)
button:SetHighlightFontObject(GameFontHighlight)
text:SetPoint("RIGHT", toggle, "LEFT", -2, 0);
text:SetJustifyH("LEFT")
local highlight = button:CreateTexture(nil, "HIGHLIGHT");
button.highlight = highlight
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestLogTitleHighlight")
highlight:SetBlendMode("ADD")
highlight:SetVertexColor(.196, .388, .8);
highlight:ClearAllPoints()
highlight:SetPoint("TOPLEFT",0,1)
highlight:SetPoint("BOTTOMRIGHT",0,1)
local icon = button:CreateTexture(nil, "OVERLAY") local icon = button:CreateTexture(nil, "OVERLAY")
icon:SetWidth(14) icon:SetWidth(14)
@@ -506,25 +553,34 @@ local methods = {
local status = self.status or self.localstatus local status = self.status or self.localstatus
if status.selected ~= value then if status.selected ~= value then
status.selected = value status.selected = value
self:Fire("OnGroupSelected", value) self:Fire("OnGroupSelected", 1, value)
end end
end, end,
["Select"] = function(self, uniquevalue, ...) ["Select"] = function(self, uniquevalue, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
self.filter = false self.filter = false
local status = self.status or self.localstatus local status = self.status or self.localstatus
local groups = status.groups local groups = status.groups
local path = {unpack(arg)} select_args[1] = a1
for i = 1, tgetn(path) do select_args[2] = a2
groups[tconcat(path, "\001", 1, i)] = true select_args[3] = a3
select_args[4] = a4
select_args[5] = a5
select_args[6] = a6
select_args[7] = a7
select_args[8] = a8
select_args[9] = a9
select_args[10] = a10
for i = 1, tgetn(select_args) do
groups[tconcat(select_args, "\001", 1, i)] = true
end end
status.selected = uniquevalue status.selected = uniquevalue
self:RefreshTree(true) self:RefreshTree(true)
self:Fire("OnGroupSelected", uniquevalue) self:Fire("OnGroupSelected", 1, uniquevalue)
end, end,
["SelectByPath"] = function(self, ...) ["SelectByPath"] = function(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
self:Select(BuildUniqueValue(unpack(arg)), unpack(arg)) self:Select(BuildUniqueValue(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10), a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
end, end,
["SelectByValue"] = function(self, uniquevalue) ["SelectByValue"] = function(self, uniquevalue)
@@ -612,6 +668,7 @@ local methods = {
self:SetHeight((height or 0) + 20) self:SetHeight((height or 0) + 20)
end end
} }
end -- method
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Constructor Constructor
@@ -635,8 +692,8 @@ local function Constructor()
local frame = CreateFrame("Frame", nil, UIParent) local frame = CreateFrame("Frame", nil, UIParent)
local treeframe = CreateFrame("Frame", nil, frame) local treeframe = CreateFrame("Frame", nil, frame)
treeframe:SetPoint("TOPLEFT") treeframe:SetPoint("TOPLEFT", 0, 0)
treeframe:SetPoint("BOTTOMLEFT") treeframe:SetPoint("BOTTOMLEFT", 0, 0)
treeframe:SetWidth(DEFAULT_TREE_WIDTH) treeframe:SetWidth(DEFAULT_TREE_WIDTH)
treeframe:EnableMouseWheel(true) treeframe:EnableMouseWheel(true)
treeframe:SetBackdrop(PaneBackdrop) treeframe:SetBackdrop(PaneBackdrop)
@@ -660,7 +717,7 @@ local function Constructor()
dragger:SetScript("OnMouseDown", Dragger_OnMouseDown) dragger:SetScript("OnMouseDown", Dragger_OnMouseDown)
dragger:SetScript("OnMouseUp", Dragger_OnMouseUp) dragger:SetScript("OnMouseUp", Dragger_OnMouseUp)
local scrollbar = CreateFrame("Slider", format("AceConfigDialogTreeGroup%dScrollBar", num), treeframe, "UIPanelScrollBarTemplate") local scrollbar = CreateFrame("Slider", strfmt("AceConfigDialogTreeGroup%dScrollBar", num), treeframe, "UIPanelScrollBarTemplate")
scrollbar:SetScript("OnValueChanged", nil) scrollbar:SetScript("OnValueChanged", nil)
scrollbar:SetPoint("TOPRIGHT", -10, -26) scrollbar:SetPoint("TOPRIGHT", -10, -26)
scrollbar:SetPoint("BOTTOMRIGHT", -10, 26) scrollbar:SetPoint("BOTTOMRIGHT", -10, 26)
@@ -676,7 +733,7 @@ local function Constructor()
local border = CreateFrame("Frame",nil,frame) local border = CreateFrame("Frame",nil,frame)
border:SetPoint("TOPLEFT", treeframe, "TOPRIGHT") border:SetPoint("TOPLEFT", treeframe, "TOPRIGHT")
border:SetPoint("BOTTOMRIGHT") border:SetPoint("BOTTOMRIGHT", 0, 0)
border:SetBackdrop(PaneBackdrop) border:SetBackdrop(PaneBackdrop)
border:SetBackdropColor(0.1, 0.1, 0.1, 0.5) border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
border:SetBackdropBorderColor(0.4, 0.4, 0.4) border:SetBackdropBorderColor(0.4, 0.4, 0.4)
@@ -21,31 +21,27 @@ local CreateFrame, UIParent = CreateFrame, UIParent
]] ]]
do do
local Type = "Window" local Type = "Window"
local Version = 6 local Version = 4
local function frameOnShow(this) local function frameOnClose()
this.obj:Fire("OnShow")
end
local function frameOnClose(this)
this.obj:Fire("OnClose") this.obj:Fire("OnClose")
end end
local function closeOnClick(this) local function closeOnClick()
PlaySound("gsTitleOptionExit") PlaySound("gsTitleOptionExit")
this.obj:Hide() this.obj:Hide()
end end
local function frameOnMouseDown(this) local function frameOnMouseDown()
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function titleOnMouseDown(this) local function titleOnMouseDown()
this:GetParent():StartMoving() this:GetParent():StartMoving()
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function frameOnMouseUp(this) local function frameOnMouseUp()
local frame = this:GetParent() local frame = this:GetParent()
frame:StopMovingOrSizing() frame:StopMovingOrSizing()
local self = frame.obj local self = frame.obj
@@ -56,22 +52,22 @@ do
status.left = frame:GetLeft() status.left = frame:GetLeft()
end end
local function sizerseOnMouseDown(this) local function sizerseOnMouseDown()
this:GetParent():StartSizing("BOTTOMRIGHT") this:GetParent():StartSizing("BOTTOMRIGHT")
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function sizersOnMouseDown(this) local function sizersOnMouseDown()
this:GetParent():StartSizing("BOTTOM") this:GetParent():StartSizing("BOTTOM")
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function sizereOnMouseDown(this) local function sizereOnMouseDown()
this:GetParent():StartSizing("RIGHT") this:GetParent():StartSizing("RIGHT")
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function sizerOnMouseUp(this) local function sizerOnMouseUp()
this:GetParent():StopMovingOrSizing() this:GetParent():StopMovingOrSizing()
end end
@@ -184,7 +180,6 @@ do
frame:SetFrameStrata("FULLSCREEN_DIALOG") frame:SetFrameStrata("FULLSCREEN_DIALOG")
frame:SetScript("OnMouseDown", frameOnMouseDown) frame:SetScript("OnMouseDown", frameOnMouseDown)
frame:SetScript("OnShow",frameOnShow)
frame:SetScript("OnHide",frameOnClose) frame:SetScript("OnHide",frameOnClose)
frame:SetMinResize(240,240) frame:SetMinResize(240,240)
frame:SetToplevel(true) frame:SetToplevel(true)
@@ -2,24 +2,27 @@
Button Widget Button Widget
Graphical Button. Graphical Button.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Button", 24 local Type, Version = "Button", 23
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local AceCore = LibStub("AceCore-3.0")
-- Lua APIs -- Lua APIs
local pairs, unpack = pairs, unpack local pairs = pairs
-- WoW APIs -- WoW APIs
local _G = _G local _G = AceCore._G
local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
-- arg1 is the button for OnClick event
local function Button_OnClick() local function Button_OnClick()
AceGUI:ClearFocus() AceGUI:ClearFocus()
PlaySound("igMainMenuOption") PlaySound("igMainMenuOption")
this.obj:Fire("OnClick", unpack(arg)) this.obj:Fire("OnClick", 1, arg1)
end end
local function Control_OnEnter() local function Control_OnEnter()
@@ -74,7 +77,7 @@ Constructor
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Constructor() local function Constructor()
local name = "AceGUI30Button" .. AceGUI:GetNextWidgetNum(Type) local name = "AceGUI30Button" .. AceGUI:GetNextWidgetNum(Type)
local frame = CreateFrame("Button", name, UIParent, "UIPanelButtonTemplate") local frame = CreateFrame("Button", name, UIParent, "UIPanelButtonTemplate2")
frame:Hide() frame:Hide()
frame:EnableMouse(true) frame:EnableMouse(true)
@@ -1,12 +1,12 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Checkbox Widget Checkbox Widget
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "CheckBox", 23 local Type, Version = "CheckBox", 22
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local select, pairs, unpack = select, pairs, unpack local pairs = pairs
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
@@ -24,10 +24,10 @@ local function AlignImage(self)
self.text:ClearAllPoints() self.text:ClearAllPoints()
if not img then if not img then
self.text:SetPoint("LEFT", self.checkbg, "RIGHT") self.text:SetPoint("LEFT", self.checkbg, "RIGHT")
self.text:SetPoint("RIGHT", 0, 0) self.text:SetPoint("RIGHT",0,0)
else else
self.text:SetPoint("LEFT", self.image,"RIGHT", 1, 0) self.text:SetPoint("LEFT", self.image,"RIGHT", 1, 0)
self.text:SetPoint("RIGHT", 0, 0) self.text:SetPoint("RIGHT",0,0)
end end
end end
@@ -55,6 +55,7 @@ local function CheckBox_OnMouseDown()
end end
local function CheckBox_OnMouseUp() local function CheckBox_OnMouseUp()
local self = this.obj local self = this.obj
if not self.disabled then if not self.disabled then
self:ToggleChecked() self:ToggleChecked()
@@ -65,7 +66,7 @@ local function CheckBox_OnMouseUp()
PlaySound("igMainMenuOptionCheckBoxOff") PlaySound("igMainMenuOptionCheckBoxOff")
end end
self:Fire("OnValueChanged", self.checked) self:Fire("OnValueChanged", 1, self.checked)
AlignImage(self) AlignImage(self)
end end
end end
@@ -172,6 +173,7 @@ local methods = {
highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight") highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
highlight:SetTexCoord(0, 1, 0, 1) highlight:SetTexCoord(0, 1, 0, 1)
end end
checkbg:SetHeight(size) checkbg:SetHeight(size)
checkbg:SetWidth(size) checkbg:SetWidth(size)
end, end,
@@ -221,14 +223,13 @@ local methods = {
end end
end, end,
["SetImage"] = function(self, path, ...) ["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8)
local image = self.image local image = self.image
image:SetTexture(path) image:SetTexture(path)
if image:GetTexture() then if image:GetTexture() then
local n = select("#", arg) if a4 or a8 then
if n == 4 or n == 8 then image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8)
image:SetTexCoord(unpack(arg))
else else
image:SetTexCoord(0, 1, 0, 1) image:SetTexCoord(0, 1, 0, 1)
end end
@@ -253,7 +254,7 @@ local function Constructor()
local checkbg = frame:CreateTexture(nil, "ARTWORK") local checkbg = frame:CreateTexture(nil, "ARTWORK")
checkbg:SetWidth(24) checkbg:SetWidth(24)
checkbg:SetHeight(24) checkbg:SetHeight(24)
checkbg:SetPoint("TOPLEFT", 0, 0) checkbg:SetPoint("TOPLEFT",0,0)
checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up") checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
local check = frame:CreateTexture(nil, "OVERLAY") local check = frame:CreateTexture(nil, "OVERLAY")
@@ -261,10 +262,10 @@ local function Constructor()
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
local text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight") local text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
text:SetJustifyH("LEFT", 0, 0) text:SetJustifyH("LEFT")
text:SetHeight(18) text:SetHeight(18)
text:SetPoint("LEFT", checkbg, "RIGHT") text:SetPoint("LEFT", checkbg, "RIGHT")
text:SetPoint("RIGHT", 0, 0) text:SetPoint("RIGHT",0,0)
local highlight = frame:CreateTexture(nil, "HIGHLIGHT") local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight") highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
@@ -1,7 +1,7 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
ColorPicker Widget ColorPicker Widget
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "ColorPicker-ElvUI", 1 local Type, Version = "ColorPicker", 23
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -25,12 +25,12 @@ local function ColorCallback(self, r, g, b, a, isAlpha)
self:SetColor(r, g, b, a) self:SetColor(r, g, b, a)
if ColorPickerFrame:IsVisible() then if ColorPickerFrame:IsVisible() then
--colorpicker is still open --colorpicker is still open
self:Fire("OnValueChanged", r, g, b, a) self:Fire("OnValueChanged", 4, r, g, b, a)
else else
--colorpicker is closed, color callback is first, ignore it, --colorpicker is closed, color callback is first, ignore it,
--alpha callback is the final call after it closes so confirm now --alpha callback is the final call after it closes so confirm now
if isAlpha then if isAlpha then
self:Fire("OnValueConfirmed", r, g, b, a) self:Fire("OnValueConfirmed", 4, r, g, b, a)
end end
end end
end end
@@ -38,20 +38,19 @@ end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter(frame) local function Control_OnEnter()
frame.obj:Fire("OnEnter") this.obj:Fire("OnEnter")
end end
local function Control_OnLeave(frame) local function Control_OnLeave()
frame.obj:Fire("OnLeave") this.obj:Fire("OnLeave")
end end
local function ColorSwatch_OnClick(frame) local function ColorSwatch_OnClick()
HideUIPanel(ColorPickerFrame) HideUIPanel(ColorPickerFrame)
local self = frame.obj local self = this.obj
if not self.disabled then if not self.disabled then
ColorPickerFrame:SetFrameStrata("FULLSCREEN_DIALOG") ColorPickerFrame:SetFrameStrata("FULLSCREEN_DIALOG")
ColorPickerFrame:SetFrameLevel(frame:GetFrameLevel() + 10)
ColorPickerFrame:SetClampedToScreen(true) ColorPickerFrame:SetClampedToScreen(true)
ColorPickerFrame.func = function() ColorPickerFrame.func = function()
@@ -67,20 +66,12 @@ local function ColorSwatch_OnClick(frame)
ColorCallback(self, r, g, b, a, true) ColorCallback(self, r, g, b, a, true)
end end
local r, g, b, a, dR, dG, dB, dA = self.r, self.g, self.b, self.a, self.dR, self.dG, self.dB, self.dA local r, g, b, a = self.r, self.g, self.b, self.a
if self.HasAlpha then if self.HasAlpha then
ColorPickerFrame.opacity = 1 - (a or 0) ColorPickerFrame.opacity = 1 - (a or 0)
end end
ColorPickerFrame:SetColorRGB(r, g, b) ColorPickerFrame:SetColorRGB(r, g, b)
if(ColorPPDefault and self.dR and self.dG and self.dB) then
local alpha = 1
if(self.dA) then
alpha = 1 - self.dA
end
ColorPPDefault.colors = {r = self.dR, g = self.dG, b = self.dB, a = alpha}
end
ColorPickerFrame.cancelFunc = function() ColorPickerFrame.cancelFunc = function()
ColorCallback(self, r, g, b, a, true) ColorCallback(self, r, g, b, a, true)
end end
@@ -109,15 +100,11 @@ local methods = {
self.text:SetText(text) self.text:SetText(text)
end, end,
["SetColor"] = function(self, r, g, b, a, defaultR, defaultG, defaultB, defaultA) ["SetColor"] = function(self, r, g, b, a)
self.r = r self.r = r
self.g = g self.g = g
self.b = b self.b = b
self.a = a or 1 self.a = a or 1
self.dR = defaultR
self.dG = defaultG
self.dB = defaultB
self.dA = defaultA
self.colorSwatch:SetVertexColor(r, g, b, a) self.colorSwatch:SetVertexColor(r, g, b, a)
end, end,
@@ -153,7 +140,7 @@ local function Constructor()
colorSwatch:SetWidth(19) colorSwatch:SetWidth(19)
colorSwatch:SetHeight(19) colorSwatch:SetHeight(19)
colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch") colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
colorSwatch:SetPoint("LEFT") colorSwatch:SetPoint("LEFT",0,0)
local texture = frame:CreateTexture(nil, "BACKGROUND") local texture = frame:CreateTexture(nil, "BACKGROUND")
texture:SetWidth(16) texture:SetWidth(16)
@@ -177,7 +164,7 @@ local function Constructor()
text:SetJustifyH("LEFT") text:SetJustifyH("LEFT")
text:SetTextColor(1, 1, 1) text:SetTextColor(1, 1, 1)
text:SetPoint("LEFT", colorSwatch, "RIGHT", 2, 0) text:SetPoint("LEFT", colorSwatch, "RIGHT", 2, 0)
text:SetPoint("RIGHT") text:SetPoint("RIGHT",0,0)
--local highlight = frame:CreateTexture(nil, "HIGHLIGHT") --local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
--highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") --highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
@@ -1,35 +1,19 @@
--[[ $Id: AceGUIWidget-DropDown-Items.lua 1153 2016-11-20 09:57:15Z nevcairiel $ ]]-- --[[ $Id: AceGUIWidget-DropDown-Items.lua 1137 2016-05-15 10:57:36Z nevcairiel $ ]]--
local AceGUI = LibStub("AceGUI-3.0") local AceGUI = LibStub("AceGUI-3.0")
local IsLegion = false
-- Lua APIs -- Lua APIs
local select, assert = select, assert local assert = assert
local tgetn = table.getn
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
local CreateFrame = CreateFrame local CreateFrame = CreateFrame
local function fixlevels(parent,...) local fixlevels = AceGUI.fixlevels
local i = 1 local fixstrata = AceGUI.fixstrata
local child = select(i, arg)
while child do
child:SetFrameLevel(parent:GetFrameLevel()+1)
fixlevels(child, child:GetChildren())
i = i + 1
child = select(i, arg)
end
end
local function fixstrata(strata, parent, ...)
local i = 1
local child = select(i, arg)
parent:SetFrameStrata(strata)
while child do
fixstrata(strata, child, child:GetChildren())
i = i + 1
child = select(i, arg)
end
end
-- ItemBase is the base "class" for all dropdown items. -- ItemBase is the base "class" for all dropdown items.
-- Each item has to use ItemBase.Create(widgetType) to -- Each item has to use ItemBase.Create(widgetType) to
@@ -45,7 +29,7 @@ local ItemBase = {
counter = 0, counter = 0,
} }
function ItemBase.Frame_OnEnter(this) function ItemBase.Frame_OnEnter()
local self = this.obj local self = this.obj
if self.useHighlight then if self.useHighlight then
@@ -58,7 +42,7 @@ function ItemBase.Frame_OnEnter(this)
end end
end end
function ItemBase.Frame_OnLeave(this) function ItemBase.Frame_OnLeave()
local self = this.obj local self = this.obj
self.highlight:Hide() self.highlight:Hide()
@@ -91,9 +75,10 @@ function ItemBase.SetPullout(self, pullout)
self.pullout = pullout self.pullout = pullout
self.frame:SetParent(nil) self.frame:SetParent(nil)
self.frame:SetParent(pullout.itemFrame) local itemFrame = pullout.itemFrame
self.parent = pullout.itemFrame self.frame:SetParent(itemFrame)
fixlevels(pullout.itemFrame, pullout.itemFrame:GetChildren()) self.parent = itemFrame
fixlevels(itemFrame)
end end
-- exported -- exported
@@ -107,8 +92,8 @@ function ItemBase.GetText(self)
end end
-- exported -- exported
function ItemBase.SetPoint(self, ...) function ItemBase.SetPoint(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
self.frame:SetPoint(unpack(arg)) self.frame:SetPoint(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
end end
-- exported -- exported
@@ -257,7 +242,7 @@ do
end end
end end
local function OnLeave(this) local function OnLeave()
local self = this.obj local self = this.obj
self:Fire("OnLeave") self:Fire("OnLeave")
@@ -323,7 +308,7 @@ end
-- Does not close the pullout on click. -- Does not close the pullout on click.
do do
local widgetType = "Dropdown-Item-Toggle" local widgetType = "Dropdown-Item-Toggle"
local widgetVersion = 4 local widgetVersion = 3
local function UpdateToggle(self) local function UpdateToggle(self)
if self.value then if self.value then
@@ -338,7 +323,7 @@ do
self:SetValue(nil) self:SetValue(nil)
end end
local function Frame_OnClick(this, button) local function Frame_OnClick()
local self = this.obj local self = this.obj
if self.disabled then return end if self.disabled then return end
self.value = not self.value self.value = not self.value
@@ -348,7 +333,7 @@ do
PlaySound("igMainMenuOptionCheckBoxOff") PlaySound("igMainMenuOptionCheckBoxOff")
end end
UpdateToggle(self) UpdateToggle(self)
self:Fire("OnValueChanged", self.value) self:Fire("OnValueChanged", 1, self.value)
end end
-- exported -- exported
@@ -385,7 +370,7 @@ do
local widgetType = "Dropdown-Item-Menu" local widgetType = "Dropdown-Item-Menu"
local widgetVersion = 2 local widgetVersion = 2
local function OnEnter(this) local function OnEnter()
local self = this.obj local self = this.obj
self:Fire("OnEnter") self:Fire("OnEnter")
@@ -400,7 +385,7 @@ do
end end
end end
local function OnHide(this) local function OnHide()
local self = this.obj local self = this.obj
if self.submenu then if self.submenu then
self.submenu:Close() self.submenu:Close()
@@ -456,6 +441,7 @@ do
local line = self.frame:CreateTexture(nil, "OVERLAY") local line = self.frame:CreateTexture(nil, "OVERLAY")
line:SetHeight(1) line:SetHeight(1)
line:SetTexture(.5, .5, .5) line:SetTexture(.5, .5, .5)
line:SetPoint("LEFT", self.frame, "LEFT", 10, 0) line:SetPoint("LEFT", self.frame, "LEFT", 10, 0)
line:SetPoint("RIGHT", self.frame, "RIGHT", -10, 0) line:SetPoint("RIGHT", self.frame, "RIGHT", -10, 0)
@@ -1,41 +1,24 @@
--[[ $Id: AceGUIWidget-DropDown.lua 1116 2014-10-12 08:15:46Z nevcairiel $ ]]-- --[[ $Id: AceGUIWidget-DropDown.lua 1116 2014-10-12 08:15:46Z nevcairiel $ ]]--
local AceGUI = LibStub("AceGUI-3.0") local AceGUI = LibStub("AceGUI-3.0")
local AceCore = LibStub("AceCore-3.0")
-- Lua APIs -- Lua APIs
local min, max, floor = math.min, math.max, math.floor local min, max, floor = math.min, math.max, math.floor
local select, pairs, ipairs, type = select, pairs, ipairs, type local pairs, ipairs, type = pairs, ipairs, type
local tgetn, tsort = table.getn, table.sort local tsort, tinsert, tgetn, tsetn = table.sort, table.insert, table.getn, table.setn
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
local UIParent, CreateFrame = UIParent, CreateFrame local UIParent, CreateFrame = UIParent, CreateFrame
local _G = _G local _G = AceCore._G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
-- GLOBALS: CLOSE -- GLOBALS: CLOSE
local function fixlevels(parent,...) local fixlevels = AceGUI.fixlevels
local i = 1 local fixstrata = AceGUI.fixstrata
local child = select(i, arg)
while child do
child:SetFrameLevel(parent:GetFrameLevel()+1)
fixlevels(child, child:GetChildren())
i = i + 1
child = select(i, arg)
end
end
local function fixstrata(strata, parent, ...)
local i = 1
local child = select(i, arg)
parent:SetFrameStrata(strata)
while child do
fixstrata(strata, child, child:GetChildren())
i = i + 1
child = select(i, arg)
end
end
do do
local widgetType = "Dropdown-Pullout" local widgetType = "Dropdown-Pullout"
@@ -76,15 +59,15 @@ do
end end
-- See the note in Constructor() for each scroll related function -- See the note in Constructor() for each scroll related function
local function OnMouseWheel(this, value) local function OnMouseWheel()
this.obj:MoveScroll(value) this.obj:MoveScroll(arg1)
end end
local function OnScrollValueChanged(this, value) local function OnScrollValueChanged()
this.obj:SetScroll(value) this.obj:SetScroll(arg1)
end end
local function OnSizeChanged(this) local function OnSizeChanged()
this.obj:FixScroll() this.obj:FixScroll()
end end
@@ -169,7 +152,7 @@ do
-- exported -- exported
local function AddItem(self, item) local function AddItem(self, item)
self.items[tgetn(self.items) + 1] = item tinsert(self.items, item)
local h = tgetn(self.items) * 16 local h = tgetn(self.items) * 16
self.itemFrame:SetHeight(h) self.itemFrame:SetHeight(h)
@@ -204,7 +187,7 @@ do
height = height + 16 height = height + 16
end end
itemFrame:SetHeight(height) itemFrame:SetHeight(height)
fixstrata("TOOLTIP", frame, frame:GetChildren()) fixstrata("TOOLTIP", frame)
frame:Show() frame:Show()
self:Fire("OnOpen") self:Fire("OnOpen")
end end
@@ -222,6 +205,7 @@ do
AceGUI:Release(item) AceGUI:Release(item)
items[i] = nil items[i] = nil
end end
tsetn(items,0)
end end
-- exported -- exported
@@ -356,30 +340,30 @@ end
do do
local widgetType = "Dropdown" local widgetType = "Dropdown"
local widgetVersion = 31 local widgetVersion = 30
--[[ Static data ]]-- --[[ Static data ]]--
--[[ UI event handler ]]-- --[[ UI event handler ]]--
local function Control_OnEnter(this) local function Control_OnEnter()
this.obj.button:LockHighlight() this.obj.button:LockHighlight()
this.obj:Fire("OnEnter") this.obj:Fire("OnEnter")
end end
local function Control_OnLeave(this) local function Control_OnLeave()
this.obj.button:UnlockHighlight() this.obj.button:UnlockHighlight()
this.obj:Fire("OnLeave") this.obj:Fire("OnLeave")
end end
local function Dropdown_OnHide(this) local function Dropdown_OnHide()
local self = this.obj local self = this.obj
if self.open then if self.open then
self.pullout:Close() self.pullout:Close()
end end
end end
local function Dropdown_TogglePullout(this) local function Dropdown_TogglePullout()
local self = this.obj local self = this.obj
PlaySound("igMainMenuOptionCheckBoxOn") -- missleading name, but the Blizzard code uses this sound PlaySound("igMainMenuOptionCheckBoxOn") -- missleading name, but the Blizzard code uses this sound
if self.open then if self.open then
@@ -430,17 +414,20 @@ do
self:SetText(text) self:SetText(text)
end end
local function OnItemValueChanged(this, event, checked) local function OnItemValueChanged(this, event, _, checked)
local self = this.userdata.obj local self = this.userdata.obj
if self.multiselect then if self.multiselect then
self:Fire("OnValueChanged", this.userdata.value, checked) self:Fire("OnValueChanged", 2, this.userdata.value, checked)
ShowMultiText(self) ShowMultiText(self)
else else
if checked then if checked then
self:SetValue(this.userdata.value) self:SetValue(this.userdata.value)
self:Fire("OnValueChanged", this.userdata.value) self:Fire("OnValueChanged", 1, this.userdata.value)
this:SetValue(false)
else else
self:SetValue(nil)
self:Fire("OnValueChanged", 1, nil)
this:SetValue(true) this:SetValue(true)
end end
if self.open then if self.open then
@@ -459,7 +446,8 @@ do
pullout:SetCallback("OnClose", OnPulloutClose) pullout:SetCallback("OnClose", OnPulloutClose)
pullout:SetCallback("OnOpen", OnPulloutOpen) pullout:SetCallback("OnOpen", OnPulloutOpen)
self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1) self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1)
fixlevels(self.pullout.frame, self.pullout.frame:GetChildren()) local frame = self.pullout.frame
fixlevels(frame)
self:SetHeight(44) self:SetHeight(44)
self:SetWidth(200) self:SetWidth(200)
@@ -571,7 +559,7 @@ do
local function AddListItem(self, value, text, itemType) local function AddListItem(self, value, text, itemType)
if not itemType then itemType = "Dropdown-Item-Toggle" end if not itemType then itemType = "Dropdown-Item-Toggle" end
local exists = AceGUI:GetWidgetVersion(itemType) local exists = AceGUI:GetWidgetVersion(itemType)
if not exists then error(format("The given item type, %q, does not exist within AceGUI-3.0", tostring(itemType)), 2) end if not exists then error(("The given item type, %q, does not exist within AceGUI-3.0"):format(tostring(itemType)), 2) end
local item = AceGUI:Create(itemType) local item = AceGUI:Create(itemType)
item:SetText(text) item:SetText(text)
@@ -600,7 +588,7 @@ do
if type(order) ~= "table" then if type(order) ~= "table" then
for v in pairs(list) do for v in pairs(list) do
sortlist[tgetn(sortlist) + 1] = v tinsert(sortlist, v)
end end
tsort(sortlist) tsort(sortlist)
@@ -608,6 +596,7 @@ do
AddListItem(self, key, list[key], itemType) AddListItem(self, key, list[key], itemType)
sortlist[i] = nil sortlist[i] = nil
end end
tsetn(sortlist,0)
else else
for i, key in ipairs(order) do for i, key in ipairs(order) do
AddListItem(self, key, list[key], itemType) AddListItem(self, key, list[key], itemType)
@@ -1,18 +1,23 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
EditBox Widget EditBox Widget
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "EditBox", 27 local Type, Version = "EditBox", 26
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local AceCore = LibStub("AceCore-3.0")
local hooksecurefunc = AceCore.hooksecurefunc
local _G = AceCore._G
local GetCursorInfo = _G.GetCursorInfo
-- Lua APIs -- Lua APIs
local tostring, pairs, unpack = tostring, pairs, unpack local tostring, pairs = tostring, pairs
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
local GetCursorInfo, ClearCursor, GetSpellInfo = GetCursorInfo, ClearCursor, GetSpellInfo local GetCursorInfo, ClearCursor, GetSpellInfo = GetCursorInfo, ClearCursor, GetSpellInfo
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
local _G = _G local strlen = string.len
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
@@ -116,7 +121,7 @@ end
function _G.AceGUIEditBoxInsertLink(text) function _G.AceGUIEditBoxInsertLink(text)
for i = 1, AceGUI:GetWidgetCount(Type) do for i = 1, AceGUI:GetWidgetCount(Type) do
local editbox = _G["AceGUI-3.0EditBox"..i] local editbox = _G["AceGUI-3.0EditBox"..i]
if editbox and editbox:IsVisible() and editbox:HasFocus() then if editbox and editbox:IsVisible() and editbox.hasfocus then
editbox:Insert(text) editbox:Insert(text)
return true return true
end end
@@ -138,73 +143,82 @@ end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter(frame) local function Control_OnEnter()
frame.obj:Fire("OnEnter") this.obj:Fire("OnEnter")
end end
local function Control_OnLeave(frame) local function Control_OnLeave()
frame.obj:Fire("OnLeave") this.obj:Fire("OnLeave")
end end
local function Frame_OnShowFocus(frame) local function Frame_OnShowFocus()
frame.obj.editbox:SetFocus() this.obj.editbox:SetFocus()
frame:SetScript("OnShow", nil) this:SetScript("OnShow", nil)
end end
local function EditBox_OnEscapePressed(frame) local function EditBox_OnEscapePressed()
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function EditBox_OnEnterPressed(frame) local function EditBox_OnEnterPressed()
local self = frame.obj local self = this.obj
local value = frame:GetText() local value = this:GetText()
local cancel = self:Fire("OnEnterPressed", value) local cancel = self:Fire("OnEnterPressed", 1, value)
if not cancel then if not cancel then
PlaySound("igMainMenuOptionCheckBoxOn") PlaySound("igMainMenuOptionCheckBoxOn")
HideButton(self) HideButton(self)
end end
end end
local function EditBox_OnReceiveDrag(frame) local function EditBox_OnReceiveDrag()
local self = frame.obj if not GetCursorInfo then return end
local self = this.obj
local type, id, info = GetCursorInfo() local type, id, info = GetCursorInfo()
if type == "item" then if type == "item" then
self:SetText(info) self:SetText(info)
self:Fire("OnEnterPressed", info) self:Fire("OnEnterPressed", 1, info)
ClearCursor() ClearCursor()
elseif type == "spell" then elseif type == "spell" then
local name = GetSpellInfo(id, info) local spell, rank = GetSpellName(id, info)
self:SetText(name) if rank ~= "" then spell = spell.."("..rank..")" end
self:Fire("OnEnterPressed", name) self:SetText(spell)
self:Fire("OnEnterPressed", 1, spell)
ClearCursor() ClearCursor()
elseif type == "macro" then elseif type == "macro" then
local name = GetMacroInfo(id) local name = GetMacroInfo(id)
self:SetText(name) self:SetText(name)
self:Fire("OnEnterPressed", name) self:Fire("OnEnterPressed", 1, name)
ClearCursor() ClearCursor()
end end
HideButton(self) HideButton(self)
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function EditBox_OnTextChanged(frame)
local self = frame.obj local function EditBox_OnTextChanged()
local value = frame:GetText() local self = this.obj
local value = this:GetText()
if tostring(value) ~= tostring(self.lasttext) then if tostring(value) ~= tostring(self.lasttext) then
self:Fire("OnTextChanged", value) self:Fire("OnTextChanged", 1, value)
self.lasttext = value self.lasttext = value
ShowButton(self) ShowButton(self)
end end
end end
local function EditBox_OnFocusGained(frame) local function EditBox_OnFocusGained()
AceGUI:SetFocus(frame.obj) this.hasfocus = true
AceGUI:SetFocus(this.obj)
end end
local function Button_OnClick(frame) local function EditBox_OnFocusLost()
local editbox = frame.obj.editbox this.hasfocus = nil
end
local function Button_OnClick()
local editbox = this.obj.editbox
editbox:ClearFocus() editbox:ClearFocus()
EditBox_OnEnterPressed(editbox) this = editbox -- Ace3v: this is kinda hack here
EditBox_OnEnterPressed()
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -242,7 +256,7 @@ local methods = {
["SetText"] = function(self, text) ["SetText"] = function(self, text)
self.lasttext = text or "" self.lasttext = text or ""
self.editbox:SetText(text or "") self.editbox:SetText(text or "")
self.editbox:SetCursorPosition(0) self.editbox:HighlightText(0)
HideButton(self) HideButton(self)
end, end,
@@ -313,10 +327,11 @@ local function Constructor()
editbox:SetScript("OnReceiveDrag", EditBox_OnReceiveDrag) editbox:SetScript("OnReceiveDrag", EditBox_OnReceiveDrag)
editbox:SetScript("OnMouseDown", EditBox_OnReceiveDrag) editbox:SetScript("OnMouseDown", EditBox_OnReceiveDrag)
editbox:SetScript("OnEditFocusGained", EditBox_OnFocusGained) editbox:SetScript("OnEditFocusGained", EditBox_OnFocusGained)
editbox:SetScript("OnEditFocusLost", EditBox_OnFocusLost)
editbox:SetTextInsets(0, 0, 3, 3) editbox:SetTextInsets(0, 0, 3, 3)
editbox:SetMaxLetters(256) editbox:SetMaxLetters(256)
editbox:SetPoint("BOTTOMLEFT", 6, 0) editbox:SetPoint("BOTTOMLEFT", 6, 0)
editbox:SetPoint("BOTTOMRIGHT") editbox:SetPoint("BOTTOMRIGHT", 0, 0)
editbox:SetHeight(19) editbox:SetHeight(19)
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
@@ -43,9 +43,9 @@ local function Constructor()
frame:Hide() frame:Hide()
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal") local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
label:SetPoint("TOP", 0, 0) label:SetPoint("TOP",0,0)
label:SetPoint("BOTTOM", 0, 0) label:SetPoint("BOTTOM",0,0)
label:SetJustifyH("CENTER", 0, 0) label:SetJustifyH("CENTER")
local left = frame:CreateTexture(nil, "BACKGROUND") local left = frame:CreateTexture(nil, "BACKGROUND")
left:SetHeight(8) left:SetHeight(8)
@@ -6,7 +6,7 @@ local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local select, pairs, print, unpack = select, pairs, print, unpack local pairs, print = pairs, print
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
@@ -14,16 +14,16 @@ local CreateFrame, UIParent = CreateFrame, UIParent
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter(frame) local function Control_OnEnter()
frame.obj:Fire("OnEnter") this.obj:Fire("OnEnter")
end end
local function Control_OnLeave(frame) local function Control_OnLeave()
frame.obj:Fire("OnLeave") this.obj:Fire("OnLeave")
end end
local function Button_OnClick(frame, button) local function Button_OnClick()
frame.obj:Fire("OnClick", button) this.obj:Fire("OnClick", 1, arg1)
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
@@ -53,14 +53,13 @@ local methods = {
end end
end, end,
["SetImage"] = function(self, path, ...) ["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8)
local image = self.image local image = self.image
image:SetTexture(path) image:SetTexture(path)
if image:GetTexture() then if image:GetTexture() then
local n = select("#", arg) if a4 or a8 then
if n == 4 or n == 8 then image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8)
image:SetTexCoord(unpack(arg))
else else
image:SetTexCoord(0, 1, 0, 1) image:SetTexCoord(0, 1, 0, 1)
end end
@@ -132,7 +131,7 @@ local function Constructor()
widget[method] = func widget[method] = func
end end
widget.SetText = function(self, ...) print("AceGUI-3.0-Icon: SetText is deprecated! Use SetLabel instead!"); self:SetLabel(unpack(arg)) end widget.SetText = function(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) print("AceGUI-3.0-Icon: SetText is deprecated! Use SetLabel instead!"); self:SetLabel(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) end
return AceGUI:RegisterAsWidget(widget) return AceGUI:RegisterAsWidget(widget)
end end
@@ -1,12 +1,12 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
InteractiveLabel Widget InteractiveLabel Widget
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "InteractiveLabel", 21 local Type, Version = "InteractiveLabel", 20
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local select, pairs, unpack = select, pairs, unpack local pairs = pairs
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
@@ -18,16 +18,16 @@ local CreateFrame, UIParent = CreateFrame, UIParent
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter(frame) local function Control_OnEnter()
frame.obj:Fire("OnEnter") this.obj:Fire("OnEnter")
end end
local function Control_OnLeave(frame) local function Control_OnLeave()
frame.obj:Fire("OnLeave") this.obj:Fire("OnLeave")
end end
local function Label_OnClick(frame, button) local function Label_OnClick()
frame.obj:Fire("OnClick", button) this.obj:Fire("OnClick", 1, arg1)
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
@@ -44,14 +44,13 @@ local methods = {
-- ["OnRelease"] = nil, -- ["OnRelease"] = nil,
["SetHighlight"] = function(self, ...) ["SetHighlight"] = function(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
self.highlight:SetTexture(unpack(arg)) self.highlight:SetTexture(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
end, end,
["SetHighlightTexCoord"] = function(self, ...) ["SetHighlightTexCoord"] = function(self, a1,a2,a3,a4,a5,a6,a7,a8)
local c = select("#", arg) if a4 or a8 then
if c == 4 or c == 8 then self.highlight:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
self.highlight:SetTexCoord(unpack(arg))
else else
self.highlight:SetTexCoord(0, 1, 0, 1) self.highlight:SetTexCoord(0, 1, 0, 1)
end end
@@ -21,44 +21,32 @@ local CreateFrame, UIParent = CreateFrame, UIParent
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter(frame) local function Control_OnEnter()
frame.obj:Fire("OnEnter") this.obj:Fire("OnEnter")
end end
local function Control_OnLeave(frame) local function Control_OnLeave()
frame.obj:Fire("OnLeave") this.obj:Fire("OnLeave")
end end
local function Keybinding_OnClick(frame, button) local function Keybinding_OnHide()
if button == "LeftButton" or button == "RightButton" then local self = this.obj
local self = frame.obj this:EnableKeyboard(false)
if self.waitingForKey then this:EnableMouseWheel(false)
frame:EnableKeyboard(false) self.msgframe:Hide()
frame:EnableMouseWheel(false) this:UnlockHighlight()
self.msgframe:Hide() self.waitingForKey = nil
frame:UnlockHighlight()
self.waitingForKey = nil
else
frame:EnableKeyboard(true)
frame:EnableMouseWheel(true)
self.msgframe:Show()
frame:LockHighlight()
self.waitingForKey = true
end
end
AceGUI:ClearFocus()
end end
local ignoreKeys = { local ignoreKeys = {
["BUTTON1"] = true, ["BUTTON2"] = true, ["BUTTON1"] = true, ["BUTTON2"] = true,
["UNKNOWN"] = true, ["UNKNOWN"] = true,
["LSHIFT"] = true, ["LCTRL"] = true, ["LALT"] = true, ["SHIFT"] = true, ["CTRL"] = true, ["ALT"] = true,
["RSHIFT"] = true, ["RCTRL"] = true, ["RALT"] = true,
} }
local function Keybinding_OnKeyDown(frame, key) local function Keybinding_OnKeyDown()
local self = frame.obj local self = this.obj
if self.waitingForKey then if self.waitingForKey then
local keyPressed = key local keyPressed = arg1
if keyPressed == "ESCAPE" then if keyPressed == "ESCAPE" then
keyPressed = "" keyPressed = ""
else else
@@ -74,40 +62,58 @@ local function Keybinding_OnKeyDown(frame, key)
end end
end end
frame:EnableKeyboard(false) this:EnableKeyboard(false)
frame:EnableMouseWheel(false) this:EnableMouseWheel(false)
self.msgframe:Hide() self.msgframe:Hide()
frame:UnlockHighlight() this:UnlockHighlight()
self.waitingForKey = nil self.waitingForKey = nil
if not self.disabled then if not self.disabled then
self:SetKey(keyPressed) self:SetKey(keyPressed)
self:Fire("OnKeyChanged", keyPressed) self:Fire("OnKeyChanged", 1, keyPressed)
end end
end end
end end
local function Keybinding_OnMouseDown(frame, button) local function Keybinding_OnMouseDown()
if button == "LeftButton" or button == "RightButton" then getglobal(this:GetName().."Left"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
return getglobal(this:GetName().."Middle"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
elseif button == "MiddleButton" then getglobal(this:GetName().."Right"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
button = "BUTTON3"
elseif button == "Button4" then
button = "BUTTON4"
elseif button == "Button5" then
button = "BUTTON5"
end
Keybinding_OnKeyDown(frame, button)
end end
local function Keybinding_OnMouseWheel(frame, direction) local function Keybinding_OnMouseUp()
local button getglobal(this:GetName().."Left"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
if direction >= 0 then getglobal(this:GetName().."Middle"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
button = "MOUSEWHEELUP" getglobal(this:GetName().."Right"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
else local self = this.obj
button = "MOUSEWHEELDOWN" if MouseIsOver(this) and not self.disabled then
if self.waitingForKey then
if arg1 ~= "LeftButton" and arg1 ~= "RightButton" then
Keybinding_OnKeyDown()
end
this:EnableKeyboard(false)
this:EnableMouseWheel(false)
self.msgframe:Hide()
this:UnlockHighlight()
self.waitingForKey = nil
else
this:EnableKeyboard(true)
this:EnableMouseWheel(true)
self.msgframe:Show()
this:LockHighlight()
self.waitingForKey = true
end
end end
Keybinding_OnKeyDown(frame, button) AceGUI:ClearFocus()
end
local function Keybinding_OnMouseWheel()
if arg1 >= 0 then
arg1 = "MOUSEWHEELUP"
else
arg1 = "MOUSEWHEELDOWN"
end
Keybinding_OnKeyDown()
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -141,10 +147,10 @@ local methods = {
["SetKey"] = function(self, key) ["SetKey"] = function(self, key)
if (key or "") == "" then if (key or "") == "" then
self.button:SetText(NOT_BOUND) self.button:SetText(NOT_BOUND)
self.button:SetNormalFontObject("GameFontNormal") self.text:SetFontObject("GameFontNormal")
else else
self.button:SetText(key) self.button:SetText(key)
self.button:SetNormalFontObject("GameFontHighlight") self.text:SetFontObject("GameFontHighlight")
end end
end, end,
@@ -179,28 +185,31 @@ local ControlBackdrop = {
insets = { left = 3, right = 3, top = 3, bottom = 3 } insets = { left = 3, right = 3, top = 3, bottom = 3 }
} }
local function keybindingMsgFixWidth(frame) local function keybindingMsgFixWidth()
frame:SetWidth(frame.msg:GetWidth() + 10) this:SetWidth(this.msg:GetWidth() + 10)
frame:SetScript("OnUpdate", nil) this:SetScript("OnUpdate", nil)
end end
local function Constructor() local function Constructor()
local name = "AceGUI30KeybindingButton" .. AceGUI:GetNextWidgetNum(Type) local name = "AceGUI30KeybindingButton" .. AceGUI:GetNextWidgetNum(Type)
local frame = CreateFrame("Frame", nil, UIParent) local frame = CreateFrame("Frame", nil, UIParent)
local button = CreateFrame("Button", name, frame, "UIPanelButtonTemplate") local button = CreateFrame("Button", name, frame, "UIPanelButtonTemplate2")
button:EnableMouse(true) button:EnableMouse(true)
button:EnableMouseWheel(false) button:EnableMouseWheel(false)
button:RegisterForClicks("AnyDown")
button:SetScript("OnEnter", Control_OnEnter) button:SetScript("OnEnter", Control_OnEnter)
button:SetScript("OnLeave", Control_OnLeave) button:SetScript("OnLeave", Control_OnLeave)
button:SetScript("OnClick", Keybinding_OnClick)
button:SetScript("OnKeyDown", Keybinding_OnKeyDown) button:SetScript("OnKeyDown", Keybinding_OnKeyDown)
button:RegisterForClicks("AnyDown","AnyUp")
-- Ace3v: RegisterForClicks means OnClick will not be triggered, so use OnKeyDown and OnKeyUp
button:SetScript("OnMouseDown", Keybinding_OnMouseDown) button:SetScript("OnMouseDown", Keybinding_OnMouseDown)
button:SetScript("OnMouseUp", Keybinding_OnMouseUp)
button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel) button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel)
button:SetPoint("BOTTOMLEFT") button:SetScript("OnHide", Keybinding_OnHide)
button:SetPoint("BOTTOMRIGHT") button:SetPoint("BOTTOMLEFT",0,0)
button:SetPoint("BOTTOMRIGHT",0,0)
button:SetHeight(24) button:SetHeight(24)
button:EnableKeyboard(false) button:EnableKeyboard(false)
@@ -209,8 +218,8 @@ local function Constructor()
text:SetPoint("RIGHT", -7, 0) text:SetPoint("RIGHT", -7, 0)
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight") local label = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
label:SetPoint("TOPLEFT") label:SetPoint("TOPLEFT",0,0)
label:SetPoint("TOPRIGHT") label:SetPoint("TOPRIGHT",0,0)
label:SetJustifyH("CENTER") label:SetJustifyH("CENTER")
label:SetHeight(18) label:SetHeight(18)
@@ -236,7 +245,8 @@ local function Constructor()
msgframe = msgframe, msgframe = msgframe,
frame = frame, frame = frame,
alignoffset = 30, alignoffset = 30,
type = Type type = Type,
text = text
} }
for method, func in pairs(methods) do for method, func in pairs(methods) do
widget[method] = func widget[method] = func
@@ -2,12 +2,12 @@
Label Widget Label Widget
Displays text and optionally an icon. Displays text and optionally an icon.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Label", 24 local Type, Version = "Label", 23
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local max, select, pairs, unpack = math.max, select, pairs, unpack local max, pairs = math.max, pairs
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
@@ -35,14 +35,14 @@ local function UpdateImageAnchor(self)
local imagewidth = image:GetWidth() local imagewidth = image:GetWidth()
if (width - imagewidth) < 200 or (label:GetText() or "") == "" then if (width - imagewidth) < 200 or (label:GetText() or "") == "" then
-- image goes on top centered when less than 200 width for the text, or if there is no text -- image goes on top centered when less than 200 width for the text, or if there is no text
image:SetPoint("TOP") image:SetPoint("TOP",0,0)
label:SetPoint("TOP", image, "BOTTOM") label:SetPoint("TOP", image, "BOTTOM")
label:SetPoint("LEFT") label:SetPoint("LEFT",0,0)
label:SetWidth(width) label:SetWidth(width)
height = image:GetHeight() + label:GetHeight() height = image:GetHeight() + label:GetHeight()
else else
-- image on the left -- image on the left
image:SetPoint("TOPLEFT") image:SetPoint("TOPLEFT",0,0)
if image:GetHeight() > label:GetHeight() then if image:GetHeight() > label:GetHeight() then
label:SetPoint("LEFT", image, "RIGHT", 4, 0) label:SetPoint("LEFT", image, "RIGHT", 4, 0)
else else
@@ -53,7 +53,7 @@ local function UpdateImageAnchor(self)
end end
else else
-- no image shown -- no image shown
label:SetPoint("TOPLEFT") label:SetPoint("TOPLEFT",0,0)
label:SetWidth(width) label:SetWidth(width)
height = label:GetHeight() height = label:GetHeight()
end end
@@ -78,8 +78,6 @@ local methods = {
self:SetImageSize(16, 16) self:SetImageSize(16, 16)
self:SetColor() self:SetColor()
self:SetFontObject() self:SetFontObject()
self:SetJustifyH("LEFT")
self:SetJustifyV("TOP")
-- reset the flag -- reset the flag
self.resizing = nil self.resizing = nil
@@ -105,15 +103,14 @@ local methods = {
self.label:SetVertexColor(r, g, b) self.label:SetVertexColor(r, g, b)
end, end,
["SetImage"] = function(self, path, ...) ["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8)
local image = self.image local image = self.image
image:SetTexture(path) image:SetTexture(path)
if image:GetTexture() then if image:GetTexture() then
self.imageshown = true self.imageshown = true
local n = select("#", arg) if a4 or a8 then
if n == 4 or n == 8 then image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8)
image:SetTexCoord(unpack(arg))
else else
image:SetTexCoord(0, 1, 0, 1) image:SetTexCoord(0, 1, 0, 1)
end end
@@ -136,14 +133,6 @@ local methods = {
self.image:SetHeight(height) self.image:SetHeight(height)
UpdateImageAnchor(self) UpdateImageAnchor(self)
end, end,
["SetJustifyH"] = function(self, justifyH)
self.label:SetJustifyH(justifyH)
end,
["SetJustifyV"] = function(self, justifyV)
self.label:SetJustifyV(justifyV)
end,
} }
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -154,6 +143,9 @@ local function Constructor()
frame:Hide() frame:Hide()
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall") local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall")
label:SetJustifyH("LEFT")
label:SetJustifyV("TOP")
local image = frame:CreateTexture(nil, "BACKGROUND") local image = frame:CreateTexture(nil, "BACKGROUND")
-- create widget -- create widget
@@ -2,13 +2,17 @@ local Type, Version = "MultiLineEditBox", 28
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local AceCore = LibStub("AceCore-3.0")
local hooksecurefunc = AceCore.hooksecurefunc
-- Lua APIs -- Lua APIs
local pairs, unpack = pairs, unpack local strfmt = string.format
local pairs = pairs
-- WoW APIs -- WoW APIs
local GetCursorInfo, GetSpellInfo, ClearCursor = GetCursorInfo, GetSpellInfo, ClearCursor local GetCursorInfo, GetSpellInfo, ClearCursor = GetCursorInfo, GetSpellInfo, ClearCursor
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
local _G = _G local _G = AceCore._G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
@@ -17,7 +21,6 @@ local _G = _G
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Support functions Support functions
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
if not AceGUIMultiLineEditBoxInsertLink then if not AceGUIMultiLineEditBoxInsertLink then
-- upgradeable hook -- upgradeable hook
hooksecurefunc("BankFrameItemButtonGeneric_OnClick", hooksecurefunc("BankFrameItemButtonGeneric_OnClick",
@@ -112,15 +115,14 @@ end
function _G.AceGUIMultiLineEditBoxInsertLink(text) function _G.AceGUIMultiLineEditBoxInsertLink(text)
for i = 1, AceGUI:GetWidgetCount(Type) do for i = 1, AceGUI:GetWidgetCount(Type) do
local editbox = _G[format("MultiLineEditBox%uEdit", i)] local editbox = _G[strfmt("MultiLineEditBox%uEdit",i)]
if editbox and editbox:IsVisible() and editbox:HasFocus() then if editbox and editbox:IsVisible() and editbox.hasfocus then
editbox:Insert(text) editbox:Insert(text)
return true return true
end end
end end
end end
local function Layout(self) local function Layout(self)
self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight) self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight)
@@ -142,104 +144,122 @@ end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function OnClick(self) -- Button local function OnClick() -- Button
self = self.obj local self = this.obj
self.editBox:ClearFocus() self.editBox:ClearFocus()
if not self:Fire("OnEnterPressed", self.editBox:GetText()) then if not self:Fire("OnEnterPressed", 1, self.editBox:GetText()) then
self.button:Disable() self.button:Disable()
end end
end end
local function OnCursorChanged(self, _, y, _, cursorHeight) -- EditBox local function OnCursorChanged() -- EditBox
self, y = self.obj.scrollFrame, -y
local self, y = this.obj.scrollFrame, -arg2
local offset = self:GetVerticalScroll() local offset = self:GetVerticalScroll()
if y < offset then if y < offset then
self:SetVerticalScroll(y) self:SetVerticalScroll(y)
else else
y = y + cursorHeight - self:GetHeight() y = y + arg4 - self:GetHeight()
if y > offset then if y > offset then
self:SetVerticalScroll(y) self:SetVerticalScroll(y)
end end
end end
end end
local function OnEditFocusLost(self) -- EditBox local function OnEditFocusLost() -- EditBox
self:HighlightText(0, 0) this.hasfocus = nil
self.obj:Fire("OnEditFocusLost") this:HighlightText(0, 0)
this.obj:Fire("OnEditFocusLost")
end end
local function OnEnter(self) -- EditBox / ScrollFrame local function OnEnter() -- EditBox / ScrollFrame
self = self.obj local self = this.obj
if not self.entered then if not self.entered then
self.entered = true self.entered = true
self:Fire("OnEnter") self:Fire("OnEnter")
end end
end end
local function OnLeave(self) -- EditBox / ScrollFrame local function OnLeave() -- EditBox / ScrollFrame
self = self.obj local self = this.obj
if self.entered then if self.entered then
self.entered = nil self.entered = nil
self:Fire("OnLeave") self:Fire("OnLeave")
end end
end end
local function OnMouseUp(self) -- ScrollFrame local function OnMouseUp() -- ScrollFrame
self = self.obj.editBox local self = this.obj.editBox
self:SetFocus() self:SetFocus()
self:SetCursorPosition(self:GetNumLetters()) local n = self:GetNumLetters()
self:HighlightText(n,n)
end end
local function OnReceiveDrag(self) -- EditBox / ScrollFrame local function OnReceiveDrag() -- EditBox / ScrollFrame
if not GetCursorInfo then return end
local type, id, info = GetCursorInfo() local type, id, info = GetCursorInfo()
if type == "spell" then if type == "spell" then
info = GetSpellInfo(id, info) local spell, rank = GetSpellName(id, info)
if rank ~= "" then spell = spell.."("..rank..")" end
info = spell
elseif type ~= "item" then elseif type ~= "item" then
return return
end end
ClearCursor() ClearCursor()
self = self.obj local self = this.obj
local editBox = self.editBox local editBox = self.editBox
if not editBox:HasFocus() then if not this.hasfocus then
this.hasfocus = true
editBox:SetFocus() editBox:SetFocus()
editBox:SetCursorPosition(editBox:GetNumLetters()) local n = editBox:GetNumLetters()
editBox:HighlightText(n,n)
end end
editBox:Insert(info) editBox:Insert(info)
self.button:Enable() self.button:Enable()
end end
local function OnSizeChanged(self, width, height) -- ScrollFrame local function OnSizeChanged() -- ScrollFrame
self.obj.editBox:SetWidth(width) this.obj.editBox:SetWidth(arg1)
end end
local function OnTextChanged(self, userInput) -- EditBox local function OnTextChanged() -- EditBox
if userInput then local self = this.obj
self = self.obj local value = this:GetText()
self:Fire("OnTextChanged", self.editBox:GetText()) if tostring(value) ~= tostring(self.lasttext) then
self:Fire("OnTextChanged", 1, value)
self.lasttext = value
self.button:Enable() self.button:Enable()
end end
end end
local function OnTextSet(self) -- EditBox local function OnTextSet() -- EditBox
self:HighlightText(0, 0) this:HighlightText(0, 0)
self:SetCursorPosition(self:GetNumLetters()) this.obj.button:Disable()
self:SetCursorPosition(0)
self.obj.button:Disable()
end end
local function OnVerticalScroll(self, offset) -- ScrollFrame local function OnVerticalScroll() -- ScrollFrame
local editBox = self.obj.editBox local self = this.obj
editBox:SetHitRectInsets(0, 0, offset, editBox:GetHeight() - offset - self:GetHeight()) local editBox = self.editBox
editBox:SetHitRectInsets(0, 0, arg1, editBox:GetHeight() - arg1 - this:GetHeight())
self.scrollFrame:SetScrollChild(self.editBox)
self.editBox:SetPoint("TOPLEFT",0,arg1)
self.editBox:SetPoint("TOPRIGHT",0,arg1)
end end
local function OnShowFocus(frame) local function OnShowFocus()
frame.obj.editBox:SetFocus() this.obj.editBox:SetFocus()
frame:SetScript("OnShow", nil) this:SetScript("OnShow", nil)
end end
local function OnEditFocusGained(frame) local function OnEditFocusGained()
AceGUI:SetFocus(frame.obj) this.hasfocus = true
frame.obj:Fire("OnEditFocusGained") AceGUI:SetFocus(this.obj)
this.obj:Fire("OnEditFocusGained")
end
local function OnEscapePressed() -- EditBox
AceGUI:ClearFocus()
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -300,7 +320,10 @@ local methods = {
end, end,
["SetText"] = function(self, text) ["SetText"] = function(self, text)
self.editBox:SetText(text) self.lasttext = text or ""
self.editBox:SetText(text or "")
self.editBox:HighlightText(0)
self.button:Disable()
end, end,
["GetText"] = function(self) ["GetText"] = function(self)
@@ -336,16 +359,6 @@ local methods = {
["HighlightText"] = function(self, from, to) ["HighlightText"] = function(self, from, to)
self.editBox:HighlightText(from, to) self.editBox:HighlightText(from, to)
end, end,
["GetCursorPosition"] = function(self)
return self.editBox:GetCursorPosition()
end,
["SetCursorPosition"] = function(self, ...)
return self.editBox:SetCursorPosition(unpack(arg))
end,
} }
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -370,7 +383,7 @@ local function Constructor()
label:SetText(ACCEPT) label:SetText(ACCEPT)
label:SetHeight(10) label:SetHeight(10)
local button = CreateFrame("Button", format("%s%dButton", Type, widgetNum), frame, "UIPanelButtonTemplate") local button = CreateFrame("Button", strfmt("%s%dButton", Type, widgetNum), frame, "UIPanelButtonTemplate")
button:SetPoint("BOTTOMLEFT", 0, 4) button:SetPoint("BOTTOMLEFT", 0, 4)
button:SetHeight(22) button:SetHeight(22)
button:SetWidth(label:GetStringWidth() + 24) button:SetWidth(label:GetStringWidth() + 24)
@@ -389,7 +402,7 @@ local function Constructor()
scrollBG:SetBackdropColor(0, 0, 0) scrollBG:SetBackdropColor(0, 0, 0)
scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4) scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4)
local scrollFrame = CreateFrame("ScrollFrame", format("%s%dScrollFrame", Type, widgetNum), frame, "UIPanelScrollFrameTemplate") local scrollFrame = CreateFrame("ScrollFrame", strfmt("%s%dScrollFrame", Type, widgetNum), frame, "UIPanelScrollFrameTemplate")
local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"] local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"]
scrollBar:ClearAllPoints() scrollBar:ClearAllPoints()
@@ -407,19 +420,26 @@ local function Constructor()
scrollFrame:SetScript("OnMouseUp", OnMouseUp) scrollFrame:SetScript("OnMouseUp", OnMouseUp)
scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag) scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag)
scrollFrame:SetScript("OnSizeChanged", OnSizeChanged) scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
scrollFrame:HookScript("OnVerticalScroll", OnVerticalScroll) local old = scrollFrame:GetScript("OnVerticalScroll");
if old then
scrollFrame:SetScript("OnVerticalScroll", function()
old()
OnVerticalScroll()
end)
else
scrollFrame:SetScript("OnVerticalScroll", OnVerticalScroll)
end
local editBox = CreateFrame("EditBox", format("%s%dEdit", Type, widgetNum), scrollFrame) local editBox = CreateFrame("EditBox", strfmt("%s%dEdit", Type, widgetNum), scrollFrame)
editBox:SetAllPoints()
editBox:SetFontObject(ChatFontNormal) editBox:SetFontObject(ChatFontNormal)
editBox:SetMultiLine(true) editBox:SetMultiLine(true)
editBox:EnableMouse(true) editBox:EnableMouse(true)
editBox:SetAutoFocus(false) editBox:SetAutoFocus(false)
editBox:SetCountInvisibleLetters(false) --editBox:SetCountInvisibleLetters(false)
editBox:SetScript("OnCursorChanged", OnCursorChanged) editBox:SetScript("OnCursorChanged", OnCursorChanged)
editBox:SetScript("OnEditFocusLost", OnEditFocusLost) editBox:SetScript("OnEditFocusLost", OnEditFocusLost)
editBox:SetScript("OnEnter", OnEnter) editBox:SetScript("OnEnter", OnEnter)
editBox:SetScript("OnEscapePressed", editBox.ClearFocus) editBox:SetScript("OnEscapePressed", OnEscapePressed)
editBox:SetScript("OnLeave", OnLeave) editBox:SetScript("OnLeave", OnLeave)
editBox:SetScript("OnMouseDown", OnReceiveDrag) editBox:SetScript("OnMouseDown", OnReceiveDrag)
editBox:SetScript("OnReceiveDrag", OnReceiveDrag) editBox:SetScript("OnReceiveDrag", OnReceiveDrag)
@@ -427,8 +447,10 @@ local function Constructor()
editBox:SetScript("OnTextSet", OnTextSet) editBox:SetScript("OnTextSet", OnTextSet)
editBox:SetScript("OnEditFocusGained", OnEditFocusGained) editBox:SetScript("OnEditFocusGained", OnEditFocusGained)
-- Ace3v: the orders are important here
scrollFrame:SetScrollChild(editBox) scrollFrame:SetScrollChild(editBox)
editBox:SetPoint("TOPLEFT",0,0)
editBox:SetPoint("TOPRIGHT",0,0)
local widget = { local widget = {
button = button, button = button,
@@ -2,13 +2,12 @@
Slider Widget Slider Widget
Graphical Slider, like, for Range values. Graphical Slider, like, for Range values.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Slider", 22 local Type, Version = "Slider", 21
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local min, max, floor = math.min, math.max, math.floor local min, max, floor = math.min, math.max, math.floor
local gsub = string.gsub
local tonumber, pairs = tonumber, pairs local tonumber, pairs = tonumber, pairs
-- WoW APIs -- WoW APIs
@@ -25,7 +24,7 @@ Support functions
local function UpdateText(self) local function UpdateText(self)
local value = self.value or 0 local value = self.value or 0
if self.ispercent then if self.ispercent then
self.editbox:SetText(format("%s%%", floor(value * 1000 + 0.5) / 10)) self.editbox:SetText(("%s%%"):format(floor(value * 1000 + 0.5) / 10))
else else
self.editbox:SetText(floor(value * 100 + 0.5) / 100) self.editbox:SetText(floor(value * 100 + 0.5) / 100)
end end
@@ -34,8 +33,8 @@ end
local function UpdateLabels(self) local function UpdateLabels(self)
local min, max = (self.min or 0), (self.max or 100) local min, max = (self.min or 0), (self.max or 100)
if self.ispercent then if self.ispercent then
self.lowtext:SetText(format("%s%%", (min * 100))) self.lowtext:SetFormattedText("%s%%", (min * 100))
self.hightext:SetText(format("%s%%", (max * 100))) self.hightext:SetFormattedText("%s%%", (max * 100))
else else
self.lowtext:SetText(min) self.lowtext:SetText(min)
self.hightext:SetText(max) self.hightext:SetText(max)
@@ -68,7 +67,7 @@ local function Slider_OnValueChanged()
end end
if newvalue ~= self.value and not self.disabled then if newvalue ~= self.value and not self.disabled then
self.value = newvalue self.value = newvalue
self:Fire("OnValueChanged", newvalue) self:Fire("OnValueChanged", 1, newvalue)
end end
if self.value then if self.value then
UpdateText(self) UpdateText(self)
@@ -78,7 +77,7 @@ end
local function Slider_OnMouseUp() local function Slider_OnMouseUp()
local self = this.obj local self = this.obj
self:Fire("OnMouseUp", self.value) self:Fire("OnMouseUp", 1, self.value)
end end
local function Slider_OnMouseWheel() local function Slider_OnMouseWheel()
@@ -102,7 +101,7 @@ local function EditBox_OnEnterPressed()
local self = this.obj local self = this.obj
local value = this:GetText() local value = this:GetText()
if self.ispercent then if self.ispercent then
value = gsub(value, '%%', '') value = value:gsub('%%', '')
value = tonumber(value) / 100 value = tonumber(value) / 100
else else
value = tonumber(value) value = tonumber(value)
@@ -111,7 +110,7 @@ local function EditBox_OnEnterPressed()
if value then if value then
PlaySound("igMainMenuOptionCheckBoxOn") PlaySound("igMainMenuOptionCheckBoxOn")
self.slider:SetValue(value) self.slider:SetValue(value)
self:Fire("OnMouseUp", value) self:Fire("OnMouseUp", 1, value)
end end
end end
@@ -222,9 +221,9 @@ local function Constructor()
frame:SetScript("OnMouseDown", Frame_OnMouseDown) frame:SetScript("OnMouseDown", Frame_OnMouseDown)
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal") local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
label:SetPoint("TOPLEFT", 0, 0) label:SetPoint("TOPLEFT",0,0)
label:SetPoint("TOPRIGHT", 0, 0) label:SetPoint("TOPRIGHT",0,0)
label:SetJustifyH("CENTER", 0, 0) label:SetJustifyH("CENTER",0,0)
label:SetHeight(15) label:SetHeight(15)
local slider = CreateFrame("Slider", nil, frame) local slider = CreateFrame("Slider", nil, frame)
@@ -12,7 +12,6 @@
<Script file="AceGUIContainer-Window.lua"/> <Script file="AceGUIContainer-Window.lua"/>
<!-- Widgets --> <!-- Widgets -->
<Script file="AceGUIWidget-Button.lua"/> <Script file="AceGUIWidget-Button.lua"/>
<Script file="AceGUIWidget-Button-ElvUI.lua"/>
<Script file="AceGUIWidget-CheckBox.lua"/> <Script file="AceGUIWidget-CheckBox.lua"/>
<Script file="AceGUIWidget-ColorPicker.lua"/> <Script file="AceGUIWidget-ColorPicker.lua"/>
<Script file="AceGUIWidget-DropDown.lua"/> <Script file="AceGUIWidget-DropDown.lua"/>
@@ -1 +1 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <Include file="AceGUI-3.0\AceGUI-3.0.xml"/> <Include file="AceConfig-3.0\AceConfig-3.0.xml"/> <Include file="AceDBOptions-3.0\AceDBOptions-3.0.xml"/> <Include file="AceGUI-3.0-SharedMediaWidgets\widget.xml"/> </Ui> <Ui xmlns="http://www.blizzard.com/wow/ui/"> <Include file="AceGUI-3.0\AceGUI-3.0.xml"/> <Include file="AceGUI-3.0\widgets\widgets.xml"/> <Include file="AceConfig-3.0\AceConfig-3.0.xml"/> <Include file="AceDBOptions-3.0\AceDBOptions-3.0.xml"/> <Include file="AceGUI-3.0-SharedMediaWidgets\widget.xml"/> </Ui>
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -14,11 +14,11 @@ local UnitName = UnitName;
local DEFAULT_WIDTH = 890; local DEFAULT_WIDTH = 890;
local DEFAULT_HEIGHT = 651; local DEFAULT_HEIGHT = 651;
local AC = LibStub("AceConfig-3.0-ElvUI"); local AC = LibStub("AceConfig-3.0");
local ACD = LibStub("AceConfigDialog-3.0-ElvUI"); local ACD = LibStub("AceConfigDialog-3.0");
local ACR = LibStub("AceConfigRegistry-3.0-ElvUI"); local ACR = LibStub("AceConfigRegistry-3.0");
AC:RegisterOptionsTable("ElvUI", E.Options); AC.RegisterOptionsTable(E, "ElvUI", E.Options);
ACD:SetDefaultSize("ElvUI", DEFAULT_WIDTH, DEFAULT_HEIGHT); ACD:SetDefaultSize("ElvUI", DEFAULT_WIDTH, DEFAULT_HEIGHT);
function E:RefreshGUI() function E:RefreshGUI()